From fa20fa95d0c6d889de9f0e44d864f36d5e562936 Mon Sep 17 00:00:00 2001 From: Morten Priess Date: Fri, 21 May 2021 09:36:54 +0200 Subject: [PATCH] Bluetooth: controller: Improve ticker_by_next_slot_get Fixes ticker_by_next_slot_get for JIT scheduler by allowing iterating through ticker nodes without ticks_slot information, and improves performance for legacy ticker scheduling use. To reduce the processing and context switching overhead, a new feature is introduced via BT_TICKER_NEXT_SLOT_GET_MATCH, by which an operation callback may be added via the ticker_next_slot_get_ext interface, and the match function is then called when the ticker_job is processing the request. By returning true in this callback, iteration stops and normal operation callback is invoked. If the match function returns false, node iteration continues. This reduces the number of ticker_job executions for node iteration. Signed-off-by: Morten Priess --- .../bluetooth/controller/Kconfig.ll_sw_split | 9 ++ .../bluetooth/controller/ll_sw/ull_adv_sync.c | 1 + subsys/bluetooth/controller/ll_sw/ull_sched.c | 30 +++++- subsys/bluetooth/controller/ticker/ticker.c | 101 ++++++++++++++---- subsys/bluetooth/controller/ticker/ticker.h | 7 ++ 5 files changed, 124 insertions(+), 24 deletions(-) diff --git a/subsys/bluetooth/controller/Kconfig.ll_sw_split b/subsys/bluetooth/controller/Kconfig.ll_sw_split index ed1b8d3da65..e493b1c873e 100644 --- a/subsys/bluetooth/controller/Kconfig.ll_sw_split +++ b/subsys/bluetooth/controller/Kconfig.ll_sw_split @@ -553,6 +553,15 @@ config BT_TICKER_LAZY_GET ticker nodes, returning tick to expire and lazy count from a reference tick. +config BT_TICKER_NEXT_SLOT_GET_MATCH + bool "Ticker Next Slot Get with match callback" + default y if BT_TICKER_SLOT_AGNOSTIC + help + This option enables ticker interface to iterate through active + ticker nodes with a callback for every found ticker node. When + returning true in the callback, iteration will stop and the normal + operation callback invoked. + config BT_TICKER_EXT bool "Ticker extensions" depends on !BT_TICKER_LOW_LAT && !BT_TICKER_SLOT_AGNOSTIC diff --git a/subsys/bluetooth/controller/ll_sw/ull_adv_sync.c b/subsys/bluetooth/controller/ll_sw/ull_adv_sync.c index b688d604825..8f3acd51a42 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_adv_sync.c +++ b/subsys/bluetooth/controller/ll_sw/ull_adv_sync.c @@ -925,6 +925,7 @@ static void mfy_sync_offset_get(void *param) TICKER_USER_ID_ULL_LOW, &id, &ticks_current, &ticks_to_expire, &lazy, + NULL, NULL, ticker_op_cb, (void *)&ret_cb); if (ret == TICKER_STATUS_BUSY) { while (ret_cb == TICKER_STATUS_BUSY) { diff --git a/subsys/bluetooth/controller/ll_sw/ull_sched.c b/subsys/bluetooth/controller/ll_sw/ull_sched.c index 21f1ca4a0e9..5dab767319b 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_sched.c +++ b/subsys/bluetooth/controller/ll_sw/ull_sched.c @@ -46,6 +46,20 @@ static void after_mstr_offset_get(uint16_t conn_interval, uint32_t ticks_slot, uint32_t *win_offset_us); static void ticker_op_cb(uint32_t status, void *param); +#if defined(CONFIG_BT_TICKER_NEXT_SLOT_GET_MATCH) +bool ticker_match_op_cb(uint8_t ticker_id, uint32_t ticks_slot, + uint32_t ticks_to_expire, void *op_context) +{ + ARG_UNUSED(ticks_slot); + ARG_UNUSED(ticks_to_expire); + ARG_UNUSED(op_context); + + bool match = ticker_id >= TICKER_ID_CONN_BASE && + ticker_id <= TICKER_ID_CONN_LAST; + return match; +} +#endif /* CONFIG_BT_TICKER_NEXT_SLOT_GET_MATCH */ + void ull_sched_after_mstr_slot_get(uint8_t user_id, uint32_t ticks_slot_abs, uint32_t *ticks_anchor, uint32_t *us_offset) { @@ -67,10 +81,20 @@ void ull_sched_after_mstr_slot_get(uint8_t user_id, uint32_t ticks_slot_abs, bool success; ret_cb = TICKER_STATUS_BUSY; +#if defined(CONFIG_BT_TICKER_NEXT_SLOT_GET_MATCH) + ret = ticker_next_slot_get_ext(TICKER_INSTANCE_ID_CTLR, user_id, + &ticker_id, ticks_anchor, + &ticks_to_expire, + NULL, /* lazy */ + ticker_match_op_cb, + NULL, /* match_op_context */ + ticker_op_cb, (void *)&ret_cb); +#else ret = ticker_next_slot_get(TICKER_INSTANCE_ID_CTLR, user_id, &ticker_id, ticks_anchor, - &ticks_to_expire, ticker_op_cb, - (void *)&ret_cb); + &ticks_to_expire, + ticker_op_cb, (void *)&ret_cb); +#endif /* CONFIG_BT_TICKER_NEXT_SLOT_GET_MATCH */ if (ret == TICKER_STATUS_BUSY) { while (ret_cb == TICKER_STATUS_BUSY) { ticker_job_sched(TICKER_INSTANCE_ID_CTLR, @@ -85,10 +109,12 @@ void ull_sched_after_mstr_slot_get(uint8_t user_id, uint32_t ticks_slot_abs, break; } +#if !defined(CONFIG_BT_TICKER_NEXT_SLOT_GET_MATCH) if ((ticker_id < TICKER_ID_CONN_BASE) || (ticker_id > TICKER_ID_CONN_LAST)) { continue; } +#endif /* CONFIG_BT_TICKER_NEXT_SLOT_GET_MATCH */ conn = ll_conn_get(ticker_id - TICKER_ID_CONN_BASE); if (conn && !conn->lll.role) { diff --git a/subsys/bluetooth/controller/ticker/ticker.c b/subsys/bluetooth/controller/ticker/ticker.c index 12c5ca8328f..423ff6ed8d3 100644 --- a/subsys/bluetooth/controller/ticker/ticker.c +++ b/subsys/bluetooth/controller/ticker/ticker.c @@ -183,6 +183,10 @@ struct ticker_user_op_slot_get { #if defined(CONFIG_BT_TICKER_LAZY_GET) uint16_t *lazy; #endif /* CONFIG_BT_TICKER_LAZY_GET */ +#if defined(CONFIG_BT_TICKER_NEXT_SLOT_GET_MATCH) + ticker_op_match_func fp_match_op_func; + void *match_op_context; +#endif /* CONFIG_BT_TICKER_NEXT_SLOT_GET_MATCH */ }; /* User operation data structure for priority_set opcode. Used for passing @@ -351,27 +355,40 @@ static uint8_t ticker_by_slot_get(struct ticker_node *node, uint8_t ticker_id_he #endif /* CONFIG_BT_TICKER_LOW_LAT */ /** - * @brief Get next ticker with slot ticks + * @brief Get next ticker with slot ticks or match * - * @details Gets the next ticker which has slot ticks specified and - * return the ticker id and accumulated ticks until expiration. If no - * ticker nodes have slot ticks, the next ticker node is returned. - * If no head id is provided (TICKER_NULL) the first node is returned. + * @details Iterates ticker nodes from ticker_id_head. If no head id is provided + * (TICKER_NULL), iteration starts from the first node. + * Operation details: + * + * NORMAL MODE (!CONFIG_BT_TICKER_SLOT_AGNOSTIC) + * - Gets the next ticker which has slot ticks specified and return the ticker + * id and accumulated ticks until expiration. + * - If a matching function is provided, this function is called and node iteration + * continues until match function returns true. + * + * SLOT AGNOSTIC MODE (CONFIG_BT_TICKER_SLOT_AGNOSTIC) + * - Gets the next ticker node. + * - If a matching function is provided, this function is called and node iteration + * continues until match function returns true. * * @param instance Pointer to ticker instance * @param ticker_id_head Pointer to id of first ticker node [in/out] * @param ticks_current Pointer to current ticks count [in/out] * @param ticks_to_expire Pointer to ticks to expire [in/out] - * + * @param fp_match_op_func Pointer to match function or NULL if unused + * @param match_op_context Pointer to operation context passed to match + * function or NULL if unused + * @param lazy Pointer to lazy variable to receive lazy_current + * of found ticker node * @internal */ static void ticker_by_next_slot_get(struct ticker_instance *instance, uint8_t *ticker_id_head, uint32_t *ticks_current, -#if defined(CONFIG_BT_TICKER_LAZY_GET) - uint32_t *ticks_to_expire, uint16_t *lazy) -#else /* !CONFIG_BT_TICKER_LAZY_GET */ - uint32_t *ticks_to_expire) -#endif /* !CONFIG_BT_TICKER_LAZY_GET */ + uint32_t *ticks_to_expire, + ticker_op_match_func fp_match_op_func, + void *match_op_context, + uint16_t *lazy) { struct ticker_node *ticker; struct ticker_node *node; @@ -394,18 +411,44 @@ static void ticker_by_next_slot_get(struct ticker_instance *instance, _ticker_id_head = ticker->next; } + /* Find first ticker node with match or slot ticks */ + while (_ticker_id_head != TICKER_NULL) { + ticker = &node[_ticker_id_head]; + +#if defined(CONFIG_BT_TICKER_NEXT_SLOT_GET_MATCH) + if (fp_match_op_func) { + uint32_t ticks_slot = 0; + #if !defined(CONFIG_BT_TICKER_SLOT_AGNOSTIC) - /* Find first ticker node with slot ticks */ - while ((_ticker_id_head != TICKER_NULL) && - ((ticker = &node[_ticker_id_head])->ticks_slot == 0U)) { + ticks_slot += ticker->ticks_slot; +#endif /* !CONFIG_BT_TICKER_SLOT_AGNOSTIC */ + + /* Match node id */ + if (fp_match_op_func(_ticker_id_head, ticks_slot, + _ticks_to_expire + + ticker->ticks_to_expire, + match_op_context)) { + /* Match found */ + break; + } + } else +#endif /* CONFIG_BT_TICKER_NEXT_SLOT_GET_MATCH */ +#if !defined(CONFIG_BT_TICKER_SLOT_AGNOSTIC) + if (ticker->ticks_slot) { + /* Matching not used and node has slot ticks */ + break; +#else + { + /* Matching not used and slot agnostic */ + break; +#endif /* !CONFIG_BT_TICKER_SLOT_AGNOSTIC */ + } + /* Accumulate expire ticks */ _ticks_to_expire += ticker->ticks_to_expire; _ticker_id_head = ticker->next; } -#else - /* TODO: Come up with different way to find/match the ticker */ - LL_ASSERT(0); -#endif + if (_ticker_id_head != TICKER_NULL) { /* Add ticks for found ticker */ _ticks_to_expire += ticker->ticks_to_expire; @@ -2154,11 +2197,17 @@ static inline void ticker_job_op_inquire(struct ticker_instance *instance, ticker_by_next_slot_get(instance, uop->params.slot_get.ticker_id, uop->params.slot_get.ticks_current, -#if defined(CONFIG_BT_TICKER_LAZY_GET) uop->params.slot_get.ticks_to_expire, +#if defined(CONFIG_BT_TICKER_NEXT_SLOT_GET_MATCH) + uop->params.slot_get.fp_match_op_func, + uop->params.slot_get.match_op_context, +#else + NULL, NULL, +#endif +#if defined(CONFIG_BT_TICKER_LAZY_GET) uop->params.slot_get.lazy); #else /* !CONFIG_BT_TICKER_LAZY_GET */ - uop->params.slot_get.ticks_to_expire); + NULL); #endif /* !CONFIG_BT_TICKER_LAZY_GET */ __fallthrough; case TICKER_USER_OP_TYPE_IDLE_GET: @@ -2894,18 +2943,22 @@ uint32_t ticker_next_slot_get(uint8_t instance_index, uint8_t user_id, uint32_t *ticks_to_expire, ticker_op_func fp_op_func, void *op_context) { -#if defined(CONFIG_BT_TICKER_LAZY_GET) +#if defined(CONFIG_BT_TICKER_LAZY_GET) || \ + defined(CONFIG_BT_TICKER_NEXT_SLOT_GET_MATCH) return ticker_next_slot_get_ext(instance_index, user_id, ticker_id, ticks_current, ticks_to_expire, NULL, + NULL, NULL, fp_op_func, op_context); } uint32_t ticker_next_slot_get_ext(uint8_t instance_index, uint8_t user_id, uint8_t *ticker_id, uint32_t *ticks_current, uint32_t *ticks_to_expire, uint16_t *lazy, + ticker_op_match_func fp_match_op_func, + void *match_op_context, ticker_op_func fp_op_func, void *op_context) { -#endif /* CONFIG_BT_TICKER_LAZY_GET */ +#endif /* CONFIG_BT_TICKER_LAZY_GET || CONFIG_BT_TICKER_NEXT_SLOT_GET_MATCH */ struct ticker_instance *instance = &_instance[instance_index]; struct ticker_user_op *user_op; struct ticker_user *user; @@ -2931,6 +2984,10 @@ uint32_t ticker_next_slot_get_ext(uint8_t instance_index, uint8_t user_id, #if defined(CONFIG_BT_TICKER_LAZY_GET) user_op->params.slot_get.lazy = lazy; #endif /* CONFIG_BT_TICKER_LAZY_GET */ +#if defined(CONFIG_BT_TICKER_NEXT_SLOT_GET_MATCH) + user_op->params.slot_get.fp_match_op_func = fp_match_op_func; + user_op->params.slot_get.match_op_context = match_op_context; +#endif /* CONFIG_BT_TICKER_NEXT_SLOT_GET_MATCH */ user_op->status = TICKER_STATUS_BUSY; user_op->fp_op_func = fp_op_func; user_op->op_context = op_context; diff --git a/subsys/bluetooth/controller/ticker/ticker.h b/subsys/bluetooth/controller/ticker/ticker.h index 042453cf1b9..62089ffdc8d 100644 --- a/subsys/bluetooth/controller/ticker/ticker.h +++ b/subsys/bluetooth/controller/ticker/ticker.h @@ -103,6 +103,11 @@ typedef void (*ticker_timeout_func) (uint32_t ticks_at_expire, uint32_t remainde */ typedef void (*ticker_op_func) (uint32_t status, void *op_context); +/** \brief Timer operation match callback function type. + */ +typedef bool (*ticker_op_match_func) (uint8_t ticker_id, uint32_t ticks_slot, + uint32_t ticks_to_expire, void *op_context); + #if defined(CONFIG_BT_TICKER_EXT) struct ticker_ext { uint32_t ticks_slot_window;/* Window in which the slot @@ -158,6 +163,8 @@ uint32_t ticker_next_slot_get(uint8_t instance_index, uint8_t user_id, uint32_t ticker_next_slot_get_ext(uint8_t instance_index, uint8_t user_id, uint8_t *ticker_id, uint32_t *ticks_current, uint32_t *ticks_to_expire, uint16_t *lazy, + ticker_op_match_func fp_op_match_func, + void *match_op_context, ticker_op_func fp_op_func, void *op_context); uint32_t ticker_job_idle_get(uint8_t instance_index, uint8_t user_id, ticker_op_func fp_op_func, void *op_context);