Bluetooth: controller: Implement ADV re-schedule for new scheduler

The new JIT scheduler does not have slot reservation, which means that
the ticker extension feature for automatically re-scheduling a colliding
non-anchored event, e.g. ADV, cannot be used.

This implementaion reacts to ADV envent done with result ABORTED or
TOO_LATE, and in those cases attempts to re-schedule the ADV event again
within the 10 ms pertubation window.

As the original scheduling, the re-scheduling is randomized, so there
is no absolute predictability as to how many attempts will be made. The
advertiser will attempt with randomly delayed re-schdules until the
window is exhausted.

If re-scheduling is unsuccessful, the weight of the ADV event is
increased, improving it's chances of success in the next event.

Signed-off-by: Morten Priess <mtpr@oticon.com>
This commit is contained in:
Morten Priess 2021-05-25 14:52:44 +02:00 committed by Christopher Friedt
commit fdc92ebb27
8 changed files with 159 additions and 35 deletions

View file

@ -134,6 +134,12 @@ enum {
#define TICKER_ID_ULL_BASE ((TICKER_ID_LLL_PREEMPT) + 1) #define TICKER_ID_ULL_BASE ((TICKER_ID_LLL_PREEMPT) + 1)
enum done_result {
DONE_COMPLETED,
DONE_ABORTED,
DONE_LATE
};
struct ull_hdr { struct ull_hdr {
uint8_t volatile ref; /* Number of ongoing (between Prepare and Done) uint8_t volatile ref; /* Number of ongoing (between Prepare and Done)
* events * events
@ -331,11 +337,11 @@ enum {
EVENT_DONE_EXTRA_TYPE_CONN, EVENT_DONE_EXTRA_TYPE_CONN,
#endif /* CONFIG_BT_CONN */ #endif /* CONFIG_BT_CONN */
#if defined(CONFIG_BT_CTLR_ADV_EXT) #if defined(CONFIG_BT_CTLR_ADV_EXT) || defined(CONFIG_BT_CTLR_JIT_SCHEDULING)
#if defined(CONFIG_BT_BROADCASTER) #if defined(CONFIG_BT_BROADCASTER)
EVENT_DONE_EXTRA_TYPE_ADV, EVENT_DONE_EXTRA_TYPE_ADV,
#endif /* CONFIG_BT_BROADCASTER */ #endif /* CONFIG_BT_BROADCASTER */
#endif /* CONFIG_BT_CTLR_ADV_EXT */ #endif /* CONFIG_BT_CTLR_ADV_EXT || CONFIG_BT_CTLR_JIT_SCHEDULING */
#if defined(CONFIG_BT_OBSERVER) #if defined(CONFIG_BT_OBSERVER)
#if defined(CONFIG_BT_CTLR_ADV_EXT) #if defined(CONFIG_BT_CTLR_ADV_EXT)
@ -368,6 +374,9 @@ struct event_done_extra_drift {
struct event_done_extra { struct event_done_extra {
uint8_t type; uint8_t type;
#if defined(CONFIG_BT_CTLR_JIT_SCHEDULING)
uint8_t result;
#endif /* CONFIG_BT_CTLR_JIT_SCHEDULING */
union { union {
struct { struct {
uint16_t trx_cnt; uint16_t trx_cnt;
@ -402,7 +411,7 @@ static inline void lll_hdr_init(void *lll, void *parent)
#endif /* CONFIG_BT_CTLR_JIT_SCHEDULING */ #endif /* CONFIG_BT_CTLR_JIT_SCHEDULING */
} }
void lll_done_score(void *param, uint8_t too_late, uint8_t aborted); void lll_done_score(void *param, uint8_t result);
int lll_init(void); int lll_init(void);
int lll_reset(void); int lll_reset(void);

View file

@ -80,7 +80,7 @@ void lll_resume(void *param)
} }
#if defined(CONFIG_BT_CTLR_JIT_SCHEDULING) #if defined(CONFIG_BT_CTLR_JIT_SCHEDULING)
void lll_done_score(void *param, uint8_t too_late, uint8_t aborted) void lll_done_score(void *param, uint8_t result)
{ {
struct lll_hdr *hdr = param; struct lll_hdr *hdr = param;
@ -88,7 +88,7 @@ void lll_done_score(void *param, uint8_t too_late, uint8_t aborted)
return; return;
} }
if (!too_late && !aborted) { if (result == DONE_COMPLETED) {
hdr->score = 0; hdr->score = 0;
hdr->latency = 0; hdr->latency = 0;
} else { } else {

View file

@ -344,7 +344,19 @@ int lll_done(void *param)
#endif /* !CONFIG_BT_CTLR_LOW_LAT_ULL_DONE */ #endif /* !CONFIG_BT_CTLR_LOW_LAT_ULL_DONE */
#if defined(CONFIG_BT_CTLR_JIT_SCHEDULING) #if defined(CONFIG_BT_CTLR_JIT_SCHEDULING)
lll_done_score(param, 0, 0); /* TODO */ struct event_done_extra *extra;
uint8_t result;
/* TODO: Pass from calling function */
result = DONE_COMPLETED;
lll_done_score(param, result);
extra = ull_event_done_extra_get();
LL_ASSERT(extra);
/* Set result in done extra data - type was set by the role */
extra->result = result;
#endif /* CONFIG_BT_CTLR_JIT_SCHEDULING */ #endif /* CONFIG_BT_CTLR_JIT_SCHEDULING */
/* Let ULL know about LLL event done */ /* Let ULL know about LLL event done */

View file

@ -45,6 +45,8 @@
#include "lll_prof_internal.h" #include "lll_prof_internal.h"
#include "lll_df_internal.h" #include "lll_df_internal.h"
#include "ull_internal.h"
#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_HCI_DRIVER) #define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_HCI_DRIVER)
#define LOG_MODULE_NAME bt_ctlr_lll_adv #define LOG_MODULE_NAME bt_ctlr_lll_adv
#include "common/log.h" #include "common/log.h"
@ -1209,14 +1211,9 @@ static void isr_done(void *param)
} }
#endif /* CONFIG_BT_CTLR_ADV_INDICATION */ #endif /* CONFIG_BT_CTLR_ADV_INDICATION */
#if defined(CONFIG_BT_CTLR_ADV_EXT) #if defined(CONFIG_BT_CTLR_ADV_EXT) || defined(CONFIG_BT_CTLR_JIT_SCHEDULING)
struct event_done_extra *extra; ull_done_extra_type_set(EVENT_DONE_EXTRA_TYPE_ADV);
#endif /* CONFIG_BT_CTLR_ADV_EXT || CONFIG_BT_CTLR_JIT_SCHEDULING */
extra = ull_event_done_extra_get();
LL_ASSERT(extra);
extra->type = EVENT_DONE_EXTRA_TYPE_ADV;
#endif /* CONFIG_BT_CTLR_ADV_EXT */
lll_isr_cleanup(param); lll_isr_cleanup(param);
} }

View file

@ -2484,13 +2484,16 @@ static inline void rx_demux_event_done(memq_link_t *link,
break; break;
#endif /* CONFIG_BT_CONN */ #endif /* CONFIG_BT_CONN */
#if defined(CONFIG_BT_CTLR_ADV_EXT)
#if defined(CONFIG_BT_BROADCASTER) #if defined(CONFIG_BT_BROADCASTER)
#if defined(CONFIG_BT_CTLR_ADV_EXT) || \
defined(CONFIG_BT_CTLR_JIT_SCHEDULING)
case EVENT_DONE_EXTRA_TYPE_ADV: case EVENT_DONE_EXTRA_TYPE_ADV:
ull_adv_done(done); ull_adv_done(done);
break; break;
#endif /* CONFIG_BT_CTLR_ADV_EXT || CONFIG_BT_CTLR_JIT_SCHEDULING */
#endif /* CONFIG_BT_BROADCASTER */ #endif /* CONFIG_BT_BROADCASTER */
#if defined(CONFIG_BT_CTLR_ADV_EXT)
#if defined(CONFIG_BT_OBSERVER) #if defined(CONFIG_BT_OBSERVER)
case EVENT_DONE_EXTRA_TYPE_SCAN: case EVENT_DONE_EXTRA_TYPE_SCAN:
ull_scan_done(done); ull_scan_done(done);
@ -2553,3 +2556,15 @@ static void disabled_cb(void *param)
{ {
k_sem_give(param); k_sem_give(param);
} }
struct event_done_extra *ull_done_extra_type_set(uint8_t type)
{
struct event_done_extra *extra;
extra = ull_event_done_extra_get();
LL_ASSERT(extra);
extra->type = type;
return extra;
}

View file

@ -16,6 +16,7 @@
#include "hal/ccm.h" #include "hal/ccm.h"
#include "hal/radio.h" #include "hal/radio.h"
#include "hal/ticker.h" #include "hal/ticker.h"
#include "hal/cntr.h"
#include "util/util.h" #include "util/util.h"
#include "util/mem.h" #include "util/mem.h"
@ -1732,20 +1733,109 @@ uint8_t ull_scan_rsp_set(struct ll_adv_set *adv, uint8_t len,
return 0; return 0;
} }
#if defined(CONFIG_BT_CTLR_ADV_EXT) static uint32_t ticker_update_rand(struct ll_adv_set *adv, uint32_t ticks_delay_window,
uint32_t ticks_delay_window_offset,
uint32_t ticks_adjust_minus)
{
uint32_t random_delay;
uint32_t ret;
/* Get pseudo-random number in the range [0..ticks_delay_window].
* Please note that using modulo of 2^32 samle space has an uneven
* distribution, slightly favoring smaller values.
*/
lll_rand_isr_get(&random_delay, sizeof(random_delay));
random_delay %= ticks_delay_window;
random_delay += (ticks_delay_window_offset + 1);
ret = ticker_update(TICKER_INSTANCE_ID_CTLR,
TICKER_USER_ID_ULL_HIGH,
TICKER_ID_ADV_BASE + ull_adv_handle_get(adv),
random_delay,
ticks_adjust_minus, 0, 0, 0, 0,
ticker_op_update_cb, adv);
LL_ASSERT((ret == TICKER_STATUS_SUCCESS) ||
(ret == TICKER_STATUS_BUSY));
#if defined(CONFIG_BT_CTLR_JIT_SCHEDULING)
adv->delay = random_delay;
#endif
return random_delay;
}
#if defined(CONFIG_BT_CTLR_ADV_EXT) || \
defined(CONFIG_BT_CTLR_JIT_SCHEDULING)
void ull_adv_done(struct node_rx_event_done *done) void ull_adv_done(struct node_rx_event_done *done)
{ {
#if defined(CONFIG_BT_CTLR_ADV_EXT)
struct lll_adv_aux *lll_aux; struct lll_adv_aux *lll_aux;
struct node_rx_hdr *rx_hdr; struct node_rx_hdr *rx_hdr;
struct ll_adv_set *adv;
struct lll_adv *lll;
uint8_t handle; uint8_t handle;
uint32_t ret; uint32_t ret;
#endif /* CONFIG_BT_CTLR_ADV_EXT */
struct ll_adv_set *adv;
struct lll_adv *lll;
/* Get reference to ULL context */ /* Get reference to ULL context */
adv = CONTAINER_OF(done->param, struct ll_adv_set, ull); adv = CONTAINER_OF(done->param, struct ll_adv_set, ull);
lll = &adv->lll; lll = &adv->lll;
#if defined(CONFIG_BT_CTLR_JIT_SCHEDULING)
if (done->extra.result == DONE_COMPLETED) {
/* Event completed successfully */
adv->delay_remain = ULL_ADV_RANDOM_DELAY;
} else {
/* Event aborted or too late - try to re-schedule */
uint32_t ticks_elapsed;
uint32_t ticks_now;
const uint32_t prepare_overhead =
HAL_TICKER_US_TO_TICKS(EVENT_OVERHEAD_START_US);
const uint32_t ticks_adv_airtime = adv->ticks_at_expire +
prepare_overhead;
ticks_elapsed = 0;
ticks_now = cntr_cnt_get();
if ((int32_t)(ticks_now - ticks_adv_airtime) > 0) {
ticks_elapsed = ticks_now - ticks_adv_airtime;
}
if (adv->delay_remain >= adv->delay + ticks_elapsed) {
/* The perturbation window is still open */
adv->delay_remain -= (adv->delay + ticks_elapsed);
} else {
adv->delay_remain = 0;
}
/* Check if we have enough time to re-schedule */
if (adv->delay_remain > prepare_overhead) {
uint32_t ticks_adjust_minus;
/* Get negative ticker adjustment needed to pull back ADV one
* interval plus the randomized delay. This means that the ticker
* will be updated to expire in time frame of now + start
* overhead, until 10 ms window is exhausted.
*/
ticks_adjust_minus = HAL_TICKER_US_TO_TICKS(
(uint64_t)adv->interval * ADV_INT_UNIT_US) + adv->delay;
/* Apply random delay in range [prepare_overhead..delay_remain] */
ticker_update_rand(adv, adv->delay_remain - prepare_overhead,
prepare_overhead, ticks_adjust_minus);
/* Score of the event was increased due to the result, but since
* we're getting a another chance we'll set it back.
*/
adv->lll.hdr.score -= 1;
} else {
adv->delay_remain = ULL_ADV_RANDOM_DELAY;
}
}
#endif /* CONFIG_BT_CTLR_JIT_SCHEDULING */
#if defined(CONFIG_BT_CTLR_ADV_EXT)
if (adv->max_events && (adv->event_counter >= adv->max_events)) { if (adv->max_events && (adv->event_counter >= adv->max_events)) {
adv->max_events = 0; adv->max_events = 0;
@ -1791,8 +1881,9 @@ void ull_adv_done(struct node_rx_event_done *done)
LL_ASSERT((ret == TICKER_STATUS_SUCCESS) || LL_ASSERT((ret == TICKER_STATUS_SUCCESS) ||
(ret == TICKER_STATUS_BUSY)); (ret == TICKER_STATUS_BUSY));
}
#endif /* CONFIG_BT_CTLR_ADV_EXT */ #endif /* CONFIG_BT_CTLR_ADV_EXT */
}
#endif /* CONFIG_BT_CTLR_ADV_EXT || CONFIG_BT_CTLR_JIT_SCHEDULING */
const uint8_t *ull_adv_pdu_update_addrs(struct ll_adv_set *adv, const uint8_t *ull_adv_pdu_update_addrs(struct ll_adv_set *adv,
struct pdu_adv *pdu) struct pdu_adv *pdu)
@ -1971,6 +2062,7 @@ static void ticker_cb(uint32_t ticks_at_expire, uint32_t remainder, uint16_t laz
static struct mayfly mfy = {0, 0, &link, NULL, lll_adv_prepare}; static struct mayfly mfy = {0, 0, &link, NULL, lll_adv_prepare};
static struct lll_prepare_param p; static struct lll_prepare_param p;
struct ll_adv_set *adv = param; struct ll_adv_set *adv = param;
uint32_t random_delay;
struct lll_adv *lll; struct lll_adv *lll;
uint32_t ret; uint32_t ret;
uint8_t ref; uint8_t ref;
@ -1997,6 +2089,10 @@ static void ticker_cb(uint32_t ticks_at_expire, uint32_t remainder, uint16_t laz
ret = mayfly_enqueue(TICKER_USER_ID_ULL_HIGH, ret = mayfly_enqueue(TICKER_USER_ID_ULL_HIGH,
TICKER_USER_ID_LLL, 0, &mfy); TICKER_USER_ID_LLL, 0, &mfy);
LL_ASSERT(!ret); LL_ASSERT(!ret);
#if defined(CONFIG_BT_CTLR_JIT_SCHEDULING)
adv->ticks_at_expire = ticks_at_expire;
#endif /* CONFIG_BT_CTLR_JIT_SCHEDULING */
} }
/* Apply adv random delay */ /* Apply adv random delay */
@ -2004,22 +2100,8 @@ static void ticker_cb(uint32_t ticks_at_expire, uint32_t remainder, uint16_t laz
if (!lll->is_hdcd) if (!lll->is_hdcd)
#endif /* CONFIG_BT_PERIPHERAL */ #endif /* CONFIG_BT_PERIPHERAL */
{ {
uint32_t random_delay; /* Apply random delay in range [0..ULL_ADV_RANDOM_DELAY] */
uint32_t ret; random_delay = ticker_update_rand(adv, ULL_ADV_RANDOM_DELAY, 0, 0);
lll_rand_isr_get(&random_delay, sizeof(random_delay));
random_delay %= ULL_ADV_RANDOM_DELAY;
random_delay += 1;
ret = ticker_update(TICKER_INSTANCE_ID_CTLR,
TICKER_USER_ID_ULL_HIGH,
(TICKER_ID_ADV_BASE +
ull_adv_handle_get(adv)),
random_delay,
0, 0, 0, 0, 0,
ticker_op_update_cb, adv);
LL_ASSERT((ret == TICKER_STATUS_SUCCESS) ||
(ret == TICKER_STATUS_BUSY));
#if defined(CONFIG_BT_CTLR_ADV_EXT) #if defined(CONFIG_BT_CTLR_ADV_EXT)
adv->event_counter += (lazy + 1); adv->event_counter += (lazy + 1);
@ -2581,6 +2663,9 @@ static void init_set(struct ll_adv_set *adv)
#endif /* CONFIG_BT_CTLR_PRIVACY */ #endif /* CONFIG_BT_CTLR_PRIVACY */
adv->lll.chan_map = BT_LE_ADV_CHAN_MAP_ALL; adv->lll.chan_map = BT_LE_ADV_CHAN_MAP_ALL;
adv->lll.filter_policy = BT_LE_ADV_FP_NO_WHITELIST; adv->lll.filter_policy = BT_LE_ADV_FP_NO_WHITELIST;
#if defined(CONFIG_BT_CTLR_JIT_SCHEDULING)
adv->delay_remain = ULL_ADV_RANDOM_DELAY;
#endif /* ONFIG_BT_CTLR_JIT_SCHEDULING */
init_pdu(lll_adv_data_peek(&ll_adv[0].lll), PDU_ADV_TYPE_ADV_IND); init_pdu(lll_adv_data_peek(&ll_adv[0].lll), PDU_ADV_TYPE_ADV_IND);
init_pdu(lll_adv_scan_rsp_peek(&ll_adv[0].lll), PDU_ADV_TYPE_SCAN_RSP); init_pdu(lll_adv_scan_rsp_peek(&ll_adv[0].lll), PDU_ADV_TYPE_SCAN_RSP);

View file

@ -57,6 +57,11 @@ struct ll_adv_set {
#if defined(CONFIG_BT_CTLR_DF_ADV_CTE_TX) #if defined(CONFIG_BT_CTLR_DF_ADV_CTE_TX)
struct lll_df_adv_cfg *df_cfg; struct lll_df_adv_cfg *df_cfg;
#endif /* CONFIG_BT_CTLR_DF_ADV_CTE_TX */ #endif /* CONFIG_BT_CTLR_DF_ADV_CTE_TX */
#if defined(CONFIG_BT_CTLR_JIT_SCHEDULING)
uint32_t delay;
uint32_t delay_remain;
uint32_t ticks_at_expire;
#endif /* CONFIG_BT_CTLR_JIT_SCHEDULING */
}; };
#if defined(CONFIG_BT_CTLR_ADV_EXT) #if defined(CONFIG_BT_CTLR_ADV_EXT)

View file

@ -53,3 +53,4 @@ int ull_disable(void *param);
void ull_drift_ticks_get(struct node_rx_event_done *done, void ull_drift_ticks_get(struct node_rx_event_done *done,
uint32_t *ticks_drift_plus, uint32_t *ticks_drift_plus,
uint32_t *ticks_drift_minus); uint32_t *ticks_drift_minus);
struct event_done_extra *ull_done_extra_type_set(uint8_t type);