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_ */