Skip to content

Commit 52b6395

Browse files
PavelVPVrugeGerritsen
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]>
1 parent 5ae8809 commit 52b6395

File tree

1 file changed

+80
-35
lines changed

1 file changed

+80
-35
lines changed

subsys/bluetooth/controller/hci_driver.c

Lines changed: 80 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,23 @@ static inline void receive_signal_raise(void)
328328
mpsl_work_submit(&receive_work);
329329
}
330330

331+
/** Storage for HCI packets from controller to host */
332+
static struct {
333+
/* Buffer for the HCI packet. */
334+
uint8_t buf[HCI_RX_BUF_SIZE];
335+
/* Type of the HCI packet the buffer contains. */
336+
sdc_hci_msg_type_t type;
337+
} rx_hci_msg;
338+
339+
static void bt_buf_rx_freed_cb(enum bt_buf_type type_mask)
340+
{
341+
if (((rx_hci_msg.type == SDC_HCI_MSG_TYPE_EVT && (type_mask & BT_BUF_EVT) != 0u) ||
342+
(rx_hci_msg.type == SDC_HCI_MSG_TYPE_DATA && (type_mask & BT_BUF_ACL_IN) != 0u) ||
343+
(rx_hci_msg.type == SDC_HCI_MSG_TYPE_ISO && (type_mask & BT_BUF_ISO_IN) != 0u))) {
344+
receive_signal_raise();
345+
}
346+
}
347+
331348
static int cmd_handle(struct net_buf *cmd)
332349
{
333350
LOG_DBG("");
@@ -429,16 +446,16 @@ static int hci_driver_send(const struct device *dev, struct net_buf *buf)
429446
return err;
430447
}
431448

432-
static void data_packet_process(const struct device *dev, uint8_t *hci_buf)
449+
static int data_packet_process(const struct device *dev, uint8_t *hci_buf)
433450
{
434-
struct net_buf *data_buf = bt_buf_get_rx(BT_BUF_ACL_IN, K_FOREVER);
451+
struct net_buf *data_buf = bt_buf_get_rx(BT_BUF_ACL_IN, K_NO_WAIT);
435452
struct bt_hci_acl_hdr *hdr = (void *)hci_buf;
436453
uint16_t hf, handle, len;
437454
uint8_t flags, pb, bc;
438455

439456
if (!data_buf) {
440-
LOG_ERR("No data buffer available");
441-
return;
457+
LOG_DBG("No data buffer available");
458+
return -ENOBUFS;
442459
}
443460

444461
len = sys_le16_to_cpu(hdr->len);
@@ -452,8 +469,7 @@ static void data_packet_process(const struct device *dev, uint8_t *hci_buf)
452469
LOG_ERR("Event buffer too small. %u > %u",
453470
len + sizeof(*hdr),
454471
HCI_RX_BUF_SIZE);
455-
k_panic();
456-
return;
472+
return -ENOMEM;
457473
}
458474

459475
LOG_DBG("Data: handle (0x%02x), PB(%01d), BC(%01d), len(%u)", handle,
@@ -464,28 +480,36 @@ static void data_packet_process(const struct device *dev, uint8_t *hci_buf)
464480
struct hci_driver_data *driver_data = dev->data;
465481

466482
driver_data->recv_func(dev, data_buf);
483+
484+
return 0;
467485
}
468486

469-
static void iso_data_packet_process(const struct device *dev, uint8_t *hci_buf)
487+
static int iso_data_packet_process(const struct device *dev, uint8_t *hci_buf)
470488
{
471-
struct net_buf *data_buf = bt_buf_get_rx(BT_BUF_ISO_IN, K_FOREVER);
489+
struct net_buf *data_buf = bt_buf_get_rx(BT_BUF_ISO_IN, K_NO_WAIT);
472490
struct bt_hci_iso_hdr *hdr = (void *)hci_buf;
473491

474492
uint16_t len = sys_le16_to_cpu(hdr->len);
475493

494+
if (!data_buf) {
495+
LOG_DBG("No data buffer available");
496+
return -ENOBUFS;
497+
}
498+
476499
if (len + sizeof(*hdr) > HCI_RX_BUF_SIZE) {
477500
LOG_ERR("Event buffer too small. %u > %u",
478501
len + sizeof(*hdr),
479502
HCI_RX_BUF_SIZE);
480-
k_panic();
481-
return;
503+
return -ENOMEM;
482504
}
483505

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

486508
struct hci_driver_data *driver_data = dev->data;
487509

488-
driver_data->recv_func(dev, data_buf);
510+
(void)driver_data->recv_func(dev, data_buf);
511+
512+
return 0;
489513
}
490514

491515
static bool event_packet_is_discardable(const uint8_t *hci_buf)
@@ -532,7 +556,7 @@ static bool event_packet_is_discardable(const uint8_t *hci_buf)
532556
}
533557
}
534558

535-
static void event_packet_process(const struct device *dev, uint8_t *hci_buf)
559+
static int event_packet_process(const struct device *dev, uint8_t *hci_buf)
536560
{
537561
bool discardable = event_packet_is_discardable(hci_buf);
538562
struct bt_hci_evt_hdr *hdr = (void *)hci_buf;
@@ -542,8 +566,7 @@ static void event_packet_process(const struct device *dev, uint8_t *hci_buf)
542566
LOG_ERR("Event buffer too small. %u > %u",
543567
hdr->len + sizeof(*hdr),
544568
HCI_RX_BUF_SIZE);
545-
k_panic();
546-
return;
569+
return -ENOMEM;
547570
}
548571

549572
if (hdr->evt == BT_HCI_EVT_LE_META_EVENT) {
@@ -569,67 +592,85 @@ static void event_packet_process(const struct device *dev, uint8_t *hci_buf)
569592
LOG_DBG("Event (0x%02x) len %u", hdr->evt, hdr->len);
570593
}
571594

572-
evt_buf = bt_buf_get_evt(hdr->evt, discardable,
573-
discardable ? K_NO_WAIT : K_FOREVER);
595+
evt_buf = bt_buf_get_evt(hdr->evt, discardable, K_NO_WAIT);
574596

575597
if (!evt_buf) {
576598
if (discardable) {
577599
LOG_DBG("Discarding event");
578-
return;
600+
return 0;
579601
}
580602

581-
LOG_ERR("No event buffer available");
582-
return;
603+
LOG_DBG("No event buffer available");
604+
return -ENOBUFS;
583605
}
584606

585607
net_buf_add_mem(evt_buf, &hci_buf[0], hdr->len + sizeof(*hdr));
586608

587609
struct hci_driver_data *driver_data = dev->data;
588610

589-
driver_data->recv_func(dev, evt_buf);
611+
(void)driver_data->recv_func(dev, evt_buf);
612+
613+
return 0;
590614
}
591615

592-
static bool fetch_and_process_hci_msg(const struct device *dev, uint8_t *p_hci_buffer)
616+
static int fetch_hci_msg(uint8_t *p_hci_buffer, sdc_hci_msg_type_t *msg_type)
593617
{
594618
int errcode;
595-
sdc_hci_msg_type_t msg_type;
596619

597620
errcode = MULTITHREADING_LOCK_ACQUIRE();
598621
if (!errcode) {
599-
errcode = hci_internal_msg_get(p_hci_buffer, &msg_type);
622+
errcode = hci_internal_msg_get(p_hci_buffer, msg_type);
600623
MULTITHREADING_LOCK_RELEASE();
601624
}
602625

603-
if (errcode) {
604-
return false;
605-
}
626+
return errcode;
627+
}
628+
629+
static int process_hci_msg(const struct device *dev, uint8_t *p_hci_buffer,
630+
sdc_hci_msg_type_t msg_type)
631+
{
632+
int err;
606633

607634
if (msg_type == SDC_HCI_MSG_TYPE_EVT) {
608-
event_packet_process(dev, p_hci_buffer);
635+
err = event_packet_process(dev, p_hci_buffer);
609636
} else if (msg_type == SDC_HCI_MSG_TYPE_DATA) {
610-
data_packet_process(dev, p_hci_buffer);
637+
err = data_packet_process(dev, p_hci_buffer);
611638
} else if (msg_type == SDC_HCI_MSG_TYPE_ISO) {
612-
iso_data_packet_process(dev, p_hci_buffer);
639+
err = iso_data_packet_process(dev, p_hci_buffer);
613640
} else {
614641
if (!IS_ENABLED(CONFIG_BT_CTLR_SDC_SILENCE_UNEXPECTED_MSG_TYPE)) {
615642
LOG_ERR("Unexpected msg_type: %u. This if-else needs a new branch",
616643
msg_type);
617644
}
645+
err = 0;
618646
}
619647

620-
return true;
648+
return err;
621649
}
622650

623651
void hci_driver_receive_process(void)
624652
{
625-
static uint8_t hci_buf[HCI_RX_BUF_SIZE];
626-
627653
const struct device *dev = DEVICE_DT_GET(DT_DRV_INST(0));
654+
int err;
628655

629-
if (fetch_and_process_hci_msg(dev, &hci_buf[0])) {
630-
/* Let other threads of same priority run in between. */
631-
receive_signal_raise();
656+
if (rx_hci_msg.type == SDC_HCI_MSG_TYPE_NONE &&
657+
fetch_hci_msg(&rx_hci_msg.buf[0], &rx_hci_msg.type) != 0) {
658+
return;
659+
}
660+
661+
err = process_hci_msg(dev, &rx_hci_msg.buf[0], rx_hci_msg.type);
662+
if (err == -ENOBUFS) {
663+
/* If we got -ENOBUFS, wait for the signal from the host. */
664+
return;
665+
} else if (err) {
666+
LOG_ERR("Unknown error when processing hci message %d", err);
667+
k_panic();
632668
}
669+
670+
rx_hci_msg.type = SDC_HCI_MSG_TYPE_NONE;
671+
672+
/* Let other threads of same priority run in between. */
673+
receive_signal_raise();
633674
}
634675

635676
static void receive_work_handler(struct k_work *work)
@@ -1410,6 +1451,8 @@ static int hci_driver_open(const struct device *dev, bt_hci_recv_t recv_func)
14101451

14111452
driver_data->recv_func = recv_func;
14121453

1454+
bt_buf_rx_freed_cb_set(bt_buf_rx_freed_cb);
1455+
14131456
return 0;
14141457
}
14151458

@@ -1442,6 +1485,8 @@ static int hci_driver_close(const struct device *dev)
14421485

14431486
MULTITHREADING_LOCK_RELEASE();
14441487

1488+
bt_buf_rx_freed_cb_set(NULL);
1489+
14451490
return err;
14461491
}
14471492

0 commit comments

Comments
 (0)