Skip to content

Commit 997a1e0

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 3c64b79 commit 997a1e0

File tree

4 files changed

+282
-269
lines changed

4 files changed

+282
-269
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: 42 additions & 169 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ static int init_reset(void);
7171
static inline void done_inc(void);
7272
#endif /* CONFIG_BT_CTLR_LOW_LAT_ULL_DONE */
7373
static inline bool is_done_sync(void);
74-
static inline struct lll_event *prepare_dequeue_iter_ready_get(uint8_t *idx);
74+
static inline struct lll_event *prepare_dequeue_iter_ready_get(void **idx);
7575
static inline struct lll_event *resume_enqueue(lll_is_abort_cb_t is_abort_cb,
7676
lll_abort_cb_t abort_cb, lll_prepare_cb_t resume_cb,
7777
void *param);
@@ -491,9 +491,9 @@ void lll_disable(void *param)
491491
}
492492
{
493493
struct lll_event *next;
494-
uint8_t idx;
494+
void *idx;
495495

496-
idx = UINT8_MAX;
496+
idx = NULL;
497497
next = ull_prepare_dequeue_iter(&idx);
498498
while (next) {
499499
if (!next->is_aborted &&
@@ -507,8 +507,10 @@ void lll_disable(void *param)
507507
* the prepare pipeline hence re-iterate
508508
* through the prepare pipeline.
509509
*/
510-
idx = UINT8_MAX;
510+
idx = NULL;
511511
#endif /* CONFIG_BT_CTLR_LOW_LAT_ULL_DONE */
512+
} else if (!idx) {
513+
break;
512514
}
513515

514516
next = ull_prepare_dequeue_iter(&idx);
@@ -860,78 +862,26 @@ int lll_prepare_resolve(lll_is_abort_cb_t is_abort_cb, lll_abort_cb_t abort_cb,
860862
struct lll_event *ready_short = NULL;
861863
struct lll_event *ready;
862864
struct lll_event *next;
863-
uint8_t idx;
865+
void *idx;
864866
int err;
865867

866868
/* Find the ready prepare in the pipeline */
867-
idx = UINT8_MAX;
869+
idx = NULL;
868870
ready = prepare_dequeue_iter_ready_get(&idx);
869871

870872
/* Find any short prepare */
871-
if (ready) {
872-
uint32_t ticks_at_preempt_min = prepare_param->ticks_at_expire;
873-
uint32_t ticks_at_preempt_next;
874-
uint8_t idx_backup = idx;
873+
if (ready && (&ready->prepare_param != prepare_param)) {
875874
uint32_t diff;
876875

877-
ticks_at_preempt_next = ready->prepare_param.ticks_at_expire;
878-
diff = ticker_ticks_diff_get(ticks_at_preempt_min,
879-
ticks_at_preempt_next);
880-
/* If the enqueued prepare is a resume or current ready prepare is shorter, then we
881-
* should pick current ready prepare for setting up the prepare timeout.
882-
*/
883-
if (is_resume || ((diff & BIT(HAL_TICKER_CNTR_MSBIT)) == 0U)) {
884-
ticks_at_preempt_min = ticks_at_preempt_next;
885-
if (&ready->prepare_param != prepare_param) {
886-
/* There is a shorter prepare in the pipeline */
887-
ready_short = ready;
888-
} else {
889-
/* It is the same prepare in the pipeline being enqueued.
890-
* This can happen executing `lll_done()`.
891-
* Hence, we should ignore it being the `first` that setup the
892-
* preempt timeout and also it has already setup the preempt
893-
* timeout, refer to `preempt_ticker_start()` for details.
894-
*
895-
* We also set the `ready` to NULL as it is the same ready, the one
896-
* being enqueued. This help short circuit a related assertion check
897-
* later in this function.
898-
*/
899-
ready = NULL;
900-
}
876+
diff = ticker_ticks_diff_get(prepare_param->ticks_at_expire,
877+
ready->prepare_param.ticks_at_expire);
878+
if (is_resume || (diff && ((diff & BIT(HAL_TICKER_CNTR_MSBIT)) == 0U))) {
879+
ready_short = ready;
901880
} else {
902881
ready = NULL;
903-
idx_backup = UINT8_MAX;
904882
}
905-
906-
/* Loop and find any short prepare present out-of-order in the prepare pipeline.
907-
*
908-
* NOTE: This loop is O(n), where n is number of items in prepare pipeline present
909-
* before a short prepare was enqueued in to the FIFO.
910-
* Use of ordered linked list implementation has show improved lower latencies
911-
* and less CPU use.
912-
* TODO: Replace use of FIFO for prepare pipeline with ordered linked list
913-
* implementation.
914-
*/
915-
do {
916-
struct lll_event *ready_next;
917-
918-
ready_next = prepare_dequeue_iter_ready_get(&idx);
919-
if (!ready_next) {
920-
break;
921-
}
922-
923-
ticks_at_preempt_next = ready_next->prepare_param.ticks_at_expire;
924-
diff = ticker_ticks_diff_get(ticks_at_preempt_next,
925-
ticks_at_preempt_min);
926-
if ((diff & BIT(HAL_TICKER_CNTR_MSBIT)) == 0U) {
927-
continue;
928-
}
929-
930-
ready_short = ready_next;
931-
ticks_at_preempt_min = ticks_at_preempt_next;
932-
} while (true);
933-
934-
idx = idx_backup;
883+
} else {
884+
ready = NULL;
935885
}
936886

937887
/* Current event active or another prepare is ready in the pipeline */
@@ -986,6 +936,8 @@ int lll_prepare_resolve(lll_is_abort_cb_t is_abort_cb, lll_abort_cb_t abort_cb,
986936
} else {
987937
next = ready;
988938
}
939+
} else if (!idx) {
940+
break;
989941
}
990942

991943
ready = ull_prepare_dequeue_iter(&idx);
@@ -1047,6 +999,7 @@ int lll_prepare_resolve(lll_is_abort_cb_t is_abort_cb, lll_abort_cb_t abort_cb,
1047999
*/
10481000

10491001
/* Find next prepare needing preempt timeout to be setup */
1002+
idx = NULL;
10501003
next = prepare_dequeue_iter_ready_get(&idx);
10511004
if (!next) {
10521005
return err;
@@ -1083,14 +1036,20 @@ static inline bool is_done_sync(void)
10831036
#endif /* !CONFIG_BT_CTLR_LOW_LAT_ULL_DONE */
10841037
}
10851038

1086-
static inline struct lll_event *prepare_dequeue_iter_ready_get(uint8_t *idx)
1039+
static inline struct lll_event *prepare_dequeue_iter_ready_get(void **idx)
10871040
{
10881041
struct lll_event *ready;
10891042

1090-
do {
1043+
ready = ull_prepare_dequeue_iter(idx);
1044+
while ((ready != NULL) && ((ready->is_aborted != 0U) || (ready->is_resume != 0U) ||
1045+
(ready->prepare_param.defer != 0U))) {
1046+
if (!*idx) {
1047+
ready = NULL;
1048+
break;
1049+
}
1050+
10911051
ready = ull_prepare_dequeue_iter(idx);
1092-
} while ((ready != NULL) && ((ready->is_aborted != 0U) || (ready->is_resume != 0U) ||
1093-
(ready->prepare_param.defer != 0U)));
1052+
}
10941053

10951054
return ready;
10961055
}
@@ -1281,7 +1240,7 @@ static void preempt(void *param)
12811240
{
12821241
lll_prepare_cb_t resume_cb;
12831242
struct lll_event *ready;
1284-
uint8_t idx;
1243+
void *idx;
12851244
int err;
12861245

12871246
/* No event to abort */
@@ -1306,9 +1265,8 @@ static void preempt(void *param)
13061265
return;
13071266
}
13081267

1309-
preempt_find_preemptor:
13101268
/* Find a prepare that is ready and not a resume */
1311-
idx = UINT8_MAX;
1269+
idx = NULL;
13121270
ready = prepare_dequeue_iter_ready_get(&idx);
13131271
if (!ready) {
13141272
/* No ready prepare */
@@ -1317,87 +1275,14 @@ static void preempt(void *param)
13171275

13181276
/* Preemptor not in pipeline */
13191277
if (ready->prepare_param.param != param) {
1320-
uint32_t ticks_at_preempt_min = ready->prepare_param.ticks_at_expire;
1321-
struct lll_event *ready_short = NULL;
1322-
struct lll_event *ready_next = NULL;
1323-
struct lll_event *preemptor;
1324-
1325-
/* Find if the short prepare request in the pipeline */
1326-
do {
1327-
uint32_t ticks_at_preempt_next;
1328-
uint32_t diff;
1329-
1330-
preemptor = prepare_dequeue_iter_ready_get(&idx);
1331-
if (!preemptor) {
1332-
break;
1333-
}
1334-
1335-
if (!ready_next) {
1336-
ready_next = preemptor;
1337-
}
1338-
1339-
if (preemptor->prepare_param.param == param) {
1340-
break;
1341-
}
1342-
1343-
ticks_at_preempt_next = preemptor->prepare_param.ticks_at_expire;
1344-
diff = ticker_ticks_diff_get(ticks_at_preempt_next,
1345-
ticks_at_preempt_min);
1346-
if ((diff & BIT(HAL_TICKER_CNTR_MSBIT)) == 0U) {
1347-
continue;
1348-
}
1349-
1350-
ready_short = preemptor;
1351-
ticks_at_preempt_min = ticks_at_preempt_next;
1352-
} while (true);
1353-
1354-
/* "The" short prepare we were looking for is not in pipeline */
1355-
if (!preemptor) {
1356-
uint32_t ret;
1357-
1358-
/* Find any short prepare */
1359-
if (ready_short) {
1360-
ready = ready_short;
1361-
}
1362-
1363-
/* Start the preempt timeout for (short) ready event */
1364-
ret = preempt_ticker_start(ready, NULL, ready);
1365-
LL_ASSERT_ERR((ret == TICKER_STATUS_SUCCESS) ||
1366-
(ret == TICKER_STATUS_BUSY));
1367-
1368-
return;
1369-
}
1370-
1371-
/* FIXME: Prepare pipeline is not a ordered list implementation,
1372-
* and for short prepare being enqueued, ideally the
1373-
* pipeline has to be implemented as ordered list.
1374-
* Until then a workaround to abort a prepare present
1375-
* before the short prepare being enqueued is implemented
1376-
* below.
1377-
* A proper solution will be to re-design the pipeline
1378-
* as a ordered list, instead of the current FIFO.
1379-
*/
1380-
1381-
/* Abort the prepare that is present before the short prepare */
1382-
ready->is_aborted = 1;
1383-
ready->abort_cb(&ready->prepare_param, ready->prepare_param.param);
1278+
uint32_t ret;
13841279

1385-
/* Abort all events in pipeline before the short prepare */
1386-
if (preemptor != ready_next) {
1387-
goto preempt_find_preemptor;
1388-
}
1280+
/* Start the preempt timeout for ready event */
1281+
ret = preempt_ticker_start(ready, NULL, ready);
1282+
LL_ASSERT((ret == TICKER_STATUS_SUCCESS) ||
1283+
(ret == TICKER_STATUS_BUSY));
13891284

1390-
/* As the prepare queue has been refreshed due to the call of
1391-
* abort_cb which invokes the lll_done, find the latest prepare
1392-
*/
1393-
idx = UINT8_MAX;
1394-
ready = prepare_dequeue_iter_ready_get(&idx);
1395-
if (!ready) {
1396-
/* No ready prepare */
1397-
return;
1398-
}
1399-
1400-
LL_ASSERT_ERR(ready->prepare_param.param == param);
1285+
return;
14011286
}
14021287

14031288
if (IS_ENABLED(CONFIG_BT_CTLR_LLL_PREPARE_AT_MARGIN)) {
@@ -1446,10 +1331,9 @@ static void preempt(void *param)
14461331
if (err == -EAGAIN) {
14471332
lll_is_abort_cb_t is_abort_cb;
14481333
lll_abort_cb_t abort_cb;
1449-
uint8_t is_resume_abort;
14501334
struct lll_event *iter;
1451-
uint8_t iter_idx;
14521335
void *curr_param;
1336+
void *iter_idx;
14531337

14541338
/* Remove parameter assignment from currently active radio event so that done event
14551339
* is not generated.
@@ -1461,18 +1345,11 @@ static void preempt(void *param)
14611345
is_abort_cb = event.curr.is_abort_cb;
14621346
abort_cb = event.curr.abort_cb;
14631347

1464-
/* Iterate twice to ensure preempt timeout is setup after all duplicate resume
1465-
* events are aborted.
1466-
*/
1467-
is_resume_abort = 0U;
1468-
1469-
preempt_abort_resume:
1470-
/* Abort any duplicate non-resume, that they get dequeued */
1471-
iter_idx = UINT8_MAX;
1348+
/* Abort any duplicates so that they get dequeued */
1349+
iter_idx = NULL;
14721350
iter = ull_prepare_dequeue_iter(&iter_idx);
14731351
while (iter) {
14741352
if (!iter->is_aborted &&
1475-
(is_resume_abort || !iter->is_resume) &&
14761353
(curr_param == iter->prepare_param.param)) {
14771354
iter->is_aborted = 1;
14781355
iter->abort_cb(&iter->prepare_param,
@@ -1483,19 +1360,15 @@ static void preempt(void *param)
14831360
* the prepare pipeline hence re-iterate
14841361
* through the prepare pipeline.
14851362
*/
1486-
iter_idx = UINT8_MAX;
1363+
iter_idx = NULL;
14871364
#endif /* CONFIG_BT_CTLR_LOW_LAT_ULL_DONE */
1365+
} else if (!iter_idx) {
1366+
break;
14881367
}
14891368

14901369
iter = ull_prepare_dequeue_iter(&iter_idx);
14911370
}
14921371

1493-
if (!is_resume_abort) {
1494-
is_resume_abort = 1U;
1495-
1496-
goto preempt_abort_resume;
1497-
}
1498-
14991372
/* Enqueue as resume event */
15001373
iter = resume_enqueue(is_abort_cb, abort_cb, resume_cb, curr_param);
15011374
LL_ASSERT_ERR(iter);

0 commit comments

Comments
 (0)