This is an automated email from the ASF dual-hosted git repository.
xiaoxiang781216 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git
The following commit(s) were added to refs/heads/master by this push:
new 57d384f466c arch/arm/nrf52,nrf53: don't pass HCI messages under the
lock
57d384f466c is described below
commit 57d384f466cf4cc36006714a06ace37171ba914e
Author: raiden00pl <[email protected]>
AuthorDate: Sat Jul 25 20:28:59 2026 +0200
arch/arm/nrf52,nrf53: don't pass HCI messages under the lock
on_hci() ran the host upcall with g_sdc_dev.lock held. On nrf53 this
deadlocks the BLE link: the upcall waits for the app core,
which cannot answer while bt_hci_send() blocks on the same lock.
nrf52 modified for consistency, deadlock is not possible there.
Signed-off-by: raiden00pl <[email protected]>
Assisted-by: Claude Code
---
arch/arm/src/nrf52/nrf52_sdc.c | 49 +++++++++++++++++++++---------------------
arch/arm/src/nrf53/nrf53_sdc.c | 49 +++++++++++++++++++++---------------------
2 files changed, 50 insertions(+), 48 deletions(-)
diff --git a/arch/arm/src/nrf52/nrf52_sdc.c b/arch/arm/src/nrf52/nrf52_sdc.c
index c0357cc33b4..0e11aac3280 100644
--- a/arch/arm/src/nrf52/nrf52_sdc.c
+++ b/arch/arm/src/nrf52/nrf52_sdc.c
@@ -181,10 +181,10 @@
struct nrf52_sdc_dev_s
{
uint8_t *mempool; /* Must be 8 bytes aligned */
- uint8_t msg_buffer[HCI_MSG_BUFFER_MAX_SIZE];
mutex_t lock;
struct work_s work;
+ struct work_s hci_work;
};
begin_packed_struct struct sdc_hci_cmd_vs_zephyr_write_bd_addr_s
@@ -308,7 +308,7 @@ static int bt_hci_send(struct bt_driver_s *btdev,
{
ret = len;
- work_queue(LPWORK, &g_sdc_dev.work, on_hci_worker, NULL, 0);
+ work_queue(LPWORK, &g_sdc_dev.hci_work, on_hci_worker, NULL, 0);
}
}
@@ -354,22 +354,7 @@ static void low_prio_worker(void *arg)
static void on_hci_worker(void *arg)
{
- /* We use this worker to force a call to on_hci() right after sending
- * an HCI command as MPSL/SDC does not always signal the low priority
- * worker
- */
-
- nxmutex_lock(&g_sdc_dev.lock);
- on_hci();
- nxmutex_unlock(&g_sdc_dev.lock);
-}
-
-/****************************************************************************
- * Name: on_hci
- ****************************************************************************/
-
-static void on_hci(void)
-{
+ uint8_t msg_buffer[HCI_MSG_BUFFER_MAX_SIZE];
sdc_hci_msg_type_t type;
bool check_again;
size_t len;
@@ -383,13 +368,16 @@ static void on_hci(void)
* buffer and then create an actual bt_buf_s, depending on msg length
*/
- ret = sdc_hci_get(g_sdc_dev.msg_buffer, &type);
+ nxmutex_lock(&g_sdc_dev.lock);
+ ret = sdc_hci_get(msg_buffer, &type);
+ nxmutex_unlock(&g_sdc_dev.lock);
+
if (ret == 0)
{
if (type == SDC_HCI_MSG_TYPE_EVT)
{
struct bt_hci_evt_hdr_s *hdr =
- (struct bt_hci_evt_hdr_s *)g_sdc_dev.msg_buffer;
+ (struct bt_hci_evt_hdr_s *)msg_buffer;
len = sizeof(*hdr) + hdr->len;
@@ -398,7 +386,7 @@ static void on_hci(void)
{
struct hci_evt_cmd_complete_s *cmd_complete =
(struct hci_evt_cmd_complete_s *)
- (g_sdc_dev.msg_buffer + sizeof(*hdr));
+ (msg_buffer + sizeof(*hdr));
uint8_t *status = (uint8_t *)cmd_complete + 3;
wlinfo("received CMD_COMPLETE from softdevice "
@@ -413,14 +401,14 @@ static void on_hci(void)
#endif
bt_netdev_receive(&g_bt_driver, BT_EVT,
- g_sdc_dev.msg_buffer, len);
+ msg_buffer, len);
check_again = true;
}
if (type == SDC_HCI_MSG_TYPE_DATA)
{
struct bt_hci_acl_hdr_s *hdr =
- (struct bt_hci_acl_hdr_s *)g_sdc_dev.msg_buffer;
+ (struct bt_hci_acl_hdr_s *)msg_buffer;
wlinfo("received HCI ACL from softdevice (handle: %d)\n",
hdr->handle);
@@ -428,7 +416,7 @@ static void on_hci(void)
len = sizeof(*hdr) + hdr->len;
bt_netdev_receive(&g_bt_driver, BT_ACL_IN,
- g_sdc_dev.msg_buffer, len);
+ msg_buffer, len);
check_again = true;
}
}
@@ -436,6 +424,19 @@ static void on_hci(void)
while (check_again);
}
+/****************************************************************************
+ * Name: on_hci
+ *
+ * Description:
+ * SDC message callback.
+ *
+ ****************************************************************************/
+
+static void on_hci(void)
+{
+ work_queue(LPWORK, &g_sdc_dev.hci_work, on_hci_worker, NULL, 0);
+}
+
/****************************************************************************
* Name: swi_isr
****************************************************************************/
diff --git a/arch/arm/src/nrf53/nrf53_sdc.c b/arch/arm/src/nrf53/nrf53_sdc.c
index 5ca4189feb6..a1ed1552c6d 100644
--- a/arch/arm/src/nrf53/nrf53_sdc.c
+++ b/arch/arm/src/nrf53/nrf53_sdc.c
@@ -182,10 +182,10 @@
struct nrf53_sdc_dev_s
{
uint8_t *mempool; /* Must be 8 bytes aligned */
- uint8_t msg_buffer[HCI_MSG_BUFFER_MAX_SIZE];
mutex_t lock;
struct work_s work;
+ struct work_s hci_work;
};
begin_packed_struct struct sdc_hci_cmd_vs_zephyr_write_bd_addr_s
@@ -309,7 +309,7 @@ static int bt_hci_send(struct bt_driver_s *btdev,
{
ret = len;
- work_queue(LPWORK, &g_sdc_dev.work, on_hci_worker, NULL, 0);
+ work_queue(LPWORK, &g_sdc_dev.hci_work, on_hci_worker, NULL, 0);
}
}
@@ -355,22 +355,7 @@ static void low_prio_worker(void *arg)
static void on_hci_worker(void *arg)
{
- /* We use this worker to force a call to on_hci() right after sending
- * an HCI command as MPSL/SDC does not always signal the low priority
- * worker
- */
-
- nxmutex_lock(&g_sdc_dev.lock);
- on_hci();
- nxmutex_unlock(&g_sdc_dev.lock);
-}
-
-/****************************************************************************
- * Name: on_hci
- ****************************************************************************/
-
-static void on_hci(void)
-{
+ uint8_t msg_buffer[HCI_MSG_BUFFER_MAX_SIZE];
sdc_hci_msg_type_t type;
bool check_again;
size_t len;
@@ -384,13 +369,16 @@ static void on_hci(void)
* buffer and then create an actual bt_buf_s, depending on msg length
*/
- ret = sdc_hci_get(g_sdc_dev.msg_buffer, &type);
+ nxmutex_lock(&g_sdc_dev.lock);
+ ret = sdc_hci_get(msg_buffer, &type);
+ nxmutex_unlock(&g_sdc_dev.lock);
+
if (ret == 0)
{
if (type == SDC_HCI_MSG_TYPE_EVT)
{
struct bt_hci_evt_hdr_s *hdr =
- (struct bt_hci_evt_hdr_s *)g_sdc_dev.msg_buffer;
+ (struct bt_hci_evt_hdr_s *)msg_buffer;
len = sizeof(*hdr) + hdr->len;
@@ -399,7 +387,7 @@ static void on_hci(void)
{
struct hci_evt_cmd_complete_s *cmd_complete =
(struct hci_evt_cmd_complete_s *)
- (g_sdc_dev.msg_buffer + sizeof(*hdr));
+ (msg_buffer + sizeof(*hdr));
uint8_t *status = (uint8_t *)cmd_complete + 3;
wlinfo("received CMD_COMPLETE from softdevice "
@@ -414,14 +402,14 @@ static void on_hci(void)
#endif
bt_netdev_receive(&g_bt_driver, BT_EVT,
- g_sdc_dev.msg_buffer, len);
+ msg_buffer, len);
check_again = true;
}
if (type == SDC_HCI_MSG_TYPE_DATA)
{
struct bt_hci_acl_hdr_s *hdr =
- (struct bt_hci_acl_hdr_s *)g_sdc_dev.msg_buffer;
+ (struct bt_hci_acl_hdr_s *)msg_buffer;
wlinfo("received HCI ACL from softdevice (handle: %d)\n",
hdr->handle);
@@ -429,7 +417,7 @@ static void on_hci(void)
len = sizeof(*hdr) + hdr->len;
bt_netdev_receive(&g_bt_driver, BT_ACL_IN,
- g_sdc_dev.msg_buffer, len);
+ msg_buffer, len);
check_again = true;
}
}
@@ -437,6 +425,19 @@ static void on_hci(void)
while (check_again);
}
+/****************************************************************************
+ * Name: on_hci
+ *
+ * Description:
+ * SDC message callback.
+ *
+ ****************************************************************************/
+
+static void on_hci(void)
+{
+ work_queue(LPWORK, &g_sdc_dev.hci_work, on_hci_worker, NULL, 0);
+}
+
/****************************************************************************
* Name: swi_isr
****************************************************************************/