zephyr/subsys/bluetooth/controller/util/dbuf.c

84 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];
}