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 *wr_idx_loc;	/* Address of the variable holding
55 					 * index value of the first free byte
56 					 * in data[].
57 					 */
58 	uint32_t dcache_alignment;	/* CPU data cache line size in bytes.
59 					 * Used for validation - TODO: To be
60 					 * replaced by flags.
61 					 */
62 	uint32_t len;			/* Length of data[] in bytes. */
63 	uint8_t *data_loc;		/* Location of the data[]. */
64 };
65 
66 /**
67  * @brief Data block of the packed buffer.
68  *
69  * The structure contains local copies of wr and rd indexes used by writer and
70  * reader respectively.
71  */
72 struct pbuf_data {
73 	volatile uint32_t wr_idx;	/* Index of the first holding first
74 					 * free byte in data[]. Used for
75 					 * writing.
76 					 */
77 	volatile uint32_t rd_idx;	/* Index of the first holding first
78 					 * valid byte in data[]. Used for
79 					 * reading.
80 					 */
81 };
82 
83 
84 /**
85  * @brief Scure packed buffer.
86  *
87  * The packet buffer implements lightweight unidirectional packet
88  * buffer with read/write semantics on top of a memory region shared
89  * by the reader and writer. It embeds cache and memory barrier management to
90  * ensure correct data access.
91  *
92  * This structure supports single writer and reader. Data stored in the buffer
93  * is encapsulated to a message (with length header). The read/write API is
94  * written in a way to protect the data from being corrupted.
95  */
96 struct pbuf {
97 	PBUF_MAYBE_CONST struct pbuf_cfg *const cfg; /* Configuration of the
98 						      * buffer.
99 						      */
100 	struct pbuf_data data;			/* Data used to read and write
101 						 * to the buffer
102 						 */
103 };
104 
105 /**
106  * @brief Macro for configuration initialization.
107  *
108  * It is recommended to use this macro to initialize packed buffer
109  * configuration.
110  *
111  * @param mem_addr	Memory address for pbuf.
112  * @param size		Size of the memory.
113  * @param dcache_align	Data cache alignment.
114  */
115 #define PBUF_CFG_INIT(mem_addr, size, dcache_align)					\
116 {											\
117 	.rd_idx_loc = (uint32_t *)(mem_addr),						\
118 	.wr_idx_loc = (uint32_t *)((uint8_t *)(mem_addr) +				\
119 				MAX(dcache_align, _PBUF_IDX_SIZE)),			\
120 	.data_loc = (uint8_t *)((uint8_t *)(mem_addr) +					\
121 				MAX(dcache_align, _PBUF_IDX_SIZE) + _PBUF_IDX_SIZE),	\
122 	.len = (uint32_t)((uint32_t)(size) - MAX(dcache_align, _PBUF_IDX_SIZE) -	\
123 				_PBUF_IDX_SIZE),					\
124 	.dcache_alignment = (dcache_align),						\
125 }
126 
127 /**
128  * @brief Macro calculates memory overhead taken by the header in shared memory.
129  *
130  * It contains the read index, write index and padding.
131  *
132  * @param dcache_align	Data cache alignment.
133  */
134 #define PBUF_HEADER_OVERHEAD(dcache_align) \
135 	(MAX(dcache_align, _PBUF_IDX_SIZE) + _PBUF_IDX_SIZE)
136 
137 /**
138  * @brief Statically define and initialize pbuf.
139  *
140  * @param name			Name of the pbuf.
141  * @param mem_addr		Memory address for pbuf.
142  * @param size			Size of the memory.
143  * @param dcache_align	Data cache line size.
144  */
145 #define PBUF_DEFINE(name, mem_addr, size, dcache_align)					\
146 	BUILD_ASSERT(dcache_align >= 0,							\
147 			"Cache line size must be non negative.");			\
148 	BUILD_ASSERT((size) > 0 && IS_PTR_ALIGNED_BYTES(size, _PBUF_IDX_SIZE),		\
149 			"Incorrect size.");						\
150 	BUILD_ASSERT(IS_PTR_ALIGNED_BYTES(mem_addr, MAX(dcache_align, _PBUF_IDX_SIZE)),	\
151 			"Misaligned memory.");						\
152 	BUILD_ASSERT(size >= (MAX(dcache_align, _PBUF_IDX_SIZE) + _PBUF_IDX_SIZE +	\
153 			_PBUF_MIN_DATA_LEN), "Insufficient size.");			\
154 	static PBUF_MAYBE_CONST struct pbuf_cfg cfg_##name =				\
155 			PBUF_CFG_INIT(mem_addr, size, dcache_align);			\
156 	static struct pbuf name = {							\
157 		.cfg = &cfg_##name,							\
158 	}
159 
160 /**
161  * @brief Initialize the Tx packet buffer.
162  *
163  * This function initializes the Tx packet buffer based on provided configuration.
164  * If the configuration is incorrect, the function will return error.
165  *
166  * It is recommended to use PBUF_DEFINE macro for build time initialization.
167  *
168  * @param pb	Pointer to the packed buffer containing
169  *		configuration and data. Configuration has to be
170  *		fixed before the initialization.
171  * @retval 0 on success.
172  * @retval -EINVAL when the input parameter is incorrect.
173  */
174 int pbuf_tx_init(struct pbuf *pb);
175 
176 /**
177  * @brief Initialize the Rx packet buffer.
178  *
179  * This function initializes the Rx packet buffer.
180  * If the configuration is incorrect, the function will return error.
181  *
182  * It is recommended to use PBUF_DEFINE macro for build time initialization.
183  *
184  * @param pb	Pointer to the packed buffer containing
185  *		configuration and data. Configuration has to be
186  *		fixed before the initialization.
187  * @retval 0 on success.
188  * @retval -EINVAL when the input parameter is incorrect.
189  */
190 int pbuf_rx_init(struct pbuf *pb);
191 
192 /**
193  * @brief Write specified amount of data to the packet buffer.
194  *
195  * This function call writes specified amount of data to the packet buffer if
196  * the buffer will fit the data.
197  *
198  * @param pb	A buffer to which to write.
199  * @param buf	Pointer to the data to be written to the buffer.
200  * @param len	Number of bytes to be written to the buffer. Must be positive.
201  * @retval int	Number of bytes written, negative error code on fail.
202  *		-EINVAL, if any of input parameter is incorrect.
203  *		-ENOMEM, if len is bigger than the buffer can fit.
204  */
205 
206 int pbuf_write(struct pbuf *pb, const char *buf, uint16_t len);
207 
208 /**
209  * @brief Read specified amount of data from the packet buffer.
210  *
211  * Single read allows to read the message send by the single write.
212  * The provided %p buf must be big enough to store the whole message.
213  *
214  * @param pb	A buffer from which data will be read.
215  * @param buf	Data pointer to which read data will be written.
216  *		If NULL, len of stored message is returned.
217  * @param len	Number of bytes to be read from the buffer.
218  * @retval int	Bytes read, negative error code on fail.
219  *		Bytes to be read, if buf == NULL.
220  *		-EINVAL, if any of input parameter is incorrect.
221  *		-ENOMEM, if message can not fit in provided buf.
222  *		-EAGAIN, if not whole message is ready yet.
223  */
224 int pbuf_read(struct pbuf *pb, char *buf, uint16_t len);
225 
226 /**
227  * @}
228  */
229 
230 #ifdef __cplusplus
231 }
232 #endif
233 
234 #endif /* ZEPHYR_INCLUDE_IPC_PBUF_H_ */
235