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 <kernel.h> 10 #include <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 kernel_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 ommited 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 /**@} */ 62 63 /* Forward declaration */ 64 struct mpsc_pbuf_buffer; 65 66 /** @brief Callback prototype for getting length of a packet. 67 * 68 * @param packet User packet. 69 * 70 * @return Size of the packet in 32 bit words. 71 */ 72 typedef uint32_t (*mpsc_pbuf_get_wlen)(const union mpsc_pbuf_generic *packet); 73 74 /** @brief Callback called when packet is dropped. 75 * 76 * @param buffer Packet buffer. 77 * 78 * @param packet Packet that is being dropped. 79 */ 80 typedef void (*mpsc_pbuf_notify_drop)(const struct mpsc_pbuf_buffer *buffer, 81 const union mpsc_pbuf_generic *packet); 82 83 /** @brief MPSC packet buffer structure. */ 84 struct mpsc_pbuf_buffer { 85 /** Temporary write index. */ 86 uint32_t tmp_wr_idx; 87 88 /** Write index. */ 89 uint32_t wr_idx; 90 91 /** Temporary read index. */ 92 uint32_t tmp_rd_idx; 93 94 /** Read index. */ 95 uint32_t rd_idx; 96 97 /** Flags. */ 98 uint32_t flags; 99 100 /** Lock. */ 101 struct k_spinlock lock; 102 103 /** User callback called whenever packet is dropped. */ 104 mpsc_pbuf_notify_drop notify_drop; 105 106 /** Callback for getting packet length. */ 107 mpsc_pbuf_get_wlen get_wlen; 108 109 /* Buffer. */ 110 uint32_t *buf; 111 112 /* Buffer size in 32 bit words. */ 113 uint32_t size; 114 115 struct k_sem sem; 116 }; 117 118 /** @brief MPSC packet buffer configuration. */ 119 struct mpsc_pbuf_buffer_config { 120 /* Pointer to a memory used for storing packets. */ 121 uint32_t *buf; 122 123 /* Buffer size in 32 bit words. */ 124 uint32_t size; 125 126 /* Callbacks. */ 127 mpsc_pbuf_notify_drop notify_drop; 128 mpsc_pbuf_get_wlen get_wlen; 129 130 /* Configuration flags. */ 131 uint32_t flags; 132 }; 133 134 /** @brief Initnialize a packet buffer. 135 * 136 * @param buffer Buffer. 137 * 138 * @param config Configuration. 139 */ 140 void mpsc_pbuf_init(struct mpsc_pbuf_buffer *buffer, 141 const struct mpsc_pbuf_buffer_config *config); 142 143 /** @brief Allocate a packet. 144 * 145 * If a buffer is configured to overwrite mode then if there is no space to 146 * allocated a new buffer, oldest packets are dropped. Otherwise allocation 147 * fails and null pointer is returned. 148 * 149 * @param buffer Buffer. 150 * 151 * @param wlen Number of words to allocate. 152 * 153 * @param timeout Timeout. If called from thread context it will pend for given 154 * timeout if packet cannot be allocated before dropping the oldest or 155 * returning null. 156 * 157 * @return Pointer to the allocated space or null if it cannot be allocated. 158 */ 159 union mpsc_pbuf_generic *mpsc_pbuf_alloc(struct mpsc_pbuf_buffer *buffer, 160 size_t wlen, k_timeout_t timeout); 161 162 /** @brief Commit a packet. 163 * 164 * @param buffer Buffer. 165 * 166 * @param packet Pointer to a packet allocated by @ref mpsc_pbuf_alloc. 167 */ 168 void mpsc_pbuf_commit(struct mpsc_pbuf_buffer *buffer, 169 union mpsc_pbuf_generic *packet); 170 171 /** @brief Put single word packet into a buffer. 172 * 173 * Function is optimized for storing a packet which fit into a single word. 174 * Note that 2 bits of that word is used by the buffer. 175 * 176 * @param buffer Buffer. 177 * 178 * @param word Packet content consisting of MPSC_PBUF_HDR with valid bit set 179 * and data on remaining bits. 180 */ 181 void mpsc_pbuf_put_word(struct mpsc_pbuf_buffer *buffer, 182 const union mpsc_pbuf_generic word); 183 184 /** @brief Put a packet consisting of a word and a pointer. 185 * * 186 * Function is optimized for storing packet consisting of a word and a pointer. 187 * Note that 2 bits of a first word is used by the buffer. 188 * 189 * @param buffer Buffer. 190 * 191 * @param word First word of a packet consisting of MPSC_PBUF_HDR with valid 192 * bit set and data on remaining bits. 193 * 194 * @param data User data. 195 */ 196 void mpsc_pbuf_put_word_ext(struct mpsc_pbuf_buffer *buffer, 197 const union mpsc_pbuf_generic word, 198 const void *data); 199 200 /** @brief Put a packet into a buffer. 201 * 202 * Copy data into a buffer. 203 * Note that 2 bits of a first word is used by the buffer. 204 * 205 * @param buffer Buffer. 206 * 207 * @param data First word of data must contain MPSC_PBUF_HDR with valid bit set. 208 * 209 * @param wlen Packet size in words. 210 */ 211 void mpsc_pbuf_put_data(struct mpsc_pbuf_buffer *buffer, 212 const uint32_t *data, size_t wlen); 213 214 /** @brief Claim the first pending packet. 215 * 216 * @param buffer Buffer. 217 * 218 * @return Pointer to the claimed packet or null if none available. 219 */ 220 const union mpsc_pbuf_generic *mpsc_pbuf_claim(struct mpsc_pbuf_buffer *buffer); 221 222 /** @brief Free a packet. 223 * 224 * @param buffer Buffer. 225 * 226 * @param packet Packet. 227 */ 228 void mpsc_pbuf_free(struct mpsc_pbuf_buffer *buffer, 229 const union mpsc_pbuf_generic *packet); 230 231 /** @brief Check if there are any message pending. 232 * 233 * @param buffer Buffer. 234 * 235 * @retval true if pending. 236 * @retval false if no message is pending. 237 */ 238 bool mpsc_pbuf_is_pending(struct mpsc_pbuf_buffer *buffer); 239 240 /** 241 * @} 242 */ 243 244 #ifdef __cplusplus 245 } 246 #endif 247 248 #endif /* ZEPHYR_INCLUDE_SYS_MPSC_PBUF_H_ */ 249