Line data Source code
1 0 : /*
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 1 : #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 0 : #define PBUF_MAYBE_CONST const
43 : #endif
44 :
45 : /** @brief Control block of packet buffer.
46 : *
47 : * The structure contains configuration data.
48 : */
49 1 : struct pbuf_cfg {
50 0 : volatile uint32_t *rd_idx_loc; /* Address of the variable holding
51 : * index value of the first valid byte
52 : * in data[].
53 : */
54 0 : volatile uint32_t *handshake_loc;/* Address of the variable holding
55 : * handshake information.
56 : */
57 0 : volatile uint32_t *wr_idx_loc; /* Address of the variable holding
58 : * index value of the first free byte
59 : * in data[].
60 : */
61 0 : uint32_t dcache_alignment; /* CPU data cache line size in bytes.
62 : * Used for validation - TODO: To be
63 : * replaced by flags.
64 : */
65 0 : uint32_t len; /* Length of data[] in bytes. */
66 0 : 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 1 : struct pbuf_data {
76 0 : volatile uint32_t wr_idx; /* Index of the first holding first
77 : * free byte in data[]. Used for
78 : * writing.
79 : */
80 0 : 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 1 : struct pbuf {
100 0 : PBUF_MAYBE_CONST struct pbuf_cfg *const cfg; /* Configuration of the
101 : * buffer.
102 : */
103 0 : 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 1 : #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 1 : #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 1 : #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 1 : 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 1 : 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 1 : 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 1 : 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 1 : 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 1 : 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 1 : 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_ */
|