1 /* 2 * Copyright (c) 2021 Nordic Semiconductor ASA 3 * 4 * SPDX-License-Identifier: Apache-2.0 5 */ 6 #ifndef ZEPHYR_INCLUDE_SYS_MPSC_PBUF_H_ 7 #define ZEPHYR_INCLUDE_SYS_MPSC_PBUF_H_ 8 9 #include <zephyr/kernel.h> 10 #include <zephyr/sys/mpsc_packet.h> 11 #include <string.h> 12 #include <stdint.h> 13 #include <stdbool.h> 14 15 #ifdef __cplusplus 16 extern "C" { 17 #endif 18 19 /** 20 * @brief Multi producer, single consumer packet buffer API 21 * @defgroup mpsc_buf MPSC (Multi producer, single consumer) packet buffer API 22 * @ingroup datastructure_apis 23 * @{ 24 */ 25 26 /* 27 * Multi producer, single consumer packet buffer allows to allocate variable 28 * length consecutive space for storing a packet. When space is allocated 29 * it can be filled by the user (except for the first 2 bits) and when packet 30 * is ready it is committed. It is allowed to allocate another packet before 31 * committing the previous one. 32 * 33 * If buffer is full and packet cannot be allocated then null is returned unless 34 * overwrite mode is selected. In that mode, oldest entry are dropped (user is 35 * notified) until allocation succeeds. It can happen that candidate for 36 * dropping is currently being claimed. In that case, it is omitted and next 37 * packet is dropped and claimed packet is marked as invalid when freeing. 38 * 39 * Reading packets is performed in two steps. First packet is claimed. Claiming 40 * returns pointer to the packet within the buffer. Packet is freed when no 41 * longer in use. 42 */ 43 44 /**@defgroup MPSC_PBUF_FLAGS MPSC packet buffer flags 45 * @{ 46 */ 47 48 /** @brief Flag indicating that buffer size is power of 2. 49 * 50 * When buffer size is power of 2 then optimizations are applied. 51 */ 52 #define MPSC_PBUF_SIZE_POW2 BIT(0) 53 54 /** @brief Flag indicating buffer full policy. 55 * 56 * If flag is set then when allocating from a full buffer oldest packets are 57 * dropped. When flag is not set then allocation returns null. 58 */ 59 #define MPSC_PBUF_MODE_OVERWRITE BIT(1) 60 61 /** @brief Flag indicating that maximum buffer usage is tracked. */ 62 #define MPSC_PBUF_MAX_UTILIZATION BIT(2) 63 64 /** @brief Flag indicated that buffer is currently full. */ 65 #define MPSC_PBUF_FULL BIT(3) 66 67 /**@} */ 68 69 /* Forward declaration */ 70 struct mpsc_pbuf_buffer; 71 72 /** @brief Callback prototype for getting length of a packet. 73 * 74 * @param packet User packet. 75 * 76 * @return Size of the packet in 32 bit words. 77 */ 78 typedef uint32_t (*mpsc_pbuf_get_wlen)(const union mpsc_pbuf_generic *packet); 79 80 /** @brief Callback called when packet is dropped. 81 * 82 * @param buffer Packet buffer. 83 * 84 * @param packet Packet that is being dropped. 85 */ 86 typedef void (*mpsc_pbuf_notify_drop)(const struct mpsc_pbuf_buffer *buffer, 87 const union mpsc_pbuf_generic *packet); 88 89 /** @brief MPSC packet buffer structure. */ 90 struct mpsc_pbuf_buffer { 91 /** Temporary write index. */ 92 uint32_t tmp_wr_idx; 93 94 /** Write index. */ 95 uint32_t wr_idx; 96 97 /** Temporary read index. */ 98 uint32_t tmp_rd_idx; 99 100 /** Read index. */ 101 uint32_t rd_idx; 102 103 /** Flags. */ 104 uint32_t flags; 105 106 /** Lock. */ 107 struct k_spinlock lock; 108 109 /** User callback called whenever packet is dropped. 110 * 111 * May be NULL if unneeded. 112 */ 113 mpsc_pbuf_notify_drop notify_drop; 114 115 /** Callback for getting packet length. */ 116 mpsc_pbuf_get_wlen get_wlen; 117 118 /* Buffer. */ 119 uint32_t *buf; 120 121 /* Buffer size in 32 bit words. */ 122 uint32_t size; 123 124 /* Store max buffer usage. */ 125 uint32_t max_usage; 126 127 struct k_sem sem; 128 }; 129 130 /** @brief MPSC packet buffer configuration. */ 131 struct mpsc_pbuf_buffer_config { 132 /* Pointer to a memory used for storing packets. */ 133 uint32_t *buf; 134 135 /* Buffer size in 32 bit words. */ 136 uint32_t size; 137 138 /* Callbacks. */ 139 mpsc_pbuf_notify_drop notify_drop; 140 mpsc_pbuf_get_wlen get_wlen; 141 142 /* Configuration flags. */ 143 uint32_t flags; 144 }; 145 146 /** @brief Initialize a packet buffer. 147 * 148 * @param buffer Buffer. 149 * 150 * @param config Configuration. 151 */ 152 void mpsc_pbuf_init(struct mpsc_pbuf_buffer *buffer, 153 const struct mpsc_pbuf_buffer_config *config); 154 155 /** @brief Allocate a packet. 156 * 157 * If a buffer is configured to overwrite mode then if there is no space to 158 * allocate a new buffer, oldest packets are dropped. Otherwise allocation 159 * fails and null pointer is returned. 160 * 161 * @param buffer Buffer. 162 * 163 * @param wlen Number of words to allocate. 164 * 165 * @param timeout Timeout. If called from thread context it will pend for given 166 * timeout if packet cannot be allocated before dropping the oldest or 167 * returning null. 168 * 169 * @return Pointer to the allocated space or null if it cannot be allocated. 170 */ 171 union mpsc_pbuf_generic *mpsc_pbuf_alloc(struct mpsc_pbuf_buffer *buffer, 172 size_t wlen, k_timeout_t timeout); 173 174 /** @brief Commit a packet. 175 * 176 * @param buffer Buffer. 177 * 178 * @param packet Pointer to a packet allocated by @ref mpsc_pbuf_alloc. 179 */ 180 void mpsc_pbuf_commit(struct mpsc_pbuf_buffer *buffer, 181 union mpsc_pbuf_generic *packet); 182 183 /** @brief Put single word packet into a buffer. 184 * 185 * Function is optimized for storing a packet which fit into a single word. 186 * Note that 2 bits of that word is used by the buffer. 187 * 188 * @param buffer Buffer. 189 * 190 * @param word Packet content consisting of MPSC_PBUF_HDR with valid bit set 191 * and data on remaining bits. 192 */ 193 void mpsc_pbuf_put_word(struct mpsc_pbuf_buffer *buffer, 194 const union mpsc_pbuf_generic word); 195 196 /** @brief Put a packet consisting of a word and a pointer. 197 * * 198 * Function is optimized for storing packet consisting of a word and a pointer. 199 * Note that 2 bits of a first word is used by the buffer. 200 * 201 * @param buffer Buffer. 202 * 203 * @param word First word of a packet consisting of MPSC_PBUF_HDR with valid 204 * bit set and data on remaining bits. 205 * 206 * @param data User data. 207 */ 208 void mpsc_pbuf_put_word_ext(struct mpsc_pbuf_buffer *buffer, 209 const union mpsc_pbuf_generic word, 210 const void *data); 211 212 /** @brief Put a packet into a buffer. 213 * 214 * Copy data into a buffer. 215 * Note that 2 bits of a first word is used by the buffer. 216 * 217 * @param buffer Buffer. 218 * 219 * @param data First word of data must contain MPSC_PBUF_HDR with valid bit set. 220 * 221 * @param wlen Packet size in words. 222 */ 223 void mpsc_pbuf_put_data(struct mpsc_pbuf_buffer *buffer, 224 const uint32_t *data, size_t wlen); 225 226 /** @brief Claim the first pending packet. 227 * 228 * @param buffer Buffer. 229 * 230 * @return Pointer to the claimed packet or null if none available. 231 */ 232 const union mpsc_pbuf_generic *mpsc_pbuf_claim(struct mpsc_pbuf_buffer *buffer); 233 234 /** @brief Free a packet. 235 * 236 * @param buffer Buffer. 237 * 238 * @param packet Packet. 239 */ 240 void mpsc_pbuf_free(struct mpsc_pbuf_buffer *buffer, 241 const union mpsc_pbuf_generic *packet); 242 243 /** @brief Check if there are any message pending. 244 * 245 * @param buffer Buffer. 246 * 247 * @retval true if pending. 248 * @retval false if no message is pending. 249 */ 250 bool mpsc_pbuf_is_pending(struct mpsc_pbuf_buffer *buffer); 251 252 /** @brief Get current memory utilization. 253 * 254 * @param[in, out] buffer Buffer. 255 * @param[out] size Buffer size in bytes. 256 * @param[out] now Current buffer usage in bytes. 257 */ 258 void mpsc_pbuf_get_utilization(struct mpsc_pbuf_buffer *buffer, 259 uint32_t *size, uint32_t *now); 260 261 /** @brief Get maximum memory utilization. 262 * 263 * @param[in, out] buffer Buffer. 264 * @param[out] max Maximum buffer usage in bytes. 265 * 266 * retval 0 if utilization data collected successfully. 267 * retval -ENOTSUP if Collecting utilization data is not supported. 268 */ 269 int mpsc_pbuf_get_max_utilization(struct mpsc_pbuf_buffer *buffer, uint32_t *max); 270 /** 271 * @} 272 */ 273 274 #ifdef __cplusplus 275 } 276 #endif 277 278 #endif /* ZEPHYR_INCLUDE_SYS_MPSC_PBUF_H_ */ 279