Bluetooth: Controller: Fix LLL events pending check from ULL Low

ULL reference count is checked in ULL_LOW context to decide
if LLL events are pending, but the reference count can be
decremented by the ULL HIGH execution context which can
prevent the set `disabled_cb` function not being called due
to no pending event to produce the done events.

Fixed by checking the reference count in the ULL HIGH
execution context using a mayfly to schedule the check.

Signed-off-by: Vinayak Kariappa Chettimada <vich@nordicsemi.no>
This commit is contained in:
Vinayak Kariappa Chettimada 2021-08-16 16:50:07 +05:30 committed by Christopher Friedt
commit f06ac2be2c
3 changed files with 126 additions and 92 deletions

View file

@ -84,6 +84,7 @@ static void conn_cleanup(struct ll_conn *conn, uint8_t reason);
static void conn_cleanup_finalize(struct ll_conn *conn);
static void tx_ull_flush(struct ll_conn *conn);
static void ticker_stop_op_cb(uint32_t status, void *param);
static void conn_disable(void *param);
static void disabled_cb(void *param);
static void tx_lll_flush(void *param);
@ -2039,39 +2040,47 @@ static void tx_ull_flush(struct ll_conn *conn)
static void ticker_stop_op_cb(uint32_t status, void *param)
{
static memq_link_t link;
static struct mayfly mfy = {0, 0, &link, NULL, NULL};
struct ll_conn *conn;
struct ull_hdr *hdr;
static struct mayfly mfy = {0, 0, &link, NULL, conn_disable};
uint32_t ret;
LL_ASSERT(status == TICKER_STATUS_SUCCESS);
/* NOTE: We are in ULL_LOW which can be pre-empted by ULL_HIGH.
* As we are in the callback after successful stop of the
* ticker, the ULL reference count will not be modified
* further hence it is safe to check and act on either the need
* to call lll_disable or not.
*/
/* Check if any pending LLL events that need to be aborted */
mfy.param = param;
ret = mayfly_enqueue(TICKER_USER_ID_ULL_LOW,
TICKER_USER_ID_ULL_HIGH, 0, &mfy);
LL_ASSERT(!ret);
}
static void conn_disable(void *param)
{
struct ll_conn *conn;
struct ull_hdr *hdr;
/* Check ref count to determine if any pending LLL events in pipeline */
conn = param;
hdr = &conn->ull;
mfy.param = &conn->lll;
if (ull_ref_get(hdr)) {
static memq_link_t link;
static struct mayfly mfy = {0, 0, &link, NULL, lll_disable};
uint32_t ret;
mfy.param = &conn->lll;
/* Setup disabled callback to be called when ref count
* returns to zero.
*/
LL_ASSERT(!hdr->disabled_cb);
hdr->disabled_param = mfy.param;
hdr->disabled_cb = disabled_cb;
mfy.fp = lll_disable;
ret = mayfly_enqueue(TICKER_USER_ID_ULL_LOW,
/* Trigger LLL disable */
ret = mayfly_enqueue(TICKER_USER_ID_ULL_HIGH,
TICKER_USER_ID_LLL, 0, &mfy);
LL_ASSERT(!ret);
} else {
uint32_t ret;
mfy.fp = disabled_cb;
ret = mayfly_enqueue(TICKER_USER_ID_ULL_LOW,
TICKER_USER_ID_ULL_HIGH, 0, &mfy);
LL_ASSERT(!ret);
/* No pending LLL events */
disabled_cb(&conn->lll);
}
}