Bluetooth: Controller: Add common ULL ticker stop with mark function

The same code block for marking an object with
ull_disable_mark, stopping the ticker and then unmarking
the object appeared multiple places; often with a regression
bug where instead of unmarking it in case of error, it would
be "remarked".

This commit fixes the bug, and moves the functionality to
a common function.

Signed-off-by: Emil Gydesen <emil.gydesen@nordicsemi.no>
This commit is contained in:
Emil Gydesen 2020-11-12 15:11:43 +01:00 committed by Carles Cufí
commit 6b72bed967
7 changed files with 74 additions and 102 deletions

View file

@ -1230,6 +1230,54 @@ void *ull_disable_mark_get(void)
return mark_get(mark_disable);
}
/**
* @brief Stops a specified ticker using the ull_disable_(un)mark functions.
*
* @param ticker_handle The handle of the ticker.
* @param param The object to mark.
* @param lll_disable Optional object when calling @ref ull_disable
*
* @return 0 if success, else ERRNO.
*/
int ull_ticker_stop_with_mark(uint8_t ticker_handle, void *param,
void *lll_disable)
{
uint32_t volatile ret_cb;
uint32_t ret;
void *mark;
mark = ull_disable_mark(param);
if (mark != param) {
return -ENOLCK;
}
ret_cb = TICKER_STATUS_BUSY;
ret = ticker_stop(TICKER_INSTANCE_ID_CTLR, TICKER_USER_ID_THREAD,
ticker_handle, ull_ticker_status_give,
(void *)&ret_cb);
ret = ull_ticker_status_take(ret, &ret_cb);
if (ret) {
mark = ull_disable_unmark(param);
if (mark != param) {
return -ENOLCK;
}
return -EALREADY;
}
ret = ull_disable(lll_disable);
if (ret) {
return -EBUSY;
}
mark = ull_disable_unmark(param);
if (mark != param) {
return -ENOLCK;
}
return 0;
}
#if defined(CONFIG_BT_CONN)
void *ull_update_mark(void *param)
{

View file

@ -866,34 +866,18 @@ uint32_t ull_adv_aux_start(struct ll_adv_aux_set *aux, uint32_t ticks_anchor,
uint8_t ull_adv_aux_stop(struct ll_adv_aux_set *aux)
{
uint32_t volatile ret_cb;
uint8_t aux_handle;
void *mark;
uint32_t ret;
mark = ull_disable_mark(aux);
LL_ASSERT(mark == aux);
int err;
aux_handle = aux_handle_get(aux);
ret_cb = TICKER_STATUS_BUSY;
ret = ticker_stop(TICKER_INSTANCE_ID_CTLR, TICKER_USER_ID_THREAD,
TICKER_ID_ADV_AUX_BASE + aux_handle,
ull_ticker_status_give, (void *)&ret_cb);
ret = ull_ticker_status_take(ret, &ret_cb);
if (ret) {
mark = ull_disable_mark(aux);
LL_ASSERT(mark == aux);
err = ull_ticker_stop_with_mark(TICKER_ID_ADV_AUX_BASE + aux_handle,
aux, &aux->lll);
LL_ASSERT(err == 0 || err == -EALREADY);
if (err) {
return BT_HCI_ERR_CMD_DISALLOWED;
}
ret = ull_disable(&aux->lll);
LL_ASSERT(!ret);
mark = ull_disable_unmark(aux);
LL_ASSERT(mark == aux);
aux->is_started = 0U;
return 0;

View file

@ -535,34 +535,18 @@ static inline uint16_t sync_handle_get(struct ll_adv_sync_set *sync)
static uint8_t sync_stop(struct ll_adv_sync_set *sync)
{
uint32_t volatile ret_cb;
uint8_t sync_handle;
void *mark;
uint32_t ret;
mark = ull_disable_mark(sync);
LL_ASSERT(mark == sync);
int err;
sync_handle = sync_handle_get(sync);
ret_cb = TICKER_STATUS_BUSY;
ret = ticker_stop(TICKER_INSTANCE_ID_CTLR, TICKER_USER_ID_THREAD,
TICKER_ID_ADV_SYNC_BASE + sync_handle,
ull_ticker_status_give, (void *)&ret_cb);
ret = ull_ticker_status_take(ret, &ret_cb);
if (ret) {
mark = ull_disable_mark(sync);
LL_ASSERT(mark == sync);
err = ull_ticker_stop_with_mark(TICKER_ID_ADV_SYNC_BASE + sync_handle,
sync, &sync->lll);
LL_ASSERT(err == 0 || err == -EALREADY);
if (err) {
return BT_HCI_ERR_CMD_DISALLOWED;
}
ret = ull_disable(&sync->lll);
LL_ASSERT(!ret);
mark = ull_disable_unmark(sync);
LL_ASSERT(mark == sync);
return 0;
}

View file

@ -1675,30 +1675,16 @@ static void ticker_op_stop_cb(uint32_t status, void *param)
static inline void disable(uint16_t handle)
{
uint32_t volatile ret_cb;
struct ll_conn *conn;
void *mark;
uint32_t ret;
int err;
conn = ll_conn_get(handle);
mark = ull_disable_mark(conn);
LL_ASSERT(mark == conn);
ret_cb = TICKER_STATUS_BUSY;
ret = ticker_stop(TICKER_INSTANCE_ID_CTLR, TICKER_USER_ID_THREAD,
TICKER_ID_CONN_BASE + handle,
ull_ticker_status_give, (void *)&ret_cb);
ret = ull_ticker_status_take(ret, &ret_cb);
if (!ret) {
ret = ull_disable(&conn->lll);
LL_ASSERT(!ret);
}
err = ull_ticker_stop_with_mark(TICKER_ID_CONN_BASE + handle,
conn, &conn->lll);
LL_ASSERT(err == 0 || err == -EALREADY);
conn->lll.link_tx_free = NULL;
mark = ull_disable_unmark(conn);
LL_ASSERT(mark == conn);
}
static void conn_cleanup(struct ll_conn *conn, uint8_t reason)

View file

@ -43,6 +43,8 @@ uint32_t ull_ticker_status_take(uint32_t ret, uint32_t volatile *ret_cb);
void *ull_disable_mark(void *param);
void *ull_disable_unmark(void *param);
void *ull_disable_mark_get(void);
int ull_ticker_stop_with_mark(uint8_t ticker_handle, void *param,
void *lll_disable);
void *ull_update_mark(void *param);
void *ull_update_unmark(void *param);
void *ull_update_mark_get(void);

View file

@ -448,31 +448,15 @@ uint8_t ull_scan_enable(struct ll_scan_set *scan)
uint8_t ull_scan_disable(uint8_t handle, struct ll_scan_set *scan)
{
uint32_t volatile ret_cb;
void *mark;
uint32_t ret;
mark = ull_disable_mark(scan);
LL_ASSERT(mark == scan);
ret_cb = TICKER_STATUS_BUSY;
ret = ticker_stop(TICKER_INSTANCE_ID_CTLR, TICKER_USER_ID_THREAD,
TICKER_ID_SCAN_BASE + handle,
ull_ticker_status_give, (void *)&ret_cb);
ret = ull_ticker_status_take(ret, &ret_cb);
if (ret) {
mark = ull_disable_unmark(scan);
LL_ASSERT(mark == scan);
int err;
err = ull_ticker_stop_with_mark(TICKER_ID_SCAN_BASE + handle,
scan, &scan->lll);
LL_ASSERT(err == 0 || err == -EALREADY);
if (err) {
return BT_HCI_ERR_CMD_DISALLOWED;
}
ret = ull_disable(&scan->lll);
LL_ASSERT(!ret);
mark = ull_disable_unmark(scan);
LL_ASSERT(mark == scan);
return 0;
}

View file

@ -235,36 +235,20 @@ uint8_t ll_sync_terminate(uint16_t handle)
{
memq_link_t *link_sync_lost;
struct ll_sync_set *sync;
uint32_t volatile ret_cb;
uint32_t ret;
void *mark;
int err;
sync = is_enabled_get(handle);
if (!sync) {
return BT_HCI_ERR_UNKNOWN_ADV_IDENTIFIER;
}
mark = ull_disable_mark(sync);
LL_ASSERT(mark == sync);
ret_cb = TICKER_STATUS_BUSY;
ret = ticker_stop(TICKER_INSTANCE_ID_CTLR, TICKER_USER_ID_THREAD,
TICKER_ID_SCAN_SYNC_BASE + handle,
ull_ticker_status_give, (void *)&ret_cb);
ret = ull_ticker_status_take(ret, &ret_cb);
if (ret) {
mark = ull_disable_mark(sync);
LL_ASSERT(mark == sync);
err = ull_ticker_stop_with_mark(TICKER_ID_SCAN_SYNC_BASE + handle,
sync, &sync->lll);
LL_ASSERT(err == 0 || err == -EALREADY);
if (err) {
return BT_HCI_ERR_CMD_DISALLOWED;
}
ret = ull_disable(&sync->lll);
LL_ASSERT(!ret);
mark = ull_disable_unmark(sync);
LL_ASSERT(mark == sync);
link_sync_lost = sync->node_rx_lost.hdr.link;
ll_rx_link_release(link_sync_lost);