Skip to content

Commit 7ba61e4

Browse files
committed
Bluetooth: Controller: Replace prepare pipeline with ordered list
Replace prepare pipeline with ordered linked list. Signed-off-by: Vinayak Kariappa Chettimada <vich@nordicsemi.no>
1 parent 2cfd924 commit 7ba61e4

File tree

3 files changed

+230
-207
lines changed

3 files changed

+230
-207
lines changed

‎subsys/bluetooth/controller/ll_sw/lll.h‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -611,7 +611,7 @@ struct lll_event *ull_prepare_enqueue(lll_is_abort_cb_t is_abort_cb,
611611
lll_prepare_cb_t prepare_cb,
612612
uint8_t is_resume);
613613
void *ull_prepare_dequeue_get(void);
614-
void *ull_prepare_dequeue_iter(uint8_t *idx);
614+
void *ull_prepare_dequeue_iter(void **idx);
615615
void ull_prepare_dequeue(uint8_t caller_id);
616616
void *ull_pdu_rx_alloc_peek(uint8_t count);
617617
void *ull_pdu_rx_alloc_peek_iter(uint8_t *idx);

‎subsys/bluetooth/controller/ll_sw/nordic/lll/lll.c‎

Lines changed: 39 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ static int init_reset(void);
7070
static inline void done_inc(void);
7171
#endif /* CONFIG_BT_CTLR_LOW_LAT_ULL_DONE */
7272
static inline bool is_done_sync(void);
73-
static inline struct lll_event *prepare_dequeue_iter_ready_get(uint8_t *idx);
73+
static inline struct lll_event *prepare_dequeue_iter_ready_get(void **idx);
7474
static inline struct lll_event *resume_enqueue(lll_is_abort_cb_t is_abort_cb,
7575
lll_abort_cb_t abort_cb, lll_prepare_cb_t resume_cb,
7676
void *param);
@@ -466,9 +466,9 @@ void lll_disable(void *param)
466466
}
467467
{
468468
struct lll_event *next;
469-
uint8_t idx;
469+
void *idx;
470470

471-
idx = UINT8_MAX;
471+
idx = NULL;
472472
next = ull_prepare_dequeue_iter(&idx);
473473
while (next) {
474474
if (!next->is_aborted &&
@@ -482,8 +482,10 @@ void lll_disable(void *param)
482482
* the prepare pipeline hence re-iterate
483483
* through the prepare pipeline.
484484
*/
485-
idx = UINT8_MAX;
485+
idx = NULL;
486486
#endif /* CONFIG_BT_CTLR_LOW_LAT_ULL_DONE */
487+
} else if (!idx) {
488+
break;
487489
}
488490

489491
next = ull_prepare_dequeue_iter(&idx);
@@ -835,53 +837,30 @@ int lll_prepare_resolve(lll_is_abort_cb_t is_abort_cb, lll_abort_cb_t abort_cb,
835837
struct lll_event *ready_short = NULL;
836838
struct lll_event *ready;
837839
struct lll_event *next;
838-
uint8_t idx;
840+
void *idx;
839841
int err;
840842

841843
/* Find the ready prepare in the pipeline */
842-
idx = UINT8_MAX;
844+
idx = NULL;
843845
ready = prepare_dequeue_iter_ready_get(&idx);
844846

845847
/* Find any short prepare */
846-
if (ready) {
848+
if (ready && (&ready->prepare_param != prepare_param)) {
847849
uint32_t ticks_at_preempt_min = prepare_param->ticks_at_expire;
848850
uint32_t ticks_at_preempt_next;
849-
uint8_t idx_backup = idx;
850851
uint32_t diff;
851852

852853
ticks_at_preempt_next = ready->prepare_param.ticks_at_expire;
853854
diff = ticker_ticks_diff_get(ticks_at_preempt_min,
854855
ticks_at_preempt_next);
855856
if (is_resume || ((diff & BIT(HAL_TICKER_CNTR_MSBIT)) == 0U)) {
856857
ticks_at_preempt_min = ticks_at_preempt_next;
857-
if (&ready->prepare_param != prepare_param) {
858-
ready_short = ready;
859-
}
858+
ready_short = ready;
860859
} else {
861860
ready = NULL;
862-
idx_backup = UINT8_MAX;
863861
}
864-
865-
do {
866-
struct lll_event *ready_next;
867-
868-
ready_next = prepare_dequeue_iter_ready_get(&idx);
869-
if (!ready_next) {
870-
break;
871-
}
872-
873-
ticks_at_preempt_next = ready_next->prepare_param.ticks_at_expire;
874-
diff = ticker_ticks_diff_get(ticks_at_preempt_next,
875-
ticks_at_preempt_min);
876-
if ((diff & BIT(HAL_TICKER_CNTR_MSBIT)) == 0U) {
877-
continue;
878-
}
879-
880-
ready_short = ready_next;
881-
ticks_at_preempt_min = ticks_at_preempt_next;
882-
} while (true);
883-
884-
idx = idx_backup;
862+
} else {
863+
ready = NULL;
885864
}
886865

887866
/* Current event active or another prepare is ready in the pipeline */
@@ -932,6 +911,8 @@ int lll_prepare_resolve(lll_is_abort_cb_t is_abort_cb, lll_abort_cb_t abort_cb,
932911
} else {
933912
next = ready;
934913
}
914+
} else if (!idx) {
915+
break;
935916
}
936917

937918
ready = ull_prepare_dequeue_iter(&idx);
@@ -989,6 +970,7 @@ int lll_prepare_resolve(lll_is_abort_cb_t is_abort_cb, lll_abort_cb_t abort_cb,
989970
*/
990971

991972
/* Find next prepare needing preempt timeout to be setup */
973+
idx = NULL;
992974
next = prepare_dequeue_iter_ready_get(&idx);
993975
if (!next) {
994976
return err;
@@ -1025,14 +1007,20 @@ static inline bool is_done_sync(void)
10251007
#endif /* !CONFIG_BT_CTLR_LOW_LAT_ULL_DONE */
10261008
}
10271009

1028-
static inline struct lll_event *prepare_dequeue_iter_ready_get(uint8_t *idx)
1010+
static inline struct lll_event *prepare_dequeue_iter_ready_get(void **idx)
10291011
{
10301012
struct lll_event *ready;
10311013

1032-
do {
1014+
ready = ull_prepare_dequeue_iter(idx);
1015+
while ((ready != NULL) && ((ready->is_aborted != 0U) || (ready->is_resume != 0U) ||
1016+
(ready->prepare_param.defer != 0U))) {
1017+
if (!*idx) {
1018+
ready = NULL;
1019+
break;
1020+
}
1021+
10331022
ready = ull_prepare_dequeue_iter(idx);
1034-
} while ((ready != NULL) && ((ready->is_aborted != 0U) || (ready->is_resume != 0U) ||
1035-
(ready->prepare_param.defer != 0U)));
1023+
}
10361024

10371025
return ready;
10381026
}
@@ -1223,17 +1211,16 @@ static void preempt(void *param)
12231211
{
12241212
lll_prepare_cb_t resume_cb;
12251213
struct lll_event *ready;
1226-
uint8_t idx;
1214+
void *idx;
12271215
int err;
12281216

12291217
/* No event to abort */
12301218
if (!event.curr.abort_cb || !event.curr.param) {
12311219
return;
12321220
}
12331221

1234-
preempt_find_preemptor:
12351222
/* Find a prepare that is ready and not a resume */
1236-
idx = UINT8_MAX;
1223+
idx = NULL;
12371224
ready = prepare_dequeue_iter_ready_get(&idx);
12381225
if (!ready) {
12391226
/* No ready prepare */
@@ -1242,87 +1229,14 @@ static void preempt(void *param)
12421229

12431230
/* Preemptor not in pipeline */
12441231
if (ready->prepare_param.param != param) {
1245-
uint32_t ticks_at_preempt_min = ready->prepare_param.ticks_at_expire;
1246-
struct lll_event *ready_short = NULL;
1247-
struct lll_event *ready_next = NULL;
1248-
struct lll_event *preemptor;
1249-
1250-
/* Find if the short prepare request in the pipeline */
1251-
do {
1252-
uint32_t ticks_at_preempt_next;
1253-
uint32_t diff;
1254-
1255-
preemptor = prepare_dequeue_iter_ready_get(&idx);
1256-
if (!preemptor) {
1257-
break;
1258-
}
1259-
1260-
if (!ready_next) {
1261-
ready_next = preemptor;
1262-
}
1263-
1264-
if (preemptor->prepare_param.param == param) {
1265-
break;
1266-
}
1267-
1268-
ticks_at_preempt_next = preemptor->prepare_param.ticks_at_expire;
1269-
diff = ticker_ticks_diff_get(ticks_at_preempt_next,
1270-
ticks_at_preempt_min);
1271-
if ((diff & BIT(HAL_TICKER_CNTR_MSBIT)) == 0U) {
1272-
continue;
1273-
}
1274-
1275-
ready_short = preemptor;
1276-
ticks_at_preempt_min = ticks_at_preempt_next;
1277-
} while (true);
1278-
1279-
/* "The" short prepare we were looking for is not in pipeline */
1280-
if (!preemptor) {
1281-
uint32_t ret;
1282-
1283-
/* Find any short prepare */
1284-
if (ready_short) {
1285-
ready = ready_short;
1286-
}
1287-
1288-
/* Start the preempt timeout for (short) ready event */
1289-
ret = preempt_ticker_start(ready, NULL, ready);
1290-
LL_ASSERT((ret == TICKER_STATUS_SUCCESS) ||
1291-
(ret == TICKER_STATUS_BUSY));
1292-
1293-
return;
1294-
}
1295-
1296-
/* FIXME: Prepare pipeline is not a ordered list implementation,
1297-
* and for short prepare being enqueued, ideally the
1298-
* pipeline has to be implemented as ordered list.
1299-
* Until then a workaround to abort a prepare present
1300-
* before the short prepare being enqueued is implemented
1301-
* below.
1302-
* A proper solution will be to re-design the pipeline
1303-
* as a ordered list, instead of the current FIFO.
1304-
*/
1305-
1306-
/* Abort the prepare that is present before the short prepare */
1307-
ready->is_aborted = 1;
1308-
ready->abort_cb(&ready->prepare_param, ready->prepare_param.param);
1309-
1310-
/* Abort all events in pipeline before the short prepare */
1311-
if (preemptor != ready_next) {
1312-
goto preempt_find_preemptor;
1313-
}
1232+
uint32_t ret;
13141233

1315-
/* As the prepare queue has been refreshed due to the call of
1316-
* abort_cb which invokes the lll_done, find the latest prepare
1317-
*/
1318-
idx = UINT8_MAX;
1319-
ready = prepare_dequeue_iter_ready_get(&idx);
1320-
if (!ready) {
1321-
/* No ready prepare */
1322-
return;
1323-
}
1234+
/* Start the preempt timeout for ready event */
1235+
ret = preempt_ticker_start(ready, NULL, ready);
1236+
LL_ASSERT((ret == TICKER_STATUS_SUCCESS) ||
1237+
(ret == TICKER_STATUS_BUSY));
13241238

1325-
LL_ASSERT(ready->prepare_param.param == param);
1239+
return;
13261240
}
13271241

13281242
/* Check if current event want to continue */
@@ -1366,8 +1280,8 @@ static void preempt(void *param)
13661280
lll_abort_cb_t abort_cb;
13671281
uint8_t is_resume_abort;
13681282
struct lll_event *iter;
1369-
uint8_t iter_idx;
13701283
void *curr_param;
1284+
void *iter_idx;
13711285

13721286
/* Remove parameter assignment from currently active radio event so that done event
13731287
* is not generated.
@@ -1385,8 +1299,8 @@ static void preempt(void *param)
13851299
is_resume_abort = 0U;
13861300

13871301
preempt_abort_resume:
1388-
/* Abort any duplicate non-resume, that they get dequeued */
1389-
iter_idx = UINT8_MAX;
1302+
/* Abort any duplicates so that they get dequeued */
1303+
iter_idx = NULL;
13901304
iter = ull_prepare_dequeue_iter(&iter_idx);
13911305
while (iter) {
13921306
if (!iter->is_aborted &&
@@ -1401,8 +1315,10 @@ static void preempt(void *param)
14011315
* the prepare pipeline hence re-iterate
14021316
* through the prepare pipeline.
14031317
*/
1404-
iter_idx = UINT8_MAX;
1318+
iter_idx = NULL;
14051319
#endif /* CONFIG_BT_CTLR_LOW_LAT_ULL_DONE */
1320+
} else if (!iter_idx) {
1321+
break;
14061322
}
14071323

14081324
iter = ull_prepare_dequeue_iter(&iter_idx);

0 commit comments

Comments
 (0)