1 /*
2 * Copyright (C) 2018-2023 Intel Corporation.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include <asm/errno.h>
8 #include <string.h>
9 #include <unistd.h>
10 #include <stdio.h>
11 #include <stdbool.h>
12 #include "sbuf.h"
13 #include <errno.h>
14
sbuf_next_ptr(uint32_t pos_arg,uint32_t span,uint32_t scope)15 static inline uint32_t sbuf_next_ptr(uint32_t pos_arg,
16 uint32_t span, uint32_t scope)
17 {
18 uint32_t pos = pos_arg;
19 pos += span;
20 pos = (pos >= scope) ? (pos - scope) : pos;
21 return pos;
22 }
23
sbuf_get(struct shared_buf * sbuf,uint8_t * data)24 uint32_t sbuf_get(struct shared_buf *sbuf, uint8_t *data)
25 {
26 const void *from;
27
28 if ((sbuf == NULL) || (data == NULL))
29 return -EINVAL;
30
31 if (sbuf_is_empty(sbuf)) {
32 /* no data available */
33 return 0;
34 }
35
36 from = (void *)sbuf + SBUF_HEAD_SIZE + sbuf->head;
37
38 memcpy(data, from, sbuf->ele_size);
39
40 mb();
41
42 sbuf->head = sbuf_next_ptr(sbuf->head, sbuf->ele_size, sbuf->size);
43
44 return sbuf->ele_size;
45 }
46
sbuf_clear_buffered(struct shared_buf * sbuf)47 int sbuf_clear_buffered(struct shared_buf *sbuf)
48 {
49 if (sbuf == NULL)
50 return -EINVAL;
51
52 sbuf->head = sbuf->tail;
53
54 return 0;
55 }
56
57 /**
58 * The high caller should guarantee each time there must have
59 * sbuf->ele_size data can be write form data.
60 * Caller should provide the max length of the data for safety reason.
61 *
62 * And this function should guarantee execution atomically.
63 *
64 * flag:
65 * If OVERWRITE_EN set, buf can store (ele_num - 1) elements at most.
66 * Should use lock to guarantee that only one read or write at
67 * the same time.
68 * if OVERWRITE_EN not set, buf can store (ele_num - 1) elements
69 * at most. Shouldn't modify the sbuf->head.
70 *
71 * return:
72 * ele_size: write succeeded.
73 * 0: no write, buf is full
74 * UINT32_MAX: failed, sbuf corrupted.
75 */
sbuf_put(struct shared_buf * sbuf,uint8_t * data,uint32_t max_len)76 uint32_t sbuf_put(struct shared_buf *sbuf, uint8_t *data, uint32_t max_len)
77 {
78 uint32_t ele_size = sbuf->ele_size;
79 void *to;
80 uint32_t next_tail;
81 uint32_t ret;
82 bool trigger_overwrite = false;
83
84 next_tail = sbuf_next_ptr(sbuf->tail, ele_size, sbuf->size);
85
86 if ((next_tail == sbuf->head) && ((sbuf->flags & OVERWRITE_EN) == 0U)) {
87 /* if overrun is not enabled, return 0 directly */
88 ret = 0U;
89 } else if (ele_size <= max_len) {
90 if (next_tail == sbuf->head) {
91 /* accumulate overrun count if necessary */
92 sbuf->overrun_cnt += sbuf->flags & OVERRUN_CNT_EN;
93 trigger_overwrite = true;
94 }
95 to = (void *)sbuf + SBUF_HEAD_SIZE + sbuf->tail;
96
97 memcpy(to, data, ele_size);
98 /* make sure write data before update head */
99 mb();
100
101 if (trigger_overwrite) {
102 sbuf->head = sbuf_next_ptr(sbuf->head,
103 ele_size, sbuf->size);
104 }
105 sbuf->tail = next_tail;
106 ret = ele_size;
107 } else {
108 /* there must be something wrong */
109 ret = UINT32_MAX;
110 }
111
112 return ret;
113 }
114
sbuf_init(struct shared_buf * sbuf,uint32_t total_size,uint32_t ele_size)115 void sbuf_init(struct shared_buf *sbuf, uint32_t total_size, uint32_t ele_size)
116 {
117 sbuf->magic = SBUF_MAGIC;
118 sbuf->ele_size = ele_size;
119 sbuf->ele_num = (total_size - SBUF_HEAD_SIZE) / sbuf->ele_size;
120 sbuf->size = sbuf->ele_size * sbuf->ele_num;
121 sbuf->flags = 0;
122 sbuf->overrun_cnt = 0;
123 sbuf->head = 0;
124 sbuf->tail = 0;
125 }
126