Skip to content

Commit 41e5774

Browse files
PavelVPVcvinayak
authored andcommitted
bluetooth: hci_driver: Fix deadlock in MPSL workq
This commit fixes deadlock in MPSL workq caused by bt_buf_get_rx with K_FOREVER. Previously, calling bt_buf_get_rx with K_FOREVER could block indefinitely if the requested pool had no available buffers. This blocking affected the MPSL work queue, preventing it from processing other work items, including critical timeslot events like MPSL_TIMESLOT_SIGNAL_CANCELLED and MPSL_TIMESLOT_SIGNAL_BLOCKED. The issue becomes more severe if a background flash operation coincides with this scenario. Flash operations often execute on the system work queue (sysworkq), which can delay host work items responsible for freeing buffers in the RX pool. In such cases: - Flash operations stall, waiting for a timeslot event from the MPSL work queue. - The MPSL work queue remains blocked by bt_buf_get_rx. - This results in a deadlock, causing the flash operation to timeout and triggering a warning. This commit modifies the HCI driver to call bt_buf_get_rx with K_NO_WAIT. If no buffer is immediately available, it relies on a callback to notify when a buffer is freed. This change ensures the MPSL work queue remains unblocked, allowing other work items to execute while waiting for a buffer. Signed-off-by: Pavel Vasilyev <[email protected]> (cherry picked from commit 52b6395) Signed-off-by: Vinayak Kariappa Chettimada <[email protected]>
1 parent 2fbfd50 commit 41e5774

File tree

1 file changed

+79
-32
lines changed

1 file changed

+79
-32
lines changed

subsys/bluetooth/controller/hci_driver.c

Lines changed: 79 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,23 @@ static inline void receive_signal_raise(void)
278278
mpsl_work_submit(&receive_work);
279279
}
280280

281+
/** Storage for HCI packets from controller to host */
282+
static struct {
283+
/* Buffer for the HCI packet. */
284+
uint8_t buf[HCI_RX_BUF_SIZE];
285+
/* Type of the HCI packet the buffer contains. */
286+
sdc_hci_msg_type_t type;
287+
} rx_hci_msg;
288+
289+
static void bt_buf_rx_freed_cb(enum bt_buf_type type_mask)
290+
{
291+
if (((rx_hci_msg.type == SDC_HCI_MSG_TYPE_EVT && (type_mask & BT_BUF_EVT) != 0u) ||
292+
(rx_hci_msg.type == SDC_HCI_MSG_TYPE_DATA && (type_mask & BT_BUF_ACL_IN) != 0u) ||
293+
(rx_hci_msg.type == SDC_HCI_MSG_TYPE_ISO && (type_mask & BT_BUF_ISO_IN) != 0u))) {
294+
receive_signal_raise();
295+
}
296+
}
297+
281298
static int cmd_handle(struct net_buf *cmd)
282299
{
283300
LOG_DBG("");
@@ -379,16 +396,16 @@ static int hci_driver_send(struct net_buf *buf)
379396
return err;
380397
}
381398

382-
static void data_packet_process(uint8_t *hci_buf)
399+
static int data_packet_process(uint8_t *hci_buf)
383400
{
384-
struct net_buf *data_buf = bt_buf_get_rx(BT_BUF_ACL_IN, K_FOREVER);
401+
struct net_buf *data_buf = bt_buf_get_rx(BT_BUF_ACL_IN, K_NO_WAIT);
385402
struct bt_hci_acl_hdr *hdr = (void *)hci_buf;
386403
uint16_t hf, handle, len;
387404
uint8_t flags, pb, bc;
388405

389406
if (!data_buf) {
390-
LOG_ERR("No data buffer available");
391-
return;
407+
LOG_DBG("No data buffer available");
408+
return -ENOBUFS;
392409
}
393410

394411
len = sys_le16_to_cpu(hdr->len);
@@ -402,35 +419,43 @@ static void data_packet_process(uint8_t *hci_buf)
402419
LOG_ERR("Event buffer too small. %u > %u",
403420
len + sizeof(*hdr),
404421
HCI_RX_BUF_SIZE);
405-
k_panic();
406-
return;
422+
return -ENOMEM;
407423
}
408424

409425
LOG_DBG("Data: handle (0x%02x), PB(%01d), BC(%01d), len(%u)", handle,
410426
pb, bc, len);
411427

412428
net_buf_add_mem(data_buf, &hci_buf[0], len + sizeof(*hdr));
429+
413430
bt_recv(data_buf);
431+
432+
return 0;
414433
}
415434

416-
static void iso_data_packet_process(uint8_t *hci_buf)
435+
static int iso_data_packet_process(uint8_t *hci_buf)
417436
{
418-
struct net_buf *data_buf = bt_buf_get_rx(BT_BUF_ISO_IN, K_FOREVER);
437+
struct net_buf *data_buf = bt_buf_get_rx(BT_BUF_ISO_IN, K_NO_WAIT);
419438
struct bt_hci_iso_hdr *hdr = (void *)hci_buf;
420439

421440
uint16_t len = sys_le16_to_cpu(hdr->len);
422441

442+
if (!data_buf) {
443+
LOG_DBG("No data buffer available");
444+
return -ENOBUFS;
445+
}
446+
423447
if (len + sizeof(*hdr) > HCI_RX_BUF_SIZE) {
424448
LOG_ERR("Event buffer too small. %u > %u",
425449
len + sizeof(*hdr),
426450
HCI_RX_BUF_SIZE);
427-
k_panic();
428-
return;
451+
return -ENOMEM;
429452
}
430453

431454
net_buf_add_mem(data_buf, &hci_buf[0], len + sizeof(*hdr));
432455

433456
bt_recv(data_buf);
457+
458+
return 0;
434459
}
435460

436461
static bool event_packet_is_discardable(const uint8_t *hci_buf)
@@ -475,7 +500,7 @@ static bool event_packet_is_discardable(const uint8_t *hci_buf)
475500
}
476501
}
477502

478-
static void event_packet_process(uint8_t *hci_buf)
503+
static int event_packet_process(uint8_t *hci_buf)
479504
{
480505
bool discardable = event_packet_is_discardable(hci_buf);
481506
struct bt_hci_evt_hdr *hdr = (void *)hci_buf;
@@ -485,8 +510,7 @@ static void event_packet_process(uint8_t *hci_buf)
485510
LOG_ERR("Event buffer too small. %u > %u",
486511
hdr->len + sizeof(*hdr),
487512
HCI_RX_BUF_SIZE);
488-
k_panic();
489-
return;
513+
return -ENOMEM;
490514
}
491515

492516
if (hdr->evt == BT_HCI_EVT_LE_META_EVENT) {
@@ -512,62 +536,81 @@ static void event_packet_process(uint8_t *hci_buf)
512536
LOG_DBG("Event (0x%02x) len %u", hdr->evt, hdr->len);
513537
}
514538

515-
evt_buf = bt_buf_get_evt(hdr->evt, discardable,
516-
discardable ? K_NO_WAIT : K_FOREVER);
539+
evt_buf = bt_buf_get_evt(hdr->evt, discardable, K_NO_WAIT);
517540

518541
if (!evt_buf) {
519542
if (discardable) {
520543
LOG_DBG("Discarding event");
521-
return;
544+
return 0;
522545
}
523546

524-
LOG_ERR("No event buffer available");
525-
return;
547+
LOG_DBG("No event buffer available");
548+
return -ENOBUFS;
526549
}
527550

528551
net_buf_add_mem(evt_buf, &hci_buf[0], hdr->len + sizeof(*hdr));
552+
529553
bt_recv(evt_buf);
554+
555+
return 0;
530556
}
531557

532-
static bool fetch_and_process_hci_msg(uint8_t *p_hci_buffer)
558+
static int fetch_hci_msg(uint8_t *p_hci_buffer, sdc_hci_msg_type_t *msg_type)
533559
{
534560
int errcode;
535-
sdc_hci_msg_type_t msg_type;
536561

537562
errcode = MULTITHREADING_LOCK_ACQUIRE();
538563
if (!errcode) {
539-
errcode = hci_internal_msg_get(p_hci_buffer, &msg_type);
564+
errcode = hci_internal_msg_get(p_hci_buffer, msg_type);
540565
MULTITHREADING_LOCK_RELEASE();
541566
}
542567

543-
if (errcode) {
544-
return false;
545-
}
568+
return errcode;
569+
}
570+
571+
static int process_hci_msg(uint8_t *p_hci_buffer, sdc_hci_msg_type_t msg_type)
572+
{
573+
int err;
546574

547575
if (msg_type == SDC_HCI_MSG_TYPE_EVT) {
548-
event_packet_process(p_hci_buffer);
576+
err = event_packet_process(p_hci_buffer);
549577
} else if (msg_type == SDC_HCI_MSG_TYPE_DATA) {
550-
data_packet_process(p_hci_buffer);
578+
err = data_packet_process(p_hci_buffer);
551579
} else if (msg_type == SDC_HCI_MSG_TYPE_ISO) {
552-
iso_data_packet_process(p_hci_buffer);
580+
err = iso_data_packet_process(p_hci_buffer);
553581
} else {
554582
if (!IS_ENABLED(CONFIG_BT_CTLR_SDC_SILENCE_UNEXPECTED_MSG_TYPE)) {
555583
LOG_ERR("Unexpected msg_type: %u. This if-else needs a new branch",
556584
msg_type);
557585
}
586+
err = 0;
558587
}
559588

560-
return true;
589+
return err;
561590
}
562591

563592
void hci_driver_receive_process(void)
564593
{
565-
static uint8_t hci_buf[HCI_RX_BUF_SIZE];
594+
int err;
566595

567-
if (fetch_and_process_hci_msg(&hci_buf[0])) {
568-
/* Let other threads of same priority run in between. */
569-
receive_signal_raise();
596+
if (rx_hci_msg.type == SDC_HCI_MSG_TYPE_NONE &&
597+
fetch_hci_msg(&rx_hci_msg.buf[0], &rx_hci_msg.type) != 0) {
598+
return;
599+
}
600+
601+
err = process_hci_msg(&rx_hci_msg.buf[0], rx_hci_msg.type);
602+
if (err == -ENOBUFS) {
603+
/* If we got -ENOBUFS, wait for the signal from the host. */
604+
return;
605+
} else if (err) {
606+
LOG_ERR("Unknown error when processing hci message %d", err);
607+
k_panic();
570608
}
609+
610+
rx_hci_msg.type = SDC_HCI_MSG_TYPE_NONE;
611+
612+
/* Let other threads of same priority run in between. */
613+
receive_signal_raise();
571614
}
572615

573616
static void receive_work_handler(struct k_work *work)
@@ -1297,6 +1340,8 @@ static int hci_driver_open(void)
12971340

12981341
MULTITHREADING_LOCK_RELEASE();
12991342

1343+
bt_buf_rx_freed_cb_set(bt_buf_rx_freed_cb);
1344+
13001345
return 0;
13011346
}
13021347

@@ -1329,6 +1374,8 @@ static int hci_driver_close(void)
13291374

13301375
MULTITHREADING_LOCK_RELEASE();
13311376

1377+
bt_buf_rx_freed_cb_set(NULL);
1378+
13321379
return err;
13331380
}
13341381

0 commit comments

Comments
 (0)