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