blob: 420eba9aab80694cd7c40dcbf15f59f1693b51bd [file] [log] [blame]
/*
* Copyright (c) 2021 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_INCLUDE_SYS_MPSC_PBUF_H_
#define ZEPHYR_INCLUDE_SYS_MPSC_PBUF_H_
#include <kernel.h>
#include <sys/mpsc_packet.h>
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Multi producer, single consumer packet buffer API
* @defgroup mpsc_buf MPSC (Multi producer, single consumer) packet buffer API
* @ingroup kernel_apis
* @{
*/
/*
* Multi producer, single consumer packet buffer allows to allocate variable
* length consecutive space for storing a packet. When space is allocated
* it can be filled by the user (except for the first 2 bits) and when packet
* is ready it is committed. It is allowed to allocate another packet before
* committing the previous one.
*
* If buffer is full and packet cannot be allocated then null is returned unless
* overwrite mode is selected. In that mode, oldest entry are dropped (user is
* notified) until allocation succeeds. It can happen that candidate for
* dropping is currently being claimed. In that case, it is ommited and next
* packet is dropped and claimed packet is marked as invalid when freeing.
*
* Reading packets is performed in two steps. First packet is claimed. Claiming
* returns pointer to the packet within the buffer. Packet is freed when no
* longer in use.
*/
/**@defgroup MPSC_PBUF_FLAGS MPSC packet buffer flags
* @{
*/
/** @brief Flag indicating that buffer size is power of 2.
*
* When buffer size is power of 2 then optimizations are applied.
*/
#define MPSC_PBUF_SIZE_POW2 BIT(0)
/** @brief Flag indicating buffer full policy.
*
* If flag is set then when allocating from a full buffer oldest packets are
* dropped. When flag is not set then allocation returns null.
*/
#define MPSC_PBUF_MODE_OVERWRITE BIT(1)
/**@} */
/* Forward declaration */
struct mpsc_pbuf_buffer;
/** @brief Callback prototype for getting length of a packet.
*
* @param packet User packet.
*
* @return Size of the packet in 32 bit words.
*/
typedef uint32_t (*mpsc_pbuf_get_wlen)(const union mpsc_pbuf_generic *packet);
/** @brief Callback called when packet is dropped.
*
* @param buffer Packet buffer.
*
* @param packet Packet that is being dropped.
*/
typedef void (*mpsc_pbuf_notify_drop)(const struct mpsc_pbuf_buffer *buffer,
const union mpsc_pbuf_generic *packet);
/** @brief MPSC packet buffer structure. */
struct mpsc_pbuf_buffer {
/** Temporary write index. */
uint32_t tmp_wr_idx;
/** Write index. */
uint32_t wr_idx;
/** Temporary read index. */
uint32_t tmp_rd_idx;
/** Read index. */
uint32_t rd_idx;
/** Flags. */
uint32_t flags;
/** Lock. */
struct k_spinlock lock;
/** User callback called whenever packet is dropped. */
mpsc_pbuf_notify_drop notify_drop;
/** Callback for getting packet length. */
mpsc_pbuf_get_wlen get_wlen;
/* Buffer. */
uint32_t *buf;
/* Buffer size in 32 bit words. */
uint32_t size;
struct k_sem sem;
};
/** @brief MPSC packet buffer configuration. */
struct mpsc_pbuf_buffer_config {
/* Pointer to a memory used for storing packets. */
uint32_t *buf;
/* Buffer size in 32 bit words. */
uint32_t size;
/* Callbacks. */
mpsc_pbuf_notify_drop notify_drop;
mpsc_pbuf_get_wlen get_wlen;
/* Configuration flags. */
uint32_t flags;
};
/** @brief Initnialize a packet buffer.
*
* @param buffer Buffer.
*
* @param config Configuration.
*/
void mpsc_pbuf_init(struct mpsc_pbuf_buffer *buffer,
const struct mpsc_pbuf_buffer_config *config);
/** @brief Allocate a packet.
*
* If a buffer is configured to overwrite mode then if there is no space to
* allocated a new buffer, oldest packets are dropped. Otherwise allocation
* fails and null pointer is returned.
*
* @param buffer Buffer.
*
* @param wlen Number of words to allocate.
*
* @param timeout Timeout. If called from thread context it will pend for given
* timeout if packet cannot be allocated before dropping the oldest or
* returning null.
*
* @return Pointer to the allocated space or null if it cannot be allocated.
*/
union mpsc_pbuf_generic *mpsc_pbuf_alloc(struct mpsc_pbuf_buffer *buffer,
size_t wlen, k_timeout_t timeout);
/** @brief Commit a packet.
*
* @param buffer Buffer.
*
* @param packet Pointer to a packet allocated by @ref mpsc_pbuf_alloc.
*/
void mpsc_pbuf_commit(struct mpsc_pbuf_buffer *buffer,
union mpsc_pbuf_generic *packet);
/** @brief Put single word packet into a buffer.
*
* Function is optimized for storing a packet which fit into a single word.
* Note that 2 bits of that word is used by the buffer.
*
* @param buffer Buffer.
*
* @param word Packet content consisting of MPSC_PBUF_HDR with valid bit set
* and data on remaining bits.
*/
void mpsc_pbuf_put_word(struct mpsc_pbuf_buffer *buffer,
const union mpsc_pbuf_generic word);
/** @brief Put a packet consisting of a word and a pointer.
* *
* Function is optimized for storing packet consisting of a word and a pointer.
* Note that 2 bits of a first word is used by the buffer.
*
* @param buffer Buffer.
*
* @param word First word of a packet consisting of MPSC_PBUF_HDR with valid
* bit set and data on remaining bits.
*
* @param data User data.
*/
void mpsc_pbuf_put_word_ext(struct mpsc_pbuf_buffer *buffer,
const union mpsc_pbuf_generic word,
const void *data);
/** @brief Put a packet into a buffer.
*
* Copy data into a buffer.
* Note that 2 bits of a first word is used by the buffer.
*
* @param buffer Buffer.
*
* @param data First word of data must contain MPSC_PBUF_HDR with valid bit set.
*
* @param wlen Packet size in words.
*/
void mpsc_pbuf_put_data(struct mpsc_pbuf_buffer *buffer,
const uint32_t *data, size_t wlen);
/** @brief Claim the first pending packet.
*
* @param buffer Buffer.
*
* @return Pointer to the claimed packet or null if none available.
*/
const union mpsc_pbuf_generic *mpsc_pbuf_claim(struct mpsc_pbuf_buffer *buffer);
/** @brief Free a packet.
*
* @param buffer Buffer.
*
* @param packet Packet.
*/
void mpsc_pbuf_free(struct mpsc_pbuf_buffer *buffer,
union mpsc_pbuf_generic *packet);
/** @brief Check if there are any message pending.
*
* @param buffer Buffer.
*
* @retval true if pending.
* @retval false if no message is pending.
*/
bool mpsc_pbuf_is_pending(struct mpsc_pbuf_buffer *buffer);
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* ZEPHYR_INCLUDE_SYS_MPSC_PBUF_H_ */