Bluetooth: controller: Add lock around LLCP data

Add mayfly locking around the access to the local pending procedure list
as it is accessed by both thread and mayfly.

Fixes #45427

Signed-off-by: Thomas Ebert Hansen <thoh@oticon.com>
This commit is contained in:
Thomas Ebert Hansen 2022-11-15 09:59:49 +01:00 committed by Carles Cufí
commit f192fccf3a
5 changed files with 110 additions and 10 deletions

View file

@ -24,12 +24,26 @@ void mayfly_enable_cb(uint8_t caller_id, uint8_t callee_id, uint8_t enable)
{ {
(void)caller_id; (void)caller_id;
LL_ASSERT(callee_id == MAYFLY_CALL_ID_JOB); switch (callee_id) {
case MAYFLY_CALL_ID_WORKER:
if (enable) {
irq_enable(HAL_SWI_WORKER_IRQ);
} else {
irq_disable(HAL_SWI_WORKER_IRQ);
}
break;
if (enable) { case MAYFLY_CALL_ID_JOB:
irq_enable(HAL_SWI_JOB_IRQ); if (enable) {
} else { irq_enable(HAL_SWI_JOB_IRQ);
irq_disable(HAL_SWI_JOB_IRQ); } else {
irq_disable(HAL_SWI_JOB_IRQ);
}
break;
default:
LL_ASSERT(0);
break;
} }
} }
@ -101,3 +115,8 @@ void mayfly_pend(uint8_t caller_id, uint8_t callee_id)
break; break;
} }
} }
uint32_t mayfly_is_running(void)
{
return k_is_in_isr();
}

View file

@ -29,12 +29,26 @@ void mayfly_enable_cb(uint8_t caller_id, uint8_t callee_id, uint8_t enable)
{ {
(void)caller_id; (void)caller_id;
LL_ASSERT(callee_id == MAYFLY_CALL_ID_JOB); switch (callee_id) {
case MAYFLY_CALL_ID_WORKER:
if (enable) {
irq_enable(HAL_SWI_WORKER_IRQ);
} else {
irq_disable(HAL_SWI_WORKER_IRQ);
}
break;
if (enable) { case MAYFLY_CALL_ID_JOB:
irq_enable(HAL_SWI_JOB_IRQ); if (enable) {
} else { irq_enable(HAL_SWI_JOB_IRQ);
irq_disable(HAL_SWI_JOB_IRQ); } else {
irq_disable(HAL_SWI_JOB_IRQ);
}
break;
default:
LL_ASSERT(0);
break;
} }
} }
@ -112,3 +126,8 @@ void mayfly_pend(uint8_t caller_id, uint8_t callee_id)
break; break;
} }
} }
uint32_t mayfly_is_running(void)
{
return k_is_in_isr();
}

View file

@ -16,6 +16,7 @@
#include "util/util.h" #include "util/util.h"
#include "util/mem.h" #include "util/mem.h"
#include "util/memq.h" #include "util/memq.h"
#include "util/mayfly.h"
#include "util/dbuf.h" #include "util/dbuf.h"
#include "pdu.h" #include "pdu.h"
@ -81,6 +82,35 @@ static void lr_check_done(struct ll_conn *conn, struct proc_ctx *ctx)
llcp_proc_ctx_release(ctx); llcp_proc_ctx_release(ctx);
} }
} }
/*
* LLCP Local Request Shared Data Locking
*/
static ALWAYS_INLINE uint32_t shared_data_access_lock(void)
{
bool enabled;
if (mayfly_is_running()) {
/* We are in Mayfly context, nothing to be done */
return false;
}
/* We are in thread context and have to disable TICKER_USER_ID_ULL_HIGH */
enabled = mayfly_is_enabled(TICKER_USER_ID_THREAD, TICKER_USER_ID_ULL_HIGH) != 0U;
mayfly_enable(TICKER_USER_ID_THREAD, TICKER_USER_ID_ULL_HIGH, 0U);
return enabled;
}
static ALWAYS_INLINE void shared_data_access_unlock(bool key)
{
if (key) {
/* We are in thread context and have to reenable TICKER_USER_ID_ULL_HIGH */
mayfly_enable(TICKER_USER_ID_THREAD, TICKER_USER_ID_ULL_HIGH, 1U);
}
}
/* /*
* LLCP Local Request FSM * LLCP Local Request FSM
*/ */
@ -92,22 +122,48 @@ static void lr_set_state(struct ll_conn *conn, enum lr_state state)
void llcp_lr_enqueue(struct ll_conn *conn, struct proc_ctx *ctx) void llcp_lr_enqueue(struct ll_conn *conn, struct proc_ctx *ctx)
{ {
/* This function is called from both Thread and Mayfly (ISR),
* make sure only a single context have access at a time.
*/
bool key = shared_data_access_lock();
sys_slist_append(&conn->llcp.local.pend_proc_list, &ctx->node); sys_slist_append(&conn->llcp.local.pend_proc_list, &ctx->node);
shared_data_access_unlock(key);
} }
static struct proc_ctx *lr_dequeue(struct ll_conn *conn) static struct proc_ctx *lr_dequeue(struct ll_conn *conn)
{ {
/* This function is called from both Thread and Mayfly (ISR),
* make sure only a single context have access at a time.
*/
struct proc_ctx *ctx; struct proc_ctx *ctx;
bool key = shared_data_access_lock();
ctx = (struct proc_ctx *)sys_slist_get(&conn->llcp.local.pend_proc_list); ctx = (struct proc_ctx *)sys_slist_get(&conn->llcp.local.pend_proc_list);
shared_data_access_unlock(key);
return ctx; return ctx;
} }
struct proc_ctx *llcp_lr_peek(struct ll_conn *conn) struct proc_ctx *llcp_lr_peek(struct ll_conn *conn)
{ {
/* This function is called from both Thread and Mayfly (ISR),
* make sure only a single context have access at a time.
*/
struct proc_ctx *ctx; struct proc_ctx *ctx;
bool key = shared_data_access_lock();
ctx = (struct proc_ctx *)sys_slist_peek_head(&conn->llcp.local.pend_proc_list); ctx = (struct proc_ctx *)sys_slist_peek_head(&conn->llcp.local.pend_proc_list);
shared_data_access_unlock(key);
return ctx; return ctx;
} }

View file

@ -30,3 +30,4 @@ extern void mayfly_enable_cb(uint8_t caller_id, uint8_t callee_id, uint8_t enabl
extern uint32_t mayfly_is_enabled(uint8_t caller_id, uint8_t callee_id); extern uint32_t mayfly_is_enabled(uint8_t caller_id, uint8_t callee_id);
extern uint32_t mayfly_prio_is_equal(uint8_t caller_id, uint8_t callee_id); extern uint32_t mayfly_prio_is_equal(uint8_t caller_id, uint8_t callee_id);
extern void mayfly_pend(uint8_t caller_id, uint8_t callee_id); extern void mayfly_pend(uint8_t caller_id, uint8_t callee_id);
extern uint32_t mayfly_is_running(void);

View file

@ -31,3 +31,8 @@ uint32_t mayfly_enqueue(uint8_t caller_id, uint8_t callee_id, uint8_t chain, str
void mayfly_run(uint8_t callee_id) void mayfly_run(uint8_t callee_id)
{ {
} }
uint32_t mayfly_is_running(void)
{
return 0U;
}