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