Bluetooth: controller: Add support for linked adv PDUs

This adds support to allow advertising PDUs to be linked which is
required to send advertising trains, i.e. AUX_CHAIN_IND.

PDUs are linked with a simple single-linked list, the pointer to next
PDU is stored at the very end of PDU buffer. This prevents it from
being overwritten if PDU is modified and allows for build time offset
calculation.

There are few helpers added to make handling easier, e.g.:
- get next linked PDU
- get last linked PDU
- link one PDU to another
- link PDU at the end
- release all linked PDUs (except for 1st)

Signed-off-by: Andrzej Kaczmarek <andrzej.kaczmarek@codecoup.pl>
This commit is contained in:
Andrzej Kaczmarek 2021-02-24 16:43:58 +01:00 committed by Anas Nashif
commit 21892eecf1
10 changed files with 119 additions and 10 deletions

View file

@ -165,6 +165,13 @@ config BT_CTLR_ADV_SYNC_SET
help help
Maximum supported periodic advertising sets. Maximum supported periodic advertising sets.
config BT_CTLR_ADV_PDU_LINK
bool "Enable linking of advertising PDU trains"
help
Enables extra space in each advertising PDU to allow linking PDUs. This
is required to enable advertising data trains (i.e. transmission of
AUX_CHAIN_IND).
config BT_CTLR_ADV_DATA_BUF_MAX config BT_CTLR_ADV_DATA_BUF_MAX
int "Advertising Data Maximum Buffers" int "Advertising Data Maximum Buffers"
depends on BT_BROADCASTER depends on BT_BROADCASTER

View file

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

View file

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

View file

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

View file

@ -97,8 +97,7 @@ static inline bool isr_rx_ci_adva_check(uint8_t tx_addr, uint8_t *addr,
#define BT_CTLR_ADV_SYNC_SET 0 #define BT_CTLR_ADV_SYNC_SET 0
#endif #endif
#define PDU_MEM_SIZE MROUND(PDU_AC_LL_HEADER_SIZE + \ #define PDU_MEM_SIZE PDU_ADV_MEM_SIZE
PDU_AC_PAYLOAD_SIZE_MAX)
#define PDU_MEM_COUNT_MIN (BT_CTLR_ADV_SET + \ #define PDU_MEM_COUNT_MIN (BT_CTLR_ADV_SET + \
(BT_CTLR_ADV_SET * PAYLOAD_FRAG_COUNT) + \ (BT_CTLR_ADV_SET * PAYLOAD_FRAG_COUNT) + \
(BT_CTLR_ADV_AUX_SET * PAYLOAD_FRAG_COUNT) + \ (BT_CTLR_ADV_AUX_SET * PAYLOAD_FRAG_COUNT) + \
@ -305,11 +304,17 @@ struct pdu_adv *lll_adv_pdu_alloc_pdu_adv(void)
MFIFO_DEQUEUE(pdu_free); MFIFO_DEQUEUE(pdu_free);
#if defined(CONFIG_BT_CTLR_ADV_PDU_LINK)
PDU_ADV_NEXT_PTR(p) = NULL;
#endif
return p; return p;
} }
p = mem_acquire(&mem_pdu.free); p = mem_acquire(&mem_pdu.free);
if (p) { if (p) {
#if defined(CONFIG_BT_CTLR_ADV_PDU_LINK)
PDU_ADV_NEXT_PTR(p) = NULL;
#endif
return p; return p;
} }
@ -319,9 +324,33 @@ struct pdu_adv *lll_adv_pdu_alloc_pdu_adv(void)
p = MFIFO_DEQUEUE(pdu_free); p = MFIFO_DEQUEUE(pdu_free);
LL_ASSERT(p); LL_ASSERT(p);
#if defined(CONFIG_BT_CTLR_ADV_PDU_LINK)
PDU_ADV_NEXT_PTR(p) = NULL;
#endif
return p; return p;
} }
#if defined(CONFIG_BT_CTLR_ADV_PDU_LINK)
void lll_adv_pdu_release(struct pdu_adv *pdu)
{
mem_release(pdu, &mem_pdu.free);
}
void lll_adv_pdu_linked_release_all(struct pdu_adv *pdu_first)
{
struct pdu_adv *pdu = pdu_first;
while (pdu) {
struct pdu_adv *pdu_next;
pdu_next = PDU_ADV_NEXT_PTR(pdu);
PDU_ADV_NEXT_PTR(pdu) = NULL;
lll_adv_pdu_release(pdu);
pdu = pdu_next;
}
}
#endif
struct pdu_adv *lll_adv_pdu_latest_get(struct lll_adv_pdu *pdu, struct pdu_adv *lll_adv_pdu_latest_get(struct lll_adv_pdu *pdu,
uint8_t *is_modified) uint8_t *is_modified)
{ {
@ -333,11 +362,34 @@ struct pdu_adv *lll_adv_pdu_latest_get(struct lll_adv_pdu *pdu,
uint8_t pdu_idx; uint8_t pdu_idx;
void *p; void *p;
pdu_idx = first;
p = pdu->pdu[pdu_idx];
do {
void *next;
/* Store partial list in current data index if there is
* no free slot in mfifo. It can be released on next
* switch attempt (on next event).
*/
if (!MFIFO_ENQUEUE_IDX_GET(pdu_free, &free_idx)) { if (!MFIFO_ENQUEUE_IDX_GET(pdu_free, &free_idx)) {
pdu->pdu[pdu_idx] = p;
return NULL; return NULL;
} }
pdu_idx = first; #if defined(CONFIG_BT_CTLR_ADV_PDU_LINK)
next = lll_adv_pdu_linked_next_get(p);
#else
next = NULL;
#endif
MFIFO_BY_IDX_ENQUEUE(pdu_free, free_idx, p);
k_sem_give(&sem_pdu_free);
p = next;
} while (p);
pdu->pdu[pdu_idx] = NULL;
first += 1U; first += 1U;
if (first == DOUBLE_BUFFER_SIZE) { if (first == DOUBLE_BUFFER_SIZE) {
@ -346,11 +398,7 @@ struct pdu_adv *lll_adv_pdu_latest_get(struct lll_adv_pdu *pdu,
pdu->first = first; pdu->first = first;
*is_modified = 1U; *is_modified = 1U;
p = pdu->pdu[pdu_idx];
pdu->pdu[pdu_idx] = NULL; pdu->pdu[pdu_idx] = NULL;
MFIFO_BY_IDX_ENQUEUE(pdu_free, free_idx, p);
k_sem_give(&sem_pdu_free);
} }
return (void *)pdu->pdu[first]; return (void *)pdu->pdu[first];

View file

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

View file

@ -4,6 +4,18 @@
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
#if defined(CONFIG_BT_CTLR_ADV_PDU_LINK)
#define PDU_ADV_MEM_SIZE MROUND(PDU_AC_LL_HEADER_SIZE + \
PDU_AC_PAYLOAD_SIZE_MAX + \
sizeof(uintptr_t))
#define PDU_ADV_NEXT_PTR(p) *(struct pdu_adv **)((uint8_t *)(p) + \
PDU_ADV_MEM_SIZE - \
sizeof(uintptr_t))
#else
#define PDU_ADV_MEM_SIZE MROUND(PDU_AC_LL_HEADER_SIZE + \
PDU_AC_PAYLOAD_SIZE_MAX)
#endif
int lll_adv_data_init(struct lll_adv_pdu *pdu); int lll_adv_data_init(struct lll_adv_pdu *pdu);
int lll_adv_data_reset(struct lll_adv_pdu *pdu); int lll_adv_data_reset(struct lll_adv_pdu *pdu);
int lll_adv_data_release(struct lll_adv_pdu *pdu); int lll_adv_data_release(struct lll_adv_pdu *pdu);
@ -124,3 +136,38 @@ static inline struct pdu_adv *lll_adv_sync_data_peek(struct lll_adv_sync *lll,
} }
#endif /* CONFIG_BT_CTLR_ADV_PERIODIC */ #endif /* CONFIG_BT_CTLR_ADV_PERIODIC */
#endif /* CONFIG_BT_CTLR_ADV_EXT */ #endif /* CONFIG_BT_CTLR_ADV_EXT */
#if defined(CONFIG_BT_CTLR_ADV_PDU_LINK)
/* Release single PDU, shall only be called from ULL */
void lll_adv_pdu_release(struct pdu_adv *pdu);
/* Release PDU and all linked PDUs, shall only be called from ULL */
void lll_adv_pdu_linked_release_all(struct pdu_adv *pdu_first);
static inline struct pdu_adv *lll_adv_pdu_linked_next_get(struct pdu_adv *pdu)
{
return PDU_ADV_NEXT_PTR(pdu);
}
static inline struct pdu_adv *lll_adv_pdu_linked_last_get(struct pdu_adv *pdu)
{
while (PDU_ADV_NEXT_PTR(pdu)) {
pdu = PDU_ADV_NEXT_PTR(pdu);
}
return pdu;
}
static inline void lll_adv_pdu_linked_append(struct pdu_adv *pdu,
struct pdu_adv *prev)
{
PDU_ADV_NEXT_PTR(prev) = pdu;
}
static inline void lll_adv_pdu_linked_append_end(struct pdu_adv *pdu,
struct pdu_adv *first)
{
struct pdu_adv *last;
last = lll_adv_pdu_linked_last_get(first);
lll_adv_pdu_linked_append(pdu, last);
}
#endif

View file

@ -15,6 +15,7 @@
#include "hal/radio_df.h" #include "hal/radio_df.h"
#include "util/util.h" #include "util/util.h"
#include "util/mem.h"
#include "util/memq.h" #include "util/memq.h"
#include "pdu.h" #include "pdu.h"

View file

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

View file

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