Bluetooth: Controller: util: Add generic double buffer implementation

There are multiple places where double buffer is used in controlers
code. This commit adds generic implementation of the double buffer.
It can be used in future in all places where the data structure is
in use.

Signed-off-by: Piotr Pryga <piotr.pryga@nordicsemi.no>
This commit is contained in:
Piotr Pryga 2021-10-30 23:40:52 +02:00 committed by Christopher Friedt
commit f23fa86449
30 changed files with 219 additions and 0 deletions

View file

@ -5,6 +5,7 @@ zephyr_library_sources(
util/mem.c
util/memq.c
util/mayfly.c
util/dbuf.c
util/util.c
ticker/ticker.c
ll_sw/ll_addr.c

View file

@ -27,6 +27,7 @@
#include "util/util.h"
#include "util/memq.h"
#include "util/mem.h"
#include "util/dbuf.h"
#include "hal/ecb.h"
#include "hal/ccm.h"

View file

@ -35,6 +35,7 @@
#include "util/util.h"
#include "util/memq.h"
#include "util/dbuf.h"
#include "hal/ccm.h"

View file

@ -9,6 +9,7 @@
#include "util/util.h"
#include "util/memq.h"
#include "util/dbuf.h"
#include "hal/ccm.h"

View file

@ -17,6 +17,7 @@
#include "util/util.h"
#include "util/memq.h"
#include "util/mem.h"
#include "util/dbuf.h"
#include "pdu.h"

View file

@ -21,6 +21,7 @@
#include "util/mem.h"
#include "util/memq.h"
#include "util/mfifo.h"
#include "util/dbuf.h"
#include "ticker/ticker.h"

View file

@ -19,6 +19,7 @@
#include "util/util.h"
#include "util/mem.h"
#include "util/memq.h"
#include "util/dbuf.h"
#include "pdu.h"

View file

@ -19,6 +19,7 @@
#include "util/util.h"
#include "util/mem.h"
#include "util/memq.h"
#include "util/dbuf.h"
#include "pdu.h"

View file

@ -19,6 +19,7 @@
#include "util/util.h"
#include "util/memq.h"
#include "util/dbuf.h"
#include "pdu.h"

View file

@ -11,6 +11,7 @@
#include "util/util.h"
#include "util/memq.h"
#include "util/mem.h"
#include "util/dbuf.h"
#include "hal/cpu.h"
#include "hal/radio_df.h"

View file

@ -17,6 +17,8 @@
#include "util/util.h"
#include "util/memq.h"
#include "util/dbuf.h"
#include "util/util.h"
#include "pdu.h"

View file

@ -20,6 +20,7 @@
#include "util/util.h"
#include "util/memq.h"
#include "util/dbuf.h"
#include "util/mayfly.h"
#include "ticker/ticker.h"

View file

@ -18,6 +18,7 @@
#include "util/util.h"
#include "util/memq.h"
#include "util/dbuf.h"
#include "util/mayfly.h"
#include "pdu.h"

View file

@ -16,6 +16,7 @@
#include "util/util.h"
#include "util/memq.h"
#include "util/dbuf.h"
#include "pdu.h"

View file

@ -24,6 +24,7 @@
#include "util/mfifo.h"
#include "util/memq.h"
#include "util/mayfly.h"
#include "util/dbuf.h"
#include "ticker/ticker.h"

View file

@ -22,6 +22,7 @@
#include "util/mem.h"
#include "util/memq.h"
#include "util/mayfly.h"
#include "util/dbuf.h"
#include "ticker/ticker.h"

View file

@ -17,6 +17,7 @@
#include "util/mem.h"
#include "util/memq.h"
#include "util/mayfly.h"
#include "util/dbuf.h"
#include "ticker/ticker.h"

View file

@ -17,6 +17,7 @@
#include "util/mem.h"
#include "util/memq.h"
#include "util/mayfly.h"
#include "util/dbuf.h"
#include "ticker/ticker.h"

View file

@ -13,6 +13,7 @@
#include "util/memq.h"
#include "util/mem.h"
#include "util/mayfly.h"
#include "util/dbuf.h"
#include "hal/cpu.h"
#include "hal/ccm.h"

View file

@ -14,6 +14,7 @@
#include "util/util.h"
#include "util/memq.h"
#include "util/mem.h"
#include "util/dbuf.h"
#include "hal/ccm.h"

View file

@ -21,6 +21,7 @@
#include "util/memq.h"
#include "util/mfifo.h"
#include "util/mayfly.h"
#include "util/dbuf.h"
#include "ticker/ticker.h"

View file

@ -17,6 +17,7 @@
#include "util/mem.h"
#include "util/memq.h"
#include "util/mfifo.h"
#include "util/dbuff.h"
#include "pdu.h"

View file

@ -18,6 +18,7 @@
#include "util/mem.h"
#include "util/memq.h"
#include "util/mayfly.h"
#include "util/dbuf.h"
#include "pdu.h"

View file

@ -13,6 +13,7 @@
#include "util/memq.h"
#include "util/mem.h"
#include "util/mayfly.h"
#include "util/dbuf.h"
#include "hal/cpu.h"
#include "hal/ccm.h"

View file

@ -18,6 +18,7 @@
#include "util/mem.h"
#include "util/memq.h"
#include "util/mayfly.h"
#include "util/dbuf.h"
#include "ticker/ticker.h"

View file

@ -11,6 +11,7 @@
#include "util/memq.h"
#include "util/mayfly.h"
#include "util/util.h"
#include "util/dbuf.h"
#include "hal/ticker.h"
#include "hal/ccm.h"

View file

@ -15,6 +15,7 @@
#include "util/util.h"
#include "util/memq.h"
#include "util/mayfly.h"
#include "util/dbuf.h"
#include "ticker/ticker.h"

View file

@ -13,6 +13,7 @@
#include "util/mem.h"
#include "util/memq.h"
#include "util/mayfly.h"
#include "util/dbuf.h"
#include "hal/cpu.h"
#include "hal/ccm.h"

View file

@ -0,0 +1,83 @@
/*
* Copyright (c) 2021 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include <stdbool.h>
#include <soc.h>
#include "hal/cpu.h"
#include "util/util.h"
#include "dbuf.h"
void *dbuf_alloc(struct dbuf_hdr *hdr, uint8_t *idx)
{
uint8_t first, last;
first = hdr->first;
last = hdr->last;
if (first == last) {
/* Return the index of next free PDU in the double buffer */
last++;
if (last == DOUBLE_BUFFER_SIZE) {
last = 0U;
}
} else {
uint8_t first_latest;
/* LLL has not consumed the first PDU. Revert back the `last` so
* that LLL still consumes the first PDU while the caller of
* this function updates/modifies the latest PDU.
*
* Under race condition:
* 1. LLL runs before `pdu->last` is reverted, then `pdu->first`
* has changed, hence restore `pdu->last` and return index of
* next free PDU in the double buffer.
* 2. LLL runs after `pdu->last` is reverted, then `pdu->first`
* will not change, return the saved `last` as the index of
* the next free PDU in the double buffer.
*/
hdr->last = first;
cpu_dmb();
first_latest = hdr->first;
if (first_latest != first) {
hdr->last = last;
last++;
if (last == DOUBLE_BUFFER_SIZE) {
last = 0U;
}
}
}
*idx = last;
return &hdr->data[last * hdr->elem_size];
}
void *dbuf_latest_get(struct dbuf_hdr *hdr, uint8_t *is_modified)
{
uint8_t first;
first = hdr->first;
if (first != hdr->last) {
uint8_t cfg_idx;
cfg_idx = first;
first += 1U;
if (first == DOUBLE_BUFFER_SIZE) {
first = 0U;
}
hdr->first = first;
if (is_modified) {
*is_modified = 1U;
}
}
return &hdr->data[first * hdr->elem_size];
}

View file

@ -0,0 +1,107 @@
/*
* Copyright (c) 2021 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @brief Generic double buffer data structure header.
*
* The structure may be used as a header for any kind of data structure that requires
* double buffering.
*/
struct dbuf_hdr {
/* The current element that is in use. */
uint8_t volatile first;
/* Last enqueued element. It will be used after buffer is swapped. */
uint8_t last;
/* Size in a bytes of a single element stored in double buffer. */
uint8_t elem_size;
/* Pointer for actual buffer memory. Its size should be 2 times @p elem_size. */
uint8_t data[0];
};
/**
* @brief Allocate element in double buffer.
*
* The function provides pointer to new element that may be modified by the user.
* For consecutive calls it always returns the same pointer until buffer is swapped
* by dbuf_latest_get operation.
*
* @param hdr Pointer to double buffer header.
* @param idx Pointer to return new element index.
*
* @return Pointer to new element memory.
*/
void *dbuf_alloc(struct dbuf_hdr *hdr, uint8_t *idx);
/**
* @brief Provides pointer to last allocated element.
*
* If it is called before dbuf_alloc it will return pointer to memory that was recently
* enqueued.
*
* @param hdr Pointer to double buffer header.
*
* @return Pointer to last allocated element.
*/
static inline void *dbuf_peek(struct dbuf_hdr *hdr)
{
return &hdr->data[hdr->last * hdr->elem_size];
}
/**
* @brief Enqueue new element for buffer swap.
*
* @param hdr Pointer to double buffer header.
* @param idx Intex of element to be swapped.
*/
static inline void dbuf_enqueue(struct dbuf_hdr *hdr, uint8_t idx)
{
hdr->last = idx;
}
/**
* @brief Get latest element in buffer.
*
* Latest enqueued element is pointed by last member of dbuf_hdr.
* If it points to a different index than member first, then buffer will be
* swapped and @p is_modified will be set to true.
*
* Pointer to lates element is returned.
*
* @param[in] hdr Pointer to double buffer header.
* @param[out] is_modifled Pointer to return information if buffer was swapped.
*
* @return Pointer to latest enqueued buffer element.
*/
void *dbuf_latest_get(struct dbuf_hdr *hdr, uint8_t *is_modified);
/**
* @brief Retruns pointer to the current element, the one after last swap operation.
*
* The function provides access to element that is pointed by member first of dbuf_hrd.
* Returned value always points to latest one, that was swapped after most recent call to
* dbuf_latest_get. The pointer will be the same as the one pointed by last if the dbuf_alloc
* is not called after last dbuf_latest_get call.
*
* @param hdr Pointer to double buffer header.
* @return Pointer to element after last buffer swap.
*/
static inline void *dbuf_curr_get(struct dbuf_hdr *hdr)
{
return &hdr->data[hdr->first * hdr->elem_size];
}
/**
* @brief Return information whether new element was enqueued to a buffer.
*
* @param hdr Pointer to double buffer header.
*
* @return True if there were new element enqueued, false in other case.
*/
static inline bool dbuf_is_modified(const struct dbuf_hdr *hdr)
{
return hdr->first != hdr->last;
}