Line data Source code
1 0 : /*
2 : * Copyright (c) 2022 Nordic Semiconductor ASA
3 : *
4 : * SPDX-License-Identifier: Apache-2.0
5 : */
6 :
7 : #ifndef ZEPHYR_INCLUDE_SYS_SPSC_PBUF_H_
8 : #define ZEPHYR_INCLUDE_SYS_SPSC_PBUF_H_
9 :
10 : #include <zephyr/cache.h>
11 : #include <zephyr/devicetree.h>
12 :
13 : #ifdef __cplusplus
14 : extern "C" {
15 : #endif
16 :
17 : /**
18 : * @brief Single producer, single consumer packet buffer API
19 : * @defgroup spsc_buf SPSC (Single producer, single consumer) packet buffer API
20 : * @ingroup datastructure_apis
21 : * @{
22 : */
23 :
24 : /**@defgroup SPSC_PBUF_FLAGS SPSC packet buffer flags
25 : * @{
26 : */
27 :
28 : /** @brief Flag indicating that cache shall be handled.
29 : *
30 : * It shall be used only when packet buffer is shared between two cores as on a single
31 : * core cache shall not be handled manually because it results in data corruption.
32 : */
33 1 : #define SPSC_PBUF_CACHE BIT(0)
34 :
35 : /** @brief Size of the field which stores maximum utilization. */
36 1 : #define SPSC_PBUF_UTILIZATION_BITS 24
37 :
38 : /** @brief Offset of the field which stores maximum utilization. */
39 1 : #define SPSC_PBUF_UTILIZATION_OFFSET 8
40 :
41 : /**@} */
42 :
43 : #if CONFIG_DCACHE_LINE_SIZE != 0
44 : #define Z_SPSC_PBUF_LOCAL_DCACHE_LINE CONFIG_DCACHE_LINE_SIZE
45 : #else
46 : #define Z_SPSC_PBUF_LOCAL_DCACHE_LINE DT_PROP_OR(CPU, d_cache_line_size, 0)
47 : #endif
48 :
49 : #ifndef CONFIG_SPSC_PBUF_REMOTE_DCACHE_LINE
50 0 : #define CONFIG_SPSC_PBUF_REMOTE_DCACHE_LINE 0
51 : #endif
52 :
53 : #define Z_SPSC_PBUF_DCACHE_LINE \
54 : MAX(CONFIG_SPSC_PBUF_REMOTE_DCACHE_LINE, Z_SPSC_PBUF_LOCAL_DCACHE_LINE)
55 :
56 : /** @brief Maximum packet length. */
57 1 : #define SPSC_PBUF_MAX_LEN 0xFF00
58 :
59 : /** @brief First part of packet buffer control block.
60 : *
61 : * This part contains only data set during the initialization and data touched
62 : * by the reader. If packet is shared between to cores then data changed by
63 : * the reader should be on different cache line than the data changed by the
64 : * writer.
65 : */
66 1 : struct spsc_pbuf_common {
67 0 : uint32_t len; /* Length of data[] in bytes. */
68 0 : uint32_t flags; /* Flags. See @ref SPSC_PBUF_FLAGS */
69 0 : uint32_t rd_idx; /* Index of the first valid byte in data[] */
70 : };
71 :
72 : /* Padding to fill cache line. */
73 : #define Z_SPSC_PBUF_PADDING \
74 : MAX(0, Z_SPSC_PBUF_DCACHE_LINE - (int)sizeof(struct spsc_pbuf_common))
75 :
76 : /** @brief Remaining part of a packet buffer when cache is used.
77 : *
78 : * It contains data that is only changed by the writer. A gap is added to ensure
79 : * that it is in different cache line than the data changed by the reader.
80 : */
81 1 : struct spsc_pbuf_ext_cache {
82 0 : uint8_t reserved[Z_SPSC_PBUF_PADDING];
83 0 : uint32_t wr_idx; /* Index of the first free byte in data[] */
84 0 : uint8_t data[]; /* Buffer data. */
85 : };
86 :
87 : /** @brief Remaining part of a packet buffer when cache is not used. */
88 1 : struct spsc_pbuf_ext_nocache {
89 0 : uint32_t wr_idx; /* Index of the first free byte in data[] */
90 0 : uint8_t data[]; /* Buffer data. */
91 : };
92 :
93 : /**
94 : * @brief Single producer, single consumer packet buffer
95 : *
96 : * The SPSC packet buffer implements lightweight unidirectional packet buffer
97 : * with read/write semantics on top of a memory region shared
98 : * by the reader and writer. It optionally embeds cache and memory barrier
99 : * management to ensure correct data access.
100 : *
101 : * This structure supports single writer and reader. Data stored in the buffer
102 : * is encapsulated to a message (with length header).
103 : *
104 : */
105 1 : struct spsc_pbuf {
106 0 : struct spsc_pbuf_common common;
107 : union {
108 0 : struct spsc_pbuf_ext_cache cache;
109 0 : struct spsc_pbuf_ext_nocache nocache;
110 0 : } ext;
111 : };
112 :
113 : /** @brief Get buffer capacity.
114 : *
115 : * This value is the amount of data that is dedicated for storing packets. Since
116 : * each packet is prefixed with 2 byte length header, longest possible packet is
117 : * less than that.
118 : *
119 : * @param pb A buffer.
120 : *
121 : * @return Packet buffer capacity.
122 : */
123 1 : static inline uint32_t spsc_pbuf_capacity(struct spsc_pbuf *pb)
124 : {
125 : return pb->common.len - sizeof(uint32_t);
126 : }
127 :
128 : /**
129 : * @brief Initialize the packet buffer.
130 : *
131 : * This function initializes the packet buffer on top of a dedicated
132 : * memory region.
133 : *
134 : * @param buf Pointer to a memory region on which buffer is
135 : * created. When cache is used it must be aligned to
136 : * Z_SPSC_PBUF_DCACHE_LINE, otherwise it must
137 : * be 32 bit word aligned.
138 : * @param blen Length of the buffer. Must be large enough to
139 : * contain the internal structure and at least two
140 : * bytes of data (one is reserved for written
141 : * messages length).
142 : * @param flags Option flags. See @ref SPSC_PBUF_FLAGS.
143 : * @retval struct spsc_pbuf* Pointer to the created buffer. The pointer
144 : * points to the same address as buf.
145 : * @retval NULL Invalid buffer alignment.
146 : */
147 1 : struct spsc_pbuf *spsc_pbuf_init(void *buf, size_t blen, uint32_t flags);
148 :
149 : /**
150 : * @brief Write specified amount of data to the packet buffer.
151 : *
152 : * It combines @ref spsc_pbuf_alloc and @ref spsc_pbuf_commit into a single call.
153 : *
154 : * @param pb A buffer to which to write.
155 : * @param buf Pointer to the data to be written to the buffer.
156 : * @param len Number of bytes to be written to the buffer. Must be positive
157 : * but less than @ref SPSC_PBUF_MAX_LEN.
158 : * @retval int Number of bytes written, negative error code on fail.
159 : * -EINVAL, if len == 0.
160 : * -ENOMEM, if len is bigger than the buffer can fit.
161 : */
162 1 : int spsc_pbuf_write(struct spsc_pbuf *pb, const char *buf, uint16_t len);
163 :
164 : /**
165 : * @brief Allocate space in the packet buffer.
166 : *
167 : * This function attempts to allocate @p len bytes of continuous memory within
168 : * the packet buffer. An internal padding is added at the end of the buffer, if
169 : * wrapping occurred during allocation. Apart from padding, allocation does not
170 : * change the state of the buffer so if after allocation packet is not needed
171 : * a commit is not needed.
172 : *
173 : * Allocated buffer must be committed (@ref spsc_pbuf_commit) to make the packet
174 : * available for reading.
175 : *
176 : * Packet buffer ensures that allocated buffers are 32 bit word aligned.
177 : *
178 : * @note If data cache is used, it is the user responsibility to write back the
179 : * new data.
180 : *
181 : * @param[in] pb A buffer to which to write.
182 : * @param[in] len Allocation length. Must be positive. If less than @ref SPSC_PBUF_MAX_LEN
183 : * then if requested length cannot be allocated, an attempt to allocate
184 : * largest possible is performed (which may include adding wrap padding).
185 : * If @ref SPSC_PBUF_MAX_LEN is used then an attempt to allocate largest
186 : * buffer without applying wrap padding is performed.
187 : * @param[out] buf Location where buffer address is written on successful allocation.
188 : *
189 : * @retval non-negative Amount of space that got allocated. Can be equal or smaller than %p len.
190 : * @retval -EINVAL if @p len is forbidden.
191 : */
192 1 : int spsc_pbuf_alloc(struct spsc_pbuf *pb, uint16_t len, char **buf);
193 :
194 : /**
195 : * @brief Commit packet to the buffer.
196 : *
197 : * Commit a packet which was previously allocated (@ref spsc_pbuf_alloc).
198 : * If cache is used, cache writeback is performed on the written data.
199 : *
200 : * @param pb A buffer to which to write.
201 : * @param len Packet length. Must be equal or less than the length used for allocation.
202 : */
203 1 : void spsc_pbuf_commit(struct spsc_pbuf *pb, uint16_t len);
204 :
205 : /**
206 : * @brief Read specified amount of data from the packet buffer.
207 : *
208 : * Single read allows to read the message send by the single write.
209 : * The provided %p buf must be big enough to store the whole message.
210 : *
211 : * It combines @ref spsc_pbuf_claim and @ref spsc_pbuf_free into a single call.
212 : *
213 : * @param pb A buffer from which data will be read.
214 : * @param buf Data pointer to which read data will be written.
215 : * If NULL, len of stored message is returned.
216 : * @param len Number of bytes to be read from the buffer.
217 : * @retval int Bytes read, negative error code on fail.
218 : * Bytes to be read, if buf == NULL.
219 : * -ENOMEM, if message can not fit in provided buf.
220 : * -EAGAIN, if not whole message is ready yet.
221 : */
222 1 : int spsc_pbuf_read(struct spsc_pbuf *pb, char *buf, uint16_t len);
223 :
224 : /**
225 : * @brief Claim packet from the buffer.
226 : *
227 : * It claims a single packet from the buffer in the order of the commitment
228 : * by the @ref spsc_pbuf_commit function. The first committed packet will be claimed first.
229 : * The returned buffer is 32 bit word aligned and points to the continuous memory.
230 : * Claimed packet must be freed using the @ref spsc_pbuf_free function.
231 : *
232 : * @note If data cache is used, cache is invalidate on the packet.
233 : *
234 : * @param[in] pb A buffer from which packet will be claimed.
235 : * @param[in,out] buf A location where claimed packet address is written.
236 : * It is 32 bit word aligned and points to the continuous memory.
237 : *
238 : * @retval 0 No packets in the buffer.
239 : * @retval positive packet length.
240 : */
241 1 : uint16_t spsc_pbuf_claim(struct spsc_pbuf *pb, char **buf);
242 :
243 : /**
244 : * @brief Free the packet to the buffer.
245 : *
246 : * Packet must be claimed (@ref spsc_pbuf_claim) before it can be freed.
247 : *
248 : * @param pb A packet buffer from which packet was claimed.
249 : * @param len Claimed packet length.
250 : */
251 1 : void spsc_pbuf_free(struct spsc_pbuf *pb, uint16_t len);
252 :
253 : /**
254 : * @brief Get maximum utilization of the packet buffer.
255 : *
256 : * Function can be used to tune the buffer size. Feature is enabled by
257 : * CONFIG_SPSC_PBUF_UTILIZATION. Utilization is updated by the consumer.
258 : *
259 : * @param pb A packet buffer.
260 : *
261 : * @retval -ENOTSUP Feature not enabled.
262 : * @retval non-negative Maximum utilization.
263 : */
264 1 : int spsc_pbuf_get_utilization(struct spsc_pbuf *pb);
265 : /**
266 : * @}
267 : */
268 :
269 : #ifdef __cplusplus
270 : }
271 : #endif
272 :
273 : #endif /* ZEPHYR_INCLUDE_SYS_SPSC_PBUF_H_ */
|