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>
83 lines
1.7 KiB
C
83 lines
1.7 KiB
C
/*
|
|
* 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];
|
|
}
|