Commit 929cf24a authored by Vinayak Kariappa Chettimada's avatar Vinayak Kariappa Chettimada Committed by Carles Cufi
Browse files

Bluetooth: Controller: Fix BIS 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: default avatarVinayak Kariappa Chettimada <vich@nordicsemi.no>
parent 2a1a14cf
Loading
Loading
Loading
Loading
+27 −16
Original line number Diff line number Diff line
@@ -59,6 +59,7 @@ static void ticker_cb(uint32_t ticks_at_expire, uint32_t ticks_drift,
		      void *param);
static void ticker_op_cb(uint32_t status, void *param);
static void ticker_stop_op_cb(uint32_t status, void *param);
static void adv_iso_disable(void *param);
static void disabled_cb(void *param);
static void tx_lll_flush(void *param);

@@ -860,37 +861,47 @@ static void ticker_op_cb(uint32_t status, void *param)
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};
	static struct mayfly mfy = {0, 0, &link, NULL, adv_iso_disable};
	uint32_t ret;

	LL_ASSERT(status == TICKER_STATUS_SUCCESS);

	/* 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 adv_iso_disable(void *param)
{
	struct ll_adv_iso_set *adv_iso;
	struct ull_hdr *hdr;

	/* 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 ref count to determine if any pending LLL events in pipeline */
	adv_iso = param;
	hdr = &adv_iso->ull;
	mfy.param = &adv_iso->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 = &adv_iso->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(&adv_iso->lll);
	}
}

+27 −18
Original line number Diff line number Diff line
@@ -52,6 +52,7 @@ static void ticker_cb(uint32_t ticks_at_expire, uint32_t ticks_drift,
static void ticker_start_op_cb(uint32_t status, void *param);
static void ticker_update_op_cb(uint32_t status, void *param);
static void ticker_stop_op_cb(uint32_t status, void *param);
static void sync_iso_disable(void *param);
static void disabled_cb(void *param);

static memq_link_t link_lll_prepare;
@@ -640,39 +641,47 @@ static void ticker_update_op_cb(uint32_t status, void *param)
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_sync_iso_set *sync_iso;
	struct ull_hdr *hdr;
	static struct mayfly mfy = {0, 0, &link, NULL, sync_iso_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 sync_iso_disable(void *param)
{
	struct ll_sync_iso_set *sync_iso;
	struct ull_hdr *hdr;

	/* Check ref count to determine if any pending LLL events in pipeline */
	sync_iso = param;
	hdr = &sync_iso->ull;
	mfy.param = &sync_iso->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 = &sync_iso->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(&sync_iso->lll);
	}
}