lib: os: Rename icmsg_buf to spsc_pbuf

Move icmsg_buf to lib/os and rename to spsc_pbuf (Single Producer
Single Consumer Packet Buffer). It is a generic module and initially
was created as internal module for ipc service.

Signed-off-by: Krzysztof Chruscinski <krzysztof.chruscinski@nordicsemi.no>
This commit is contained in:
Krzysztof Chruscinski 2022-05-17 15:49:59 +02:00 committed by Carles Cufí
commit 2f189e39a5
15 changed files with 240 additions and 241 deletions

View file

@ -4,16 +4,16 @@
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
#ifndef ZEPHYR_INCLUDE_IPC_SERVICE_IPC_ICMSG_BUF_H_ #ifndef ZEPHYR_INCLUDE_SYS_SPSC_PBUF_H_
#define ZEPHYR_INCLUDE_IPC_SERVICE_IPC_ICMSG_BUF_H_ #define ZEPHYR_INCLUDE_SYS_SPSC_PBUF_H_
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
/** /**
* @brief IPC Service ICMsg buffer API * @brief Single producer, single consumer packet buffer API
* @ingroup ipc_service_icmsg_buffer_api IPC service ICMsg buffer API * @ingroup kernel_apis
* @{ * @{
*/ */
@ -29,7 +29,7 @@ extern "C" {
* is encapsulated to a message. * is encapsulated to a message.
* *
*/ */
struct icmsg_buf { struct spsc_pbuf {
uint32_t len; /* Length of data[] in bytes. */ uint32_t len; /* Length of data[] in bytes. */
uint32_t wr_idx; /* Index of the first free byte in data[] */ uint32_t wr_idx; /* Index of the first free byte in data[] */
uint32_t rd_idx; /* Index of the first valid byte in data[] */ uint32_t rd_idx; /* Index of the first valid byte in data[] */
@ -37,9 +37,9 @@ struct icmsg_buf {
}; };
/** /**
* @brief Initialize inter core messaging buffer. * @brief Initialize the packet buffer.
* *
* This function initializes inter core messaging buffer on top of dedicated * This function initializes the packet buffer on top of a dedicated
* memory region. * memory region.
* *
* @param buf Pointer to a memory region on which buffer is * @param buf Pointer to a memory region on which buffer is
@ -48,39 +48,39 @@ struct icmsg_buf {
* contain the internal structure and at least two * contain the internal structure and at least two
* bytes of data (one is reserved for written * bytes of data (one is reserved for written
* messages length). * messages length).
* @retval struct icmsg_buf* Pointer to the created buffer. The pointer * @retval struct spsc_pbuf* Pointer to the created buffer. The pointer
* points to the same address as buf. * points to the same address as buf.
*/ */
struct icmsg_buf *icmsg_buf_init(void *buf, size_t blen); struct spsc_pbuf *spsc_pbuf_init(void *buf, size_t blen);
/** /**
* @brief Write specified amount of data to the inter core messaging buffer. * @brief Write specified amount of data to the packet buffer.
* *
* @param ib A icmsg buffer to which to write. * @param pb A buffer to which to write.
* @param buf Pointer to the data to be written to icmsg buffer. * @param buf Pointer to the data to be written to the buffer.
* @param len Number of bytes to be written to the icmsg buffer. * @param len Number of bytes to be written to the buffer.
* @retval int Number of bytes written, negative error code on fail. * @retval int Number of bytes written, negative error code on fail.
* -EINVAL, if len == 0. * -EINVAL, if len == 0.
* -ENOMEM, if len is bigger than the icmsg buffer can fit. * -ENOMEM, if len is bigger than the buffer can fit.
*/ */
int icmsg_buf_write(struct icmsg_buf *ib, const char *buf, uint16_t len); int spsc_pbuf_write(struct spsc_pbuf *pb, const char *buf, uint16_t len);
/** /**
* @brief Read specified amount of data from the inter core messaging buffer. * @brief Read specified amount of data from the packet buffer.
* *
* Single read allows to read the message send by the single write. * Single read allows to read the message send by the single write.
* The provided buf must be big enough to store the whole message. * The provided buf must be big enough to store the whole message.
* *
* @param ib A icmsg buffer to which data are to be written * @param pb A buffer from which data is to be read.
* @param buf Data pointer to which read data will be written. * @param buf Data pointer to which read data will be written.
* If NULL, len of stored message is returned. * If NULL, len of stored message is returned.
* @param len Number of bytes to be read from the icmsg buffer. * @param len Number of bytes to be read from the buffer.
* @retval int Bytes read, negative error code on fail. * @retval int Bytes read, negative error code on fail.
* Bytes to be read, if buf == NULL. * Bytes to be read, if buf == NULL.
* -ENOMEM, if message can not fit in provided buf. * -ENOMEM, if message can not fit in provided buf.
* -EAGAIN, if not whole message is ready yet. * -EAGAIN, if not whole message is ready yet.
*/ */
int icmsg_buf_read(struct icmsg_buf *ib, char *buf, uint16_t len); int spsc_pbuf_read(struct spsc_pbuf *pb, char *buf, uint16_t len);
/** /**
@ -91,4 +91,4 @@ int icmsg_buf_read(struct icmsg_buf *ib, char *buf, uint16_t len);
} }
#endif #endif
#endif /* ZEPHYR_INCLUDE_IPC_SERVICE_IPC_ICMSG_BUF_H_ */ #endif /* ZEPHYR_INCLUDE_SYS_SPSC_PBUF_H_ */

View file

@ -37,11 +37,12 @@ if (CONFIG_ASSERT OR CONFIG_ASSERT_VERBOSE)
zephyr_sources(assert.c) zephyr_sources(assert.c)
endif() endif()
zephyr_sources_ifdef(CONFIG_USERSPACE mutex.c user_work.c) zephyr_sources_ifdef(CONFIG_USERSPACE mutex.c user_work.c)
zephyr_sources_ifdef(CONFIG_MPSC_PBUF mpsc_pbuf.c) zephyr_sources_ifdef(CONFIG_MPSC_PBUF mpsc_pbuf.c)
zephyr_sources_ifdef(CONFIG_SPSC_PBUF spsc_pbuf.c)
zephyr_sources_ifdef(CONFIG_SCHED_DEADLINE p4wq.c) zephyr_sources_ifdef(CONFIG_SCHED_DEADLINE p4wq.c)
zephyr_sources_ifdef(CONFIG_REBOOT reboot.c) zephyr_sources_ifdef(CONFIG_REBOOT reboot.c)

View file

@ -38,6 +38,13 @@ config MPSC_PBUF
storing variable length packets in a circular way and operate directly storing variable length packets in a circular way and operate directly
on the buffer memory. on the buffer memory.
config SPSC_PBUF
bool "Single producer, single consumer packet buffer"
help
Enable usage of spsc packet buffer. Packet buffer is capable of
storing variable length packets in a circular way and operate directly
on the buffer memory.
config SHARED_MULTI_HEAP config SHARED_MULTI_HEAP
bool "Shared multi-heap manager" bool "Shared multi-heap manager"
help help

171
lib/os/spsc_pbuf.c Normal file
View file

@ -0,0 +1,171 @@
/*
* Copyright (c) 2022 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/zephyr.h>
#include <string.h>
#include <errno.h>
#include <zephyr/cache.h>
#include <zephyr/sys/spsc_pbuf.h>
/* Helpers */
static uint32_t idx_occupied(uint32_t len, uint32_t a, uint32_t b)
{
/* It is implicitly assumed a and b cannot differ by more then len. */
return (b > a) ? (len - (b - a)) : (a - b);
}
static uint32_t idx_cut(uint32_t len, uint32_t idx)
{
/* It is implicitly assumed a and b cannot differ by more then len. */
return (idx >= len) ? (idx - len) : (idx);
}
struct spsc_pbuf *spsc_pbuf_init(void *buf, size_t blen)
{
/* blen must be big enough to contain spsc_pbuf struct, byte of data
* and message len (2 bytes).
*/
struct spsc_pbuf *pb = buf;
__ASSERT_NO_MSG(blen > (sizeof(*pb) + sizeof(uint16_t)));
pb->len = blen - sizeof(*pb);
pb->wr_idx = 0;
pb->rd_idx = 0;
__sync_synchronize();
sys_cache_data_range(pb, sizeof(*pb), K_CACHE_WB);
return pb;
}
int spsc_pbuf_write(struct spsc_pbuf *pb, const char *buf, uint16_t len)
{
/* The length of buffer is immutable - avoid reloading that may happen
* due to memory bariers.
*/
const uint32_t pblen = pb->len;
/* rx_idx == wr_idx means the buffer is empty.
* Max bytes that can be stored is len - 1.
*/
const uint32_t max_len = pblen - 1;
sys_cache_data_range(pb, sizeof(*pb), K_CACHE_INVD);
__sync_synchronize();
uint32_t wr_idx = pb->wr_idx;
uint32_t rd_idx = pb->rd_idx;
if (len == 0) {
/* Incorrect call. */
return -EINVAL;
}
uint32_t avail = max_len - idx_occupied(pblen, wr_idx, rd_idx);
if ((len + sizeof(len) > avail) ||
(len + sizeof(len) > max_len)) {
/* No free space. */
return -ENOMEM;
}
/* Store info about the message length. */
pb->data[wr_idx] = (uint8_t)len;
sys_cache_data_range(&pb->data[wr_idx], sizeof(pb->data[wr_idx]), K_CACHE_WB);
wr_idx = idx_cut(pblen, wr_idx + sizeof(pb->data[wr_idx]));
pb->data[wr_idx] = (uint8_t)(len >> 8);
sys_cache_data_range(&pb->data[wr_idx], sizeof(pb->data[wr_idx]), K_CACHE_WB);
wr_idx = idx_cut(pblen, wr_idx + sizeof(pb->data[wr_idx]));
/* Write until the end of the buffer. */
uint32_t sz = MIN(len, pblen - wr_idx);
memcpy(&pb->data[wr_idx], buf, sz);
sys_cache_data_range(&pb->data[wr_idx], sz, K_CACHE_WB);
if (len > sz) {
/* Write remaining data at the buffer head. */
memcpy(&pb->data[0], buf + sz, len - sz);
sys_cache_data_range(&pb->data[0], len - sz, K_CACHE_WB);
}
/* Update write index - make other side aware data was written. */
__sync_synchronize();
wr_idx = idx_cut(pblen, wr_idx + len);
pb->wr_idx = wr_idx;
sys_cache_data_range(pb, sizeof(*pb), K_CACHE_WB);
return len;
}
int spsc_pbuf_read(struct spsc_pbuf *pb, char *buf, uint16_t len)
{
/* The length of buffer is immutable - avoid reloading. */
const uint32_t pblen = pb->len;
sys_cache_data_range(pb, sizeof(*pb), K_CACHE_INVD);
__sync_synchronize();
uint32_t rd_idx = pb->rd_idx;
uint32_t wr_idx = pb->wr_idx;
if (rd_idx == wr_idx) {
/* The buffer is empty. */
return 0;
}
uint32_t bytes_stored = idx_occupied(pblen, wr_idx, rd_idx);
/* Read message len. */
sys_cache_data_range(&pb->data[rd_idx], sizeof(pb->data[rd_idx]), K_CACHE_INVD);
uint16_t mlen = pb->data[rd_idx];
rd_idx = idx_cut(pblen, rd_idx + sizeof(pb->data[rd_idx]));
sys_cache_data_range(&pb->data[rd_idx], sizeof(pb->data[rd_idx]), K_CACHE_INVD);
mlen |= (pb->data[rd_idx] << 8);
rd_idx = idx_cut(pblen, rd_idx + sizeof(pb->data[rd_idx]));
if (!buf) {
return mlen;
}
if (len < mlen) {
return -ENOMEM;
}
if (bytes_stored < mlen + sizeof(mlen)) {
/* Part of message not available. Should not happen. */
__ASSERT_NO_MSG(false);
return -EAGAIN;
}
len = MIN(len, mlen);
/* Read up to the end of the buffer. */
uint32_t sz = MIN(len, pblen - rd_idx);
sys_cache_data_range(&pb->data[rd_idx], sz, K_CACHE_INVD);
memcpy(buf, &pb->data[rd_idx], sz);
if (len > sz) {
/* Read remaining bytes starting from the buffer head. */
sys_cache_data_range(&pb->data[0], len - sz, K_CACHE_INVD);
memcpy(&buf[sz], &pb->data[0], len - sz);
}
/* Update read index - make other side aware data was read. */
__sync_synchronize();
rd_idx = idx_cut(pblen, rd_idx + len);
pb->rd_idx = rd_idx;
sys_cache_data_range(pb, sizeof(*pb), K_CACHE_WB);
return len;
}

View file

@ -19,13 +19,13 @@ config IPC_SERVICE_BACKEND_RPMSG
select OPENAMP select OPENAMP
config IPC_SERVICE_BACKEND_ICMSG config IPC_SERVICE_BACKEND_ICMSG
bool "ICMSG backend with ICMsg buffer" bool "ICMSG backend with SPSC packet buffer"
depends on MBOX depends on MBOX
default $(dt_compat_enabled,$(DT_COMPAT_ZEPHYR_IPC_ICMSG)) default $(dt_compat_enabled,$(DT_COMPAT_ZEPHYR_IPC_ICMSG))
select IPC_SERVICE_ICMSG_BUF select SPSC_PBUF
help help
Chosing this backend results in single endpoint implementation based Chosing this backend results in single endpoint implementation based
on ringbuf. on circular packet buffer.
config IPC_SERVICE_RPMSG config IPC_SERVICE_RPMSG
bool "RPMsg support library" bool "RPMsg support library"
@ -44,10 +44,5 @@ config IPC_SERVICE_STATIC_VRINGS_ALIGNMENT
help help
Static VRINGs alignment Static VRINGs alignment
config IPC_SERVICE_ICMSG_BUF
bool "Inter core messaging buffer support library"
help
Inter core messaging buffer library
rsource "Kconfig.icmsg" rsource "Kconfig.icmsg"
rsource "Kconfig.rpmsg" rsource "Kconfig.rpmsg"

View file

@ -22,8 +22,8 @@ BUILD_ASSERT(CB_BUF_SIZE <= UINT16_MAX);
struct backend_data_t { struct backend_data_t {
/* Tx/Rx buffers. */ /* Tx/Rx buffers. */
struct icmsg_buf *tx_ib; struct spsc_pbuf *tx_ib;
struct icmsg_buf *rx_ib; struct spsc_pbuf *rx_ib;
/* Backend ops for an endpoint. */ /* Backend ops for an endpoint. */
const struct ipc_ept_cfg *cfg; const struct ipc_ept_cfg *cfg;
@ -49,7 +49,7 @@ static void mbox_callback_process(struct k_work *item)
uint8_t cb_buffer[CB_BUF_SIZE] __aligned(4); uint8_t cb_buffer[CB_BUF_SIZE] __aligned(4);
atomic_t state = atomic_get(&dev_data->state); atomic_t state = atomic_get(&dev_data->state);
int len = icmsg_buf_read(dev_data->rx_ib, cb_buffer, CB_BUF_SIZE); int len = spsc_pbuf_read(dev_data->rx_ib, cb_buffer, CB_BUF_SIZE);
__ASSERT_NO_MSG(len <= CB_BUF_SIZE); __ASSERT_NO_MSG(len <= CB_BUF_SIZE);
@ -69,7 +69,7 @@ static void mbox_callback_process(struct k_work *item)
/* Reading with NULL buffer to know if there are data in the /* Reading with NULL buffer to know if there are data in the
* buffer to be read. * buffer to be read.
*/ */
len = icmsg_buf_read(dev_data->rx_ib, NULL, 0); len = spsc_pbuf_read(dev_data->rx_ib, NULL, 0);
if (len > 0) { if (len > 0) {
(void)k_work_submit(&dev_data->mbox_work); (void)k_work_submit(&dev_data->mbox_work);
} }
@ -133,7 +133,7 @@ static int register_ept(const struct device *instance, void **token,
return ret; return ret;
} }
ret = icmsg_buf_write(dev_data->tx_ib, magic, sizeof(magic)); ret = spsc_pbuf_write(dev_data->tx_ib, magic, sizeof(magic));
if (ret < sizeof(magic)) { if (ret < sizeof(magic)) {
__ASSERT_NO_MSG(ret == sizeof(magic)); __ASSERT_NO_MSG(ret == sizeof(magic));
return ret; return ret;
@ -144,7 +144,7 @@ static int register_ept(const struct device *instance, void **token,
return ret; return ret;
} }
ret = icmsg_buf_read(dev_data->rx_ib, NULL, 0); ret = spsc_pbuf_read(dev_data->rx_ib, NULL, 0);
if (ret > 0) { if (ret > 0) {
(void)k_work_submit(&dev_data->mbox_work); (void)k_work_submit(&dev_data->mbox_work);
} }
@ -168,7 +168,7 @@ static int send(const struct device *instance, void *token,
return -ENODATA; return -ENODATA;
} }
ret = icmsg_buf_write(dev_data->tx_ib, msg, len); ret = spsc_pbuf_write(dev_data->tx_ib, msg, len);
if (ret < 0) { if (ret < 0) {
return ret; return ret;
} else if (ret < len) { } else if (ret < len) {
@ -190,9 +190,9 @@ static int backend_init(const struct device *instance)
const struct backend_config_t *conf = instance->config; const struct backend_config_t *conf = instance->config;
struct backend_data_t *dev_data = instance->data; struct backend_data_t *dev_data = instance->data;
__ASSERT_NO_MSG(conf->tx_shm_size > sizeof(struct icmsg_buf)); __ASSERT_NO_MSG(conf->tx_shm_size > sizeof(struct spsc_pbuf));
dev_data->tx_ib = icmsg_buf_init((void *)conf->tx_shm_addr, conf->tx_shm_size); dev_data->tx_ib = spsc_pbuf_init((void *)conf->tx_shm_addr, conf->tx_shm_size);
dev_data->rx_ib = (void *)conf->rx_shm_addr; dev_data->rx_ib = (void *)conf->rx_shm_addr;
return 0; return 0;

View file

@ -4,7 +4,7 @@
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
#include <zephyr/ipc/ipc_icmsg_buf.h> #include <zephyr/sys/spsc_pbuf.h>
enum icmsg_state { enum icmsg_state {
ICMSG_STATE_OFF, ICMSG_STATE_OFF,

View file

@ -1,5 +1,4 @@
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
zephyr_sources_ifdef(CONFIG_IPC_SERVICE_ICMSG_BUF ipc_icmsg_buf.c)
zephyr_sources_ifdef(CONFIG_IPC_SERVICE_RPMSG ipc_rpmsg.c) zephyr_sources_ifdef(CONFIG_IPC_SERVICE_RPMSG ipc_rpmsg.c)
zephyr_sources_ifdef(CONFIG_IPC_SERVICE_STATIC_VRINGS ipc_static_vrings.c) zephyr_sources_ifdef(CONFIG_IPC_SERVICE_STATIC_VRINGS ipc_static_vrings.c)

View file

@ -1,171 +0,0 @@
/*
* Copyright (c) 2022 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/zephyr.h>
#include <string.h>
#include <errno.h>
#include <zephyr/cache.h>
#include <zephyr/ipc/ipc_icmsg_buf.h>
/* Helpers */
static uint32_t idx_occupied(uint32_t len, uint32_t a, uint32_t b)
{
/* It is implicitly assumed a and b cannot differ by more then len. */
return (b > a) ? (len - (b - a)) : (a - b);
}
static uint32_t idx_cut(uint32_t len, uint32_t idx)
{
/* It is implicitly assumed a and b cannot differ by more then len. */
return (idx >= len) ? (idx - len) : (idx);
}
struct icmsg_buf *icmsg_buf_init(void *buf, size_t blen)
{
/* blen must be big enough to contain icmsg_buf struct, byte of data
* and message len (2 bytes).
*/
struct icmsg_buf *ib = buf;
__ASSERT_NO_MSG(blen > (sizeof(*ib) + sizeof(uint16_t)));
ib->len = blen - sizeof(*ib);
ib->wr_idx = 0;
ib->rd_idx = 0;
__sync_synchronize();
sys_cache_data_range(ib, sizeof(*ib), K_CACHE_WB);
return ib;
}
int icmsg_buf_write(struct icmsg_buf *ib, const char *buf, uint16_t len)
{
/* The length of buffer is immutable - avoid reloading that may happen
* due to memory bariers.
*/
const uint32_t iblen = ib->len;
/* rx_idx == wr_idx means the buffer is empty.
* Max bytes that can be stored is len - 1.
*/
const uint32_t max_len = iblen - 1;
sys_cache_data_range(ib, sizeof(*ib), K_CACHE_INVD);
__sync_synchronize();
uint32_t wr_idx = ib->wr_idx;
uint32_t rd_idx = ib->rd_idx;
if (len == 0) {
/* Incorrect call. */
return -EINVAL;
}
uint32_t avail = max_len - idx_occupied(iblen, wr_idx, rd_idx);
if ((len + sizeof(len) > avail) ||
(len + sizeof(len) > max_len)) {
/* No free space. */
return -ENOMEM;
}
/* Store info about the message length. */
ib->data[wr_idx] = (uint8_t)len;
sys_cache_data_range(&ib->data[wr_idx], sizeof(ib->data[wr_idx]), K_CACHE_WB);
wr_idx = idx_cut(iblen, wr_idx + sizeof(ib->data[wr_idx]));
ib->data[wr_idx] = (uint8_t)(len >> 8);
sys_cache_data_range(&ib->data[wr_idx], sizeof(ib->data[wr_idx]), K_CACHE_WB);
wr_idx = idx_cut(iblen, wr_idx + sizeof(ib->data[wr_idx]));
/* Write until the end of the buffer. */
uint32_t sz = MIN(len, iblen - wr_idx);
memcpy(&ib->data[wr_idx], buf, sz);
sys_cache_data_range(&ib->data[wr_idx], sz, K_CACHE_WB);
if (len > sz) {
/* Write remaining data at the buffer head. */
memcpy(&ib->data[0], buf + sz, len - sz);
sys_cache_data_range(&ib->data[0], len - sz, K_CACHE_WB);
}
/* Update write index - make other side aware data was written. */
__sync_synchronize();
wr_idx = idx_cut(iblen, wr_idx + len);
ib->wr_idx = wr_idx;
sys_cache_data_range(ib, sizeof(*ib), K_CACHE_WB);
return len;
}
int icmsg_buf_read(struct icmsg_buf *ib, char *buf, uint16_t len)
{
/* The length of buffer is immutable - avoid reloading. */
const uint32_t iblen = ib->len;
sys_cache_data_range(ib, sizeof(*ib), K_CACHE_INVD);
__sync_synchronize();
uint32_t rd_idx = ib->rd_idx;
uint32_t wr_idx = ib->wr_idx;
if (rd_idx == wr_idx) {
/* The buffer is empty. */
return 0;
}
uint32_t bytes_stored = idx_occupied(iblen, wr_idx, rd_idx);
/* Read message len. */
sys_cache_data_range(&ib->data[rd_idx], sizeof(ib->data[rd_idx]), K_CACHE_INVD);
uint16_t mlen = ib->data[rd_idx];
rd_idx = idx_cut(iblen, rd_idx + sizeof(ib->data[rd_idx]));
sys_cache_data_range(&ib->data[rd_idx], sizeof(ib->data[rd_idx]), K_CACHE_INVD);
mlen |= (ib->data[rd_idx] << 8);
rd_idx = idx_cut(iblen, rd_idx + sizeof(ib->data[rd_idx]));
if (!buf) {
return mlen;
}
if (len < mlen) {
return -ENOMEM;
}
if (bytes_stored < mlen + sizeof(mlen)) {
/* Part of message not available. Should not happen. */
__ASSERT_NO_MSG(false);
return -EAGAIN;
}
len = MIN(len, mlen);
/* Read up to the end of the buffer. */
uint32_t sz = MIN(len, iblen - rd_idx);
sys_cache_data_range(&ib->data[rd_idx], sz, K_CACHE_INVD);
memcpy(buf, &ib->data[rd_idx], sz);
if (len > sz) {
/* Read remaining bytes starting from the buffer head. */
sys_cache_data_range(&ib->data[0], len - sz, K_CACHE_INVD);
memcpy(&buf[sz], &ib->data[0], len - sz);
}
/* Update read index - make other side aware data was read. */
__sync_synchronize();
rd_idx = idx_cut(iblen, rd_idx + len);
ib->rd_idx = rd_idx;
sys_cache_data_range(ib, sizeof(*ib), K_CACHE_WB);
return len;
}

View file

@ -2,7 +2,7 @@
cmake_minimum_required(VERSION 3.20.0) cmake_minimum_required(VERSION 3.20.0)
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(icmsg_buf) project(spsc_pbuf)
FILE(GLOB app_sources src/main.c) FILE(GLOB app_sources src/main.c)
target_sources(app PRIVATE ${app_sources}) target_sources(app PRIVATE ${app_sources})

View file

@ -0,0 +1,2 @@
CONFIG_ZTEST=y
CONFIG_SPSC_PBUF=y

View file

@ -5,45 +5,45 @@
*/ */
#include <ztest.h> #include <ztest.h>
#include <zephyr/ipc/ipc_icmsg_buf.h> #include <zephyr/sys/spsc_pbuf.h>
/* The buffer size itself would be 199 bytes. /* The buffer size itself would be 199 bytes.
* 212 - sizeof(struct icmsg_buf) - 1 = 199. * 212 - sizeof(struct spsc_pbuf) - 1 = 199.
* -1 because internal rd/wr_idx is reserved to mean the buffer is empty. * -1 because internal rd/wr_idx is reserved to mean the buffer is empty.
*/ */
static uint8_t memory_area[212] __aligned(4); static uint8_t memory_area[212] __aligned(4);
static void test_icmsg_buf_ut(void) static void test_spsc_pbuf_ut(void)
{ {
static uint8_t rbuf[198]; static uint8_t rbuf[198];
static uint8_t message[20] = {'a'}; static uint8_t message[20] = {'a'};
struct icmsg_buf *ib; struct spsc_pbuf *ib;
int rlen; int rlen;
int wlen; int wlen;
ib = icmsg_buf_init(memory_area, sizeof(memory_area)); ib = spsc_pbuf_init(memory_area, sizeof(memory_area));
zassert_equal_ptr(ib, memory_area, NULL); zassert_equal_ptr(ib, memory_area, NULL);
zassert_equal(ib->len, (sizeof(memory_area) - sizeof(*ib)), NULL); zassert_equal(ib->len, (sizeof(memory_area) - sizeof(*ib)), NULL);
zassert_equal(ib->wr_idx, 0, NULL); zassert_equal(ib->wr_idx, 0, NULL);
zassert_equal(ib->rd_idx, 0, NULL); zassert_equal(ib->rd_idx, 0, NULL);
/* Try to write more than buffer can store. */ /* Try to write more than buffer can store. */
rlen = icmsg_buf_write(ib, rbuf, sizeof(rbuf)); rlen = spsc_pbuf_write(ib, rbuf, sizeof(rbuf));
zassert_equal(rlen, -ENOMEM, NULL); zassert_equal(rlen, -ENOMEM, NULL);
zassert_equal(ib->wr_idx, 0, NULL); zassert_equal(ib->wr_idx, 0, NULL);
zassert_equal(ib->rd_idx, 0, NULL); zassert_equal(ib->rd_idx, 0, NULL);
/* Read empty buffer. */ /* Read empty buffer. */
rlen = icmsg_buf_read(ib, rbuf, sizeof(rbuf)); rlen = spsc_pbuf_read(ib, rbuf, sizeof(rbuf));
zassert_equal(rlen, 0, NULL); zassert_equal(rlen, 0, NULL);
/* Single write and read. */ /* Single write and read. */
wlen = icmsg_buf_write(ib, message, sizeof(message)); wlen = spsc_pbuf_write(ib, message, sizeof(message));
zassert_equal(wlen, sizeof(message), NULL); zassert_equal(wlen, sizeof(message), NULL);
zassert_equal(ib->wr_idx, (sizeof(message) + sizeof(uint16_t)), NULL); zassert_equal(ib->wr_idx, (sizeof(message) + sizeof(uint16_t)), NULL);
zassert_equal(ib->rd_idx, 0, NULL); zassert_equal(ib->rd_idx, 0, NULL);
rlen = icmsg_buf_read(ib, rbuf, sizeof(rbuf)); rlen = spsc_pbuf_read(ib, rbuf, sizeof(rbuf));
zassert_equal(rlen, sizeof(message), NULL); zassert_equal(rlen, sizeof(message), NULL);
zassert_equal(ib->wr_idx, (sizeof(message) + sizeof(uint16_t)), NULL); zassert_equal(ib->wr_idx, (sizeof(message) + sizeof(uint16_t)), NULL);
zassert_equal(ib->rd_idx, (sizeof(message) + sizeof(uint16_t)), NULL); zassert_equal(ib->rd_idx, (sizeof(message) + sizeof(uint16_t)), NULL);
@ -55,32 +55,32 @@ static void test_icmsg_buf_ut(void)
* *
* Reset the buffer first. * Reset the buffer first.
*/ */
ib = icmsg_buf_init(memory_area, sizeof(memory_area)); ib = spsc_pbuf_init(memory_area, sizeof(memory_area));
zassert_equal_ptr(ib, memory_area, NULL); zassert_equal_ptr(ib, memory_area, NULL);
zassert_equal(ib->len, (sizeof(memory_area) - sizeof(*ib)), NULL); zassert_equal(ib->len, (sizeof(memory_area) - sizeof(*ib)), NULL);
zassert_equal(ib->wr_idx, 0, NULL); zassert_equal(ib->wr_idx, 0, NULL);
zassert_equal(ib->rd_idx, 0, NULL); zassert_equal(ib->rd_idx, 0, NULL);
for (size_t i = 0; i < 9; i++) { for (size_t i = 0; i < 9; i++) {
wlen = icmsg_buf_write(ib, message, sizeof(message)); wlen = spsc_pbuf_write(ib, message, sizeof(message));
zassert_equal(wlen, sizeof(message), NULL); zassert_equal(wlen, sizeof(message), NULL);
} }
wlen = icmsg_buf_write(ib, message, sizeof(message)); wlen = spsc_pbuf_write(ib, message, sizeof(message));
zassert_equal(wlen, -ENOMEM, NULL); zassert_equal(wlen, -ENOMEM, NULL);
/* Test reading with buf == NULL, should return len of the next message to read. */ /* Test reading with buf == NULL, should return len of the next message to read. */
rlen = icmsg_buf_read(ib, NULL, 0); rlen = spsc_pbuf_read(ib, NULL, 0);
zassert_equal(rlen, sizeof(message), NULL); zassert_equal(rlen, sizeof(message), NULL);
/* Read with len == 0 and correct buf pointer. */ /* Read with len == 0 and correct buf pointer. */
rlen = icmsg_buf_read(ib, rbuf, 0); rlen = spsc_pbuf_read(ib, rbuf, 0);
zassert_equal(rlen, -ENOMEM, NULL); zassert_equal(rlen, -ENOMEM, NULL);
/* Read whole data from the buffer. */ /* Read whole data from the buffer. */
for (size_t i = 0; i < 9; i++) { for (size_t i = 0; i < 9; i++) {
zassert_equal(ib->rd_idx, i * (sizeof(message) + sizeof(uint16_t)), NULL); zassert_equal(ib->rd_idx, i * (sizeof(message) + sizeof(uint16_t)), NULL);
wlen = icmsg_buf_read(ib, rbuf, sizeof(rbuf)); wlen = spsc_pbuf_read(ib, rbuf, sizeof(rbuf));
zassert_equal(wlen, sizeof(message), NULL); zassert_equal(wlen, sizeof(message), NULL);
} }
@ -88,7 +88,7 @@ static void test_icmsg_buf_ut(void)
zassert_equal(ib->rd_idx, 9 * (sizeof(message) + sizeof(uint16_t)), NULL); zassert_equal(ib->rd_idx, 9 * (sizeof(message) + sizeof(uint16_t)), NULL);
/* Write message that would be wrapped around. */ /* Write message that would be wrapped around. */
wlen = icmsg_buf_write(ib, message, sizeof(message)); wlen = spsc_pbuf_write(ib, message, sizeof(message));
zassert_equal(wlen, sizeof(message), NULL); zassert_equal(wlen, sizeof(message), NULL);
/* Have to store 22 bytes in total. /* Have to store 22 bytes in total.
* 2 Bytes left in tail of the buffer 20 bytes go in front. * 2 Bytes left in tail of the buffer 20 bytes go in front.
@ -96,15 +96,15 @@ static void test_icmsg_buf_ut(void)
zassert_equal(ib->wr_idx, 20, NULL); zassert_equal(ib->wr_idx, 20, NULL);
/* Read wrapped message. */ /* Read wrapped message. */
rlen = icmsg_buf_read(ib, rbuf, sizeof(rbuf)); rlen = spsc_pbuf_read(ib, rbuf, sizeof(rbuf));
zassert_equal(rlen, sizeof(message), NULL); zassert_equal(rlen, sizeof(message), NULL);
zassert_equal(message[0], 'a', NULL); zassert_equal(message[0], 'a', NULL);
} }
void test_main(void) void test_main(void)
{ {
ztest_test_suite(icmsg_buf, ztest_test_suite(spsc_pbuf,
ztest_unit_test(test_icmsg_buf_ut) ztest_unit_test(test_spsc_pbuf_ut)
); );
ztest_run_test_suite(icmsg_buf); ztest_run_test_suite(spsc_pbuf);
} }

View file

@ -0,0 +1,4 @@
tests:
lib.spsc_pbuf:
integration_platforms:
- native_posix

View file

@ -1,4 +0,0 @@
CONFIG_ZTEST=y
CONFIG_IPC_SERVICE=y
CONFIG_IPC_SERVICE_ICMSG_BUF=y

View file

@ -1,5 +0,0 @@
tests:
subsys.ipc.icmsg_buf:
integration_platforms:
- nrf5340dk_nrf5340_cpuapp
platform_exclude: qemu_malta ast1030_evb