1 /*
2  * Copyright (c) 2023 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #ifndef ZEPHYR_INCLUDE_IPC_PBUF_H_
8 #define ZEPHYR_INCLUDE_IPC_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 Packed buffer API
19  * @defgroup pbuf Packed Buffer API
20  * @ingroup ipc
21  * @{
22  */
23 
24 /** @brief Size of packet length field. */
25 #define PBUF_PACKET_LEN_SZ sizeof(uint32_t)
26 
27 /* Amount of data that is left unused to distinguish between empty and full. */
28 #define _PBUF_IDX_SIZE sizeof(uint32_t)
29 
30 /* Minimal length of the data field in the buffer to store the smalest packet
31  * possible.
32  * (+1) for at least one byte of data.
33  * (+_PBUF_IDX_SIZE) to distinguish buffer full and buffer empty.
34  * Rounded up to keep wr/rd indexes pointing to aligned address.
35  */
36 #define _PBUF_MIN_DATA_LEN ROUND_UP(PBUF_PACKET_LEN_SZ + 1 + _PBUF_IDX_SIZE, _PBUF_IDX_SIZE)
37 
38 #if defined(CONFIG_ARCH_POSIX)
39 /* For the native simulated boards we need to modify some pointers at init */
40 #define PBUF_MAYBE_CONST
41 #else
42 #define PBUF_MAYBE_CONST const
43 #endif
44 
45 /** @brief Control block of packet buffer.
46  *
47  * The structure contains configuration data.
48  */
49 struct pbuf_cfg {
50 	volatile uint32_t *rd_idx_loc;	 /* Address of the variable holding
51 					  * index value of the first valid byte
52 					  * in data[].
53 					  */
54 	volatile uint32_t *handshake_loc;/* Address of the variable holding
55 					  * handshake information.
56 					  */
57 	volatile uint32_t *wr_idx_loc;	 /* Address of the variable holding
58 					  * index value of the first free byte
59 					  * in data[].
60 					  */
61 	uint32_t dcache_alignment;	 /* CPU data cache line size in bytes.
62 					  * Used for validation - TODO: To be
63 					  * replaced by flags.
64 					  */
65 	uint32_t len;			 /* Length of data[] in bytes. */
66 	uint8_t *data_loc;		 /* Location of the data[]. */
67 };
68 
69 /**
70  * @brief Data block of the packed buffer.
71  *
72  * The structure contains local copies of wr and rd indexes used by writer and
73  * reader respectively.
74  */
75 struct pbuf_data {
76 	volatile uint32_t wr_idx;	/* Index of the first holding first
77 					 * free byte in data[]. Used for
78 					 * writing.
79 					 */
80 	volatile uint32_t rd_idx;	/* Index of the first holding first
81 					 * valid byte in data[]. Used for
82 					 * reading.
83 					 */
84 };
85 
86 
87 /**
88  * @brief Scure packed buffer.
89  *
90  * The packet buffer implements lightweight unidirectional packet
91  * buffer with read/write semantics on top of a memory region shared
92  * by the reader and writer. It embeds cache and memory barrier management to
93  * ensure correct data access.
94  *
95  * This structure supports single writer and reader. Data stored in the buffer
96  * is encapsulated to a message (with length header). The read/write API is
97  * written in a way to protect the data from being corrupted.
98  */
99 struct pbuf {
100 	PBUF_MAYBE_CONST struct pbuf_cfg *const cfg; /* Configuration of the
101 						      * buffer.
102 						      */
103 	struct pbuf_data data;			/* Data used to read and write
104 						 * to the buffer
105 						 */
106 };
107 
108 /**
109  * @brief Macro for configuration initialization.
110  *
111  * It is recommended to use this macro to initialize packed buffer
112  * configuration.
113  *
114  * @param mem_addr	Memory address for pbuf.
115  * @param size		Size of the memory.
116  * @param dcache_align	Data cache alignment.
117  * @param use_handshake	Add handshake word inside shared memory that can be access with
118  *			@ref pbuf_handshake_read and @ref pbuf_handshake_write.
119  */
120 #define PBUF_CFG_INIT(mem_addr, size, dcache_align, use_handshake)			\
121 {											\
122 	.rd_idx_loc = (uint32_t *)(mem_addr),						\
123 	.handshake_loc = use_handshake ? (uint32_t *)((uint8_t *)(mem_addr) +		\
124 				_PBUF_IDX_SIZE) : NULL,					\
125 	.wr_idx_loc = (uint32_t *)((uint8_t *)(mem_addr) + MAX(dcache_align,		\
126 				(use_handshake ? 2 : 1) * _PBUF_IDX_SIZE)),		\
127 	.data_loc = (uint8_t *)((uint8_t *)(mem_addr) +					\
128 				MAX(dcache_align, (use_handshake ? 2 : 1) *		\
129 						  _PBUF_IDX_SIZE) + _PBUF_IDX_SIZE),	\
130 	.len = (uint32_t)((uint32_t)(size) - MAX(dcache_align,				\
131 			(use_handshake ? 2 : 1) * _PBUF_IDX_SIZE) - _PBUF_IDX_SIZE),	\
132 	.dcache_alignment = (dcache_align),						\
133 }
134 
135 /**
136  * @brief Macro calculates memory overhead taken by the header in shared memory.
137  *
138  * It contains the read index, write index and padding.
139  *
140  * @param dcache_align	Data cache alignment.
141  */
142 #define PBUF_HEADER_OVERHEAD(dcache_align) \
143 	(MAX(dcache_align, _PBUF_IDX_SIZE) + _PBUF_IDX_SIZE)
144 
145 /**
146  * @brief Statically define and initialize pbuf.
147  *
148  * @param name			Name of the pbuf.
149  * @param mem_addr		Memory address for pbuf.
150  * @param size			Size of the memory.
151  * @param dcache_align		Data cache line size.
152  * @param use_handshake		Add handshake word inside shared memory that can be access with
153  *				@ref pbuf_handshake_read and @ref pbuf_handshake_write.
154  */
155 #define PBUF_DEFINE(name, mem_addr, size, dcache_align, use_handshake, compatibility)	\
156 	BUILD_ASSERT(dcache_align >= 0,							\
157 			"Cache line size must be non negative.");			\
158 	BUILD_ASSERT((size) > 0 && IS_PTR_ALIGNED_BYTES(size, _PBUF_IDX_SIZE),		\
159 			"Incorrect size.");						\
160 	BUILD_ASSERT(IS_PTR_ALIGNED_BYTES(mem_addr, MAX(dcache_align, _PBUF_IDX_SIZE)),	\
161 			"Misaligned memory.");						\
162 	BUILD_ASSERT(size >= (MAX(dcache_align, _PBUF_IDX_SIZE) + _PBUF_IDX_SIZE +	\
163 			_PBUF_MIN_DATA_LEN), "Insufficient size.");			\
164 	BUILD_ASSERT(!(compatibility) || (dcache_align) >= 8,				\
165 		"Data cache alignment must be at least 8 if compatibility is enabled.");\
166 	static PBUF_MAYBE_CONST struct pbuf_cfg cfg_##name =				\
167 			PBUF_CFG_INIT(mem_addr, size, dcache_align, use_handshake);	\
168 	static struct pbuf name = {							\
169 		.cfg = &cfg_##name,							\
170 	}
171 
172 /**
173  * @brief Initialize the Tx packet buffer.
174  *
175  * This function initializes the Tx packet buffer based on provided configuration.
176  * If the configuration is incorrect, the function will return error.
177  *
178  * It is recommended to use PBUF_DEFINE macro for build time initialization.
179  *
180  * @param pb	Pointer to the packed buffer containing
181  *		configuration and data. Configuration has to be
182  *		fixed before the initialization.
183  * @retval 0 on success.
184  * @retval -EINVAL when the input parameter is incorrect.
185  */
186 int pbuf_tx_init(struct pbuf *pb);
187 
188 /**
189  * @brief Initialize the Rx packet buffer.
190  *
191  * This function initializes the Rx packet buffer.
192  * If the configuration is incorrect, the function will return error.
193  *
194  * It is recommended to use PBUF_DEFINE macro for build time initialization.
195  *
196  * @param pb	Pointer to the packed buffer containing
197  *		configuration and data. Configuration has to be
198  *		fixed before the initialization.
199  * @retval 0 on success.
200  * @retval -EINVAL when the input parameter is incorrect.
201  */
202 int pbuf_rx_init(struct pbuf *pb);
203 
204 /**
205  * @brief Write specified amount of data to the packet buffer.
206  *
207  * This function call writes specified amount of data to the packet buffer if
208  * the buffer will fit the data.
209  *
210  * @param pb	A buffer to which to write.
211  * @param buf	Pointer to the data to be written to the buffer.
212  * @param len	Number of bytes to be written to the buffer. Must be positive.
213  * @retval int	Number of bytes written, negative error code on fail.
214  *		-EINVAL, if any of input parameter is incorrect.
215  *		-ENOMEM, if len is bigger than the buffer can fit.
216  */
217 
218 int pbuf_write(struct pbuf *pb, const char *buf, uint16_t len);
219 
220 /**
221  * @brief Read specified amount of data from the packet buffer.
222  *
223  * Single read allows to read the message send by the single write.
224  * The provided %p buf must be big enough to store the whole message.
225  *
226  * @param pb	A buffer from which data will be read.
227  * @param buf	Data pointer to which read data will be written.
228  *		If NULL, len of stored message is returned.
229  * @param len	Number of bytes to be read from the buffer.
230  * @retval int	Bytes read, negative error code on fail.
231  *		Bytes to be read, if buf == NULL.
232  *		-EINVAL, if any of input parameter is incorrect.
233  *		-ENOMEM, if message can not fit in provided buf.
234  *		-EAGAIN, if not whole message is ready yet.
235  */
236 int pbuf_read(struct pbuf *pb, char *buf, uint16_t len);
237 
238 /**
239  * @brief Read handshake word from pbuf.
240  *
241  * The pb must be defined with "PBUF_DEFINE" with "use_handshake" set.
242  *
243  * @param pb		A buffer from which data will be read.
244  * @retval uint32_t	The handshake word value.
245  */
246 uint32_t pbuf_handshake_read(struct pbuf *pb);
247 
248 /**
249  * @brief Write handshake word to pbuf.
250  *
251  * The pb must be defined with "PBUF_DEFINE" with "use_handshake" set.
252  *
253  * @param pb		A buffer to which data will be written.
254  * @param value		A handshake value.
255  */
256 void pbuf_handshake_write(struct pbuf *pb, uint32_t value);
257 
258 /**
259  * @brief Get first buffer from pbuf.
260  *
261  * This function retrieves buffer located at the beginning of queue.
262  * It will be continuous block since it is the first buffer.
263  *
264  * @param pb		A buffer from which data will be read.
265  * @param[out] buf	A pointer to output pointer to the date of the first buffer.
266  * @param[out] len	A pointer to output length the first buffer.
267  * @retval		0 on success.
268  *			-EINVAL when there is no buffer at the beginning of queue.
269  */
270 int pbuf_get_initial_buf(struct pbuf *pb, volatile char **buf, uint16_t *len);
271 
272 /**
273  * @}
274  */
275 
276 #ifdef __cplusplus
277 }
278 #endif
279 
280 #endif /* ZEPHYR_INCLUDE_IPC_PBUF_H_ */
281