1 /*
2  * Copyright (c) 2021 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <stdint.h>
8 #include <stdbool.h>
9 
10 #include <soc.h>
11 
12 #include "hal/cpu.h"
13 
14 #include "util/util.h"
15 #include "dbuf.h"
16 
dbuf_alloc(struct dbuf_hdr * hdr,uint8_t * idx)17 void *dbuf_alloc(struct dbuf_hdr *hdr, uint8_t *idx)
18 {
19 	uint8_t first, last;
20 
21 	first = hdr->first;
22 	last = hdr->last;
23 	if (first == last) {
24 		/* Return the index of next free PDU in the double buffer */
25 		last++;
26 		if (last == DOUBLE_BUFFER_SIZE) {
27 			last = 0U;
28 		}
29 	} else {
30 		uint8_t first_latest;
31 
32 		/* LLL has not consumed the first PDU. Revert back the `last` so
33 		 * that LLL still consumes the first PDU while the caller of
34 		 * this function updates/modifies the latest PDU.
35 		 *
36 		 * Under race condition:
37 		 * 1. LLL runs before `pdu->last` is reverted, then `pdu->first`
38 		 *    has changed, hence restore `pdu->last` and return index of
39 		 *    next free PDU in the double buffer.
40 		 * 2. LLL runs after `pdu->last` is reverted, then `pdu->first`
41 		 *    will not change, return the saved `last` as the index of
42 		 *    the next free PDU in the double buffer.
43 		 */
44 		hdr->last = first;
45 		cpu_dmb();
46 		first_latest = hdr->first;
47 		if (first_latest != first) {
48 			hdr->last = last;
49 			last++;
50 			if (last == DOUBLE_BUFFER_SIZE) {
51 				last = 0U;
52 			}
53 		}
54 	}
55 
56 	*idx = last;
57 
58 	return &hdr->data[last * hdr->elem_size];
59 }
60 
dbuf_latest_get(struct dbuf_hdr * hdr,uint8_t * is_modified)61 void *dbuf_latest_get(struct dbuf_hdr *hdr, uint8_t *is_modified)
62 {
63 	uint8_t first;
64 
65 	first = hdr->first;
66 	if (first != hdr->last) {
67 		uint8_t cfg_idx;
68 
69 		cfg_idx = first;
70 
71 		first += 1U;
72 		if (first == DOUBLE_BUFFER_SIZE) {
73 			first = 0U;
74 		}
75 		hdr->first = first;
76 
77 		if (is_modified) {
78 			*is_modified = 1U;
79 		}
80 	}
81 
82 	return &hdr->data[first * hdr->elem_size];
83 }
84