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 <mtpr@oticon.com>
This commit is contained in:
parent
ce757d5970
commit
fa20fa95d0
5 changed files with 124 additions and 24 deletions
|
@ -553,6 +553,15 @@ config BT_TICKER_LAZY_GET
|
||||||
ticker nodes, returning tick to expire and lazy count from a reference
|
ticker nodes, returning tick to expire and lazy count from a reference
|
||||||
tick.
|
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
|
config BT_TICKER_EXT
|
||||||
bool "Ticker extensions"
|
bool "Ticker extensions"
|
||||||
depends on !BT_TICKER_LOW_LAT && !BT_TICKER_SLOT_AGNOSTIC
|
depends on !BT_TICKER_LOW_LAT && !BT_TICKER_SLOT_AGNOSTIC
|
||||||
|
|
|
@ -925,6 +925,7 @@ static void mfy_sync_offset_get(void *param)
|
||||||
TICKER_USER_ID_ULL_LOW,
|
TICKER_USER_ID_ULL_LOW,
|
||||||
&id, &ticks_current,
|
&id, &ticks_current,
|
||||||
&ticks_to_expire, &lazy,
|
&ticks_to_expire, &lazy,
|
||||||
|
NULL, NULL,
|
||||||
ticker_op_cb, (void *)&ret_cb);
|
ticker_op_cb, (void *)&ret_cb);
|
||||||
if (ret == TICKER_STATUS_BUSY) {
|
if (ret == TICKER_STATUS_BUSY) {
|
||||||
while (ret_cb == TICKER_STATUS_BUSY) {
|
while (ret_cb == TICKER_STATUS_BUSY) {
|
||||||
|
|
|
@ -46,6 +46,20 @@ static void after_mstr_offset_get(uint16_t conn_interval, uint32_t ticks_slot,
|
||||||
uint32_t *win_offset_us);
|
uint32_t *win_offset_us);
|
||||||
static void ticker_op_cb(uint32_t status, void *param);
|
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,
|
void ull_sched_after_mstr_slot_get(uint8_t user_id, uint32_t ticks_slot_abs,
|
||||||
uint32_t *ticks_anchor, uint32_t *us_offset)
|
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;
|
bool success;
|
||||||
|
|
||||||
ret_cb = TICKER_STATUS_BUSY;
|
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,
|
ret = ticker_next_slot_get(TICKER_INSTANCE_ID_CTLR, user_id,
|
||||||
&ticker_id, ticks_anchor,
|
&ticker_id, ticks_anchor,
|
||||||
&ticks_to_expire, ticker_op_cb,
|
&ticks_to_expire,
|
||||||
(void *)&ret_cb);
|
ticker_op_cb, (void *)&ret_cb);
|
||||||
|
#endif /* CONFIG_BT_TICKER_NEXT_SLOT_GET_MATCH */
|
||||||
if (ret == TICKER_STATUS_BUSY) {
|
if (ret == TICKER_STATUS_BUSY) {
|
||||||
while (ret_cb == TICKER_STATUS_BUSY) {
|
while (ret_cb == TICKER_STATUS_BUSY) {
|
||||||
ticker_job_sched(TICKER_INSTANCE_ID_CTLR,
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !defined(CONFIG_BT_TICKER_NEXT_SLOT_GET_MATCH)
|
||||||
if ((ticker_id < TICKER_ID_CONN_BASE) ||
|
if ((ticker_id < TICKER_ID_CONN_BASE) ||
|
||||||
(ticker_id > TICKER_ID_CONN_LAST)) {
|
(ticker_id > TICKER_ID_CONN_LAST)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
#endif /* CONFIG_BT_TICKER_NEXT_SLOT_GET_MATCH */
|
||||||
|
|
||||||
conn = ll_conn_get(ticker_id - TICKER_ID_CONN_BASE);
|
conn = ll_conn_get(ticker_id - TICKER_ID_CONN_BASE);
|
||||||
if (conn && !conn->lll.role) {
|
if (conn && !conn->lll.role) {
|
||||||
|
|
|
@ -183,6 +183,10 @@ struct ticker_user_op_slot_get {
|
||||||
#if defined(CONFIG_BT_TICKER_LAZY_GET)
|
#if defined(CONFIG_BT_TICKER_LAZY_GET)
|
||||||
uint16_t *lazy;
|
uint16_t *lazy;
|
||||||
#endif /* CONFIG_BT_TICKER_LAZY_GET */
|
#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
|
/* 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 */
|
#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
|
* @details Iterates ticker nodes from ticker_id_head. If no head id is provided
|
||||||
* return the ticker id and accumulated ticks until expiration. If no
|
* (TICKER_NULL), iteration starts from the first node.
|
||||||
* ticker nodes have slot ticks, the next ticker node is returned.
|
* Operation details:
|
||||||
* If no head id is provided (TICKER_NULL) the first node is returned.
|
*
|
||||||
|
* 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 instance Pointer to ticker instance
|
||||||
* @param ticker_id_head Pointer to id of first ticker node [in/out]
|
* @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_current Pointer to current ticks count [in/out]
|
||||||
* @param ticks_to_expire Pointer to ticks to expire [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
|
* @internal
|
||||||
*/
|
*/
|
||||||
static void ticker_by_next_slot_get(struct ticker_instance *instance,
|
static void ticker_by_next_slot_get(struct ticker_instance *instance,
|
||||||
uint8_t *ticker_id_head, uint32_t *ticks_current,
|
uint8_t *ticker_id_head, uint32_t *ticks_current,
|
||||||
#if defined(CONFIG_BT_TICKER_LAZY_GET)
|
uint32_t *ticks_to_expire,
|
||||||
uint32_t *ticks_to_expire, uint16_t *lazy)
|
ticker_op_match_func fp_match_op_func,
|
||||||
#else /* !CONFIG_BT_TICKER_LAZY_GET */
|
void *match_op_context,
|
||||||
uint32_t *ticks_to_expire)
|
uint16_t *lazy)
|
||||||
#endif /* !CONFIG_BT_TICKER_LAZY_GET */
|
|
||||||
{
|
{
|
||||||
struct ticker_node *ticker;
|
struct ticker_node *ticker;
|
||||||
struct ticker_node *node;
|
struct ticker_node *node;
|
||||||
|
@ -394,18 +411,44 @@ static void ticker_by_next_slot_get(struct ticker_instance *instance,
|
||||||
_ticker_id_head = ticker->next;
|
_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)
|
#if !defined(CONFIG_BT_TICKER_SLOT_AGNOSTIC)
|
||||||
/* Find first ticker node with slot ticks */
|
ticks_slot += ticker->ticks_slot;
|
||||||
while ((_ticker_id_head != TICKER_NULL) &&
|
#endif /* !CONFIG_BT_TICKER_SLOT_AGNOSTIC */
|
||||||
((ticker = &node[_ticker_id_head])->ticks_slot == 0U)) {
|
|
||||||
|
/* 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 */
|
/* Accumulate expire ticks */
|
||||||
_ticks_to_expire += ticker->ticks_to_expire;
|
_ticks_to_expire += ticker->ticks_to_expire;
|
||||||
_ticker_id_head = ticker->next;
|
_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) {
|
if (_ticker_id_head != TICKER_NULL) {
|
||||||
/* Add ticks for found ticker */
|
/* Add ticks for found ticker */
|
||||||
_ticks_to_expire += ticker->ticks_to_expire;
|
_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,
|
ticker_by_next_slot_get(instance,
|
||||||
uop->params.slot_get.ticker_id,
|
uop->params.slot_get.ticker_id,
|
||||||
uop->params.slot_get.ticks_current,
|
uop->params.slot_get.ticks_current,
|
||||||
#if defined(CONFIG_BT_TICKER_LAZY_GET)
|
|
||||||
uop->params.slot_get.ticks_to_expire,
|
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);
|
uop->params.slot_get.lazy);
|
||||||
#else /* !CONFIG_BT_TICKER_LAZY_GET */
|
#else /* !CONFIG_BT_TICKER_LAZY_GET */
|
||||||
uop->params.slot_get.ticks_to_expire);
|
NULL);
|
||||||
#endif /* !CONFIG_BT_TICKER_LAZY_GET */
|
#endif /* !CONFIG_BT_TICKER_LAZY_GET */
|
||||||
__fallthrough;
|
__fallthrough;
|
||||||
case TICKER_USER_OP_TYPE_IDLE_GET:
|
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,
|
uint32_t *ticks_to_expire,
|
||||||
ticker_op_func fp_op_func, void *op_context)
|
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,
|
return ticker_next_slot_get_ext(instance_index, user_id, ticker_id,
|
||||||
ticks_current, ticks_to_expire, NULL,
|
ticks_current, ticks_to_expire, NULL,
|
||||||
|
NULL, NULL,
|
||||||
fp_op_func, op_context);
|
fp_op_func, op_context);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t ticker_next_slot_get_ext(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,
|
uint8_t *ticker_id, uint32_t *ticks_current,
|
||||||
uint32_t *ticks_to_expire, uint16_t *lazy,
|
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)
|
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_instance *instance = &_instance[instance_index];
|
||||||
struct ticker_user_op *user_op;
|
struct ticker_user_op *user_op;
|
||||||
struct ticker_user *user;
|
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)
|
#if defined(CONFIG_BT_TICKER_LAZY_GET)
|
||||||
user_op->params.slot_get.lazy = lazy;
|
user_op->params.slot_get.lazy = lazy;
|
||||||
#endif /* CONFIG_BT_TICKER_LAZY_GET */
|
#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->status = TICKER_STATUS_BUSY;
|
||||||
user_op->fp_op_func = fp_op_func;
|
user_op->fp_op_func = fp_op_func;
|
||||||
user_op->op_context = op_context;
|
user_op->op_context = op_context;
|
||||||
|
|
|
@ -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);
|
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)
|
#if defined(CONFIG_BT_TICKER_EXT)
|
||||||
struct ticker_ext {
|
struct ticker_ext {
|
||||||
uint32_t ticks_slot_window;/* Window in which the slot
|
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,
|
uint32_t ticker_next_slot_get_ext(uint8_t instance_index, uint8_t user_id,
|
||||||
uint8_t *ticker_id, uint32_t *ticks_current,
|
uint8_t *ticker_id, uint32_t *ticks_current,
|
||||||
uint32_t *ticks_to_expire, uint16_t *lazy,
|
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);
|
ticker_op_func fp_op_func, void *op_context);
|
||||||
uint32_t ticker_job_idle_get(uint8_t instance_index, uint8_t user_id,
|
uint32_t ticker_job_idle_get(uint8_t instance_index, uint8_t user_id,
|
||||||
ticker_op_func fp_op_func, void *op_context);
|
ticker_op_func fp_op_func, void *op_context);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue