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
  ****************************************************************************/

Reply via email to