Skip to content

Commit 5fd2fe6

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 d17ed46 commit 5fd2fe6

File tree

1 file changed

+112
-34
lines changed

1 file changed

+112
-34
lines changed

subsys/bluetooth/controller/hci_driver.c

Lines changed: 112 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,23 @@ static inline void receive_signal_raise(void)
270270
mpsl_work_submit(&receive_work);
271271
}
272272

273+
/** Storage for HCI packets from controller to host */
274+
static struct {
275+
/* Buffer for the HCI packet. */
276+
uint8_t buf[HCI_RX_BUF_SIZE];
277+
/* Type of the HCI packet the buffer contains. */
278+
sdc_hci_msg_type_t type;
279+
} rx_hci_msg;
280+
281+
static void bt_buf_rx_freed_cb(enum bt_buf_type type_mask)
282+
{
283+
if (((rx_hci_msg.type == SDC_HCI_MSG_TYPE_EVT && (type_mask & BT_BUF_EVT) != 0u) ||
284+
(rx_hci_msg.type == SDC_HCI_MSG_TYPE_DATA && (type_mask & BT_BUF_ACL_IN) != 0u) ||
285+
(rx_hci_msg.type == SDC_HCI_MSG_TYPE_ISO && (type_mask & BT_BUF_ISO_IN) != 0u))) {
286+
receive_signal_raise();
287+
}
288+
}
289+
273290
static int cmd_handle(struct net_buf *cmd)
274291
{
275292
LOG_DBG("");
@@ -371,16 +388,16 @@ static int hci_driver_send(struct net_buf *buf)
371388
return err;
372389
}
373390

374-
static void data_packet_process(uint8_t *hci_buf)
391+
static int data_packet_process(const struct device *dev, uint8_t *hci_buf)
375392
{
376-
struct net_buf *data_buf = bt_buf_get_rx(BT_BUF_ACL_IN, K_FOREVER);
393+
struct net_buf *data_buf = bt_buf_get_rx(BT_BUF_ACL_IN, K_NO_WAIT);
377394
struct bt_hci_acl_hdr *hdr = (void *)hci_buf;
378395
uint16_t hf, handle, len;
379396
uint8_t flags, pb, bc;
380397

381398
if (!data_buf) {
382-
LOG_ERR("No data buffer available");
383-
return;
399+
LOG_DBG("No data buffer available");
400+
return -ENOBUFS;
384401
}
385402

386403
len = sys_le16_to_cpu(hdr->len);
@@ -390,23 +407,51 @@ static void data_packet_process(uint8_t *hci_buf)
390407
pb = bt_acl_flags_pb(flags);
391408
bc = bt_acl_flags_bc(flags);
392409

410+
if (len + sizeof(*hdr) > HCI_RX_BUF_SIZE) {
411+
LOG_ERR("Event buffer too small. %u > %u",
412+
len + sizeof(*hdr),
413+
HCI_RX_BUF_SIZE);
414+
return -ENOMEM;
415+
}
416+
393417
LOG_DBG("Data: handle (0x%02x), PB(%01d), BC(%01d), len(%u)", handle,
394418
pb, bc, len);
395419

396420
net_buf_add_mem(data_buf, &hci_buf[0], len + sizeof(*hdr));
397-
bt_recv(data_buf);
421+
422+
struct hci_driver_data *driver_data = dev->data;
423+
424+
(void)driver_data->recv_func(dev, data_buf);
425+
426+
return 0;
398427
}
399428

400-
static void iso_data_packet_process(uint8_t *hci_buf)
429+
static int iso_data_packet_process(const struct device *dev, uint8_t *hci_buf)
401430
{
402-
struct net_buf *data_buf = bt_buf_get_rx(BT_BUF_ISO_IN, K_FOREVER);
431+
struct net_buf *data_buf = bt_buf_get_rx(BT_BUF_ISO_IN, K_NO_WAIT);
403432
struct bt_hci_iso_hdr *hdr = (void *)hci_buf;
404433

405434
uint16_t len = sys_le16_to_cpu(hdr->len);
406435

436+
if (!data_buf) {
437+
LOG_DBG("No data buffer available");
438+
return -ENOBUFS;
439+
}
440+
441+
if (len + sizeof(*hdr) > HCI_RX_BUF_SIZE) {
442+
LOG_ERR("Event buffer too small. %u > %u",
443+
len + sizeof(*hdr),
444+
HCI_RX_BUF_SIZE);
445+
return -ENOMEM;
446+
}
447+
407448
net_buf_add_mem(data_buf, &hci_buf[0], len + sizeof(*hdr));
408449

409-
bt_recv(data_buf);
450+
struct hci_driver_data *driver_data = dev->data;
451+
452+
(void)driver_data->recv_func(dev, data_buf);
453+
454+
return 0;
410455
}
411456

412457
static bool event_packet_is_discardable(const uint8_t *hci_buf)
@@ -451,12 +496,19 @@ static bool event_packet_is_discardable(const uint8_t *hci_buf)
451496
}
452497
}
453498

454-
static void event_packet_process(uint8_t *hci_buf)
499+
static int event_packet_process(const struct device *dev, uint8_t *hci_buf)
455500
{
456501
bool discardable = event_packet_is_discardable(hci_buf);
457502
struct bt_hci_evt_hdr *hdr = (void *)hci_buf;
458503
struct net_buf *evt_buf;
459504

505+
if (hdr->len + sizeof(*hdr) > HCI_RX_BUF_SIZE) {
506+
LOG_ERR("Event buffer too small. %u > %u",
507+
hdr->len + sizeof(*hdr),
508+
HCI_RX_BUF_SIZE);
509+
return -ENOMEM;
510+
}
511+
460512
if (hdr->evt == BT_HCI_EVT_LE_META_EVENT) {
461513
struct bt_hci_evt_le_meta_event *me = (void *)&hci_buf[2];
462514

@@ -480,67 +532,85 @@ static void event_packet_process(uint8_t *hci_buf)
480532
LOG_DBG("Event (0x%02x) len %u", hdr->evt, hdr->len);
481533
}
482534

483-
evt_buf = bt_buf_get_evt(hdr->evt, discardable,
484-
discardable ? K_NO_WAIT : K_FOREVER);
535+
evt_buf = bt_buf_get_evt(hdr->evt, discardable, K_NO_WAIT);
485536

486537
if (!evt_buf) {
487538
if (discardable) {
488539
LOG_DBG("Discarding event");
489-
return;
540+
return 0;
490541
}
491542

492-
LOG_ERR("No event buffer available");
493-
return;
543+
LOG_DBG("No event buffer available");
544+
return -ENOBUFS;
494545
}
495546

496547
net_buf_add_mem(evt_buf, &hci_buf[0], hdr->len + sizeof(*hdr));
497-
bt_recv(evt_buf);
548+
549+
struct hci_driver_data *driver_data = dev->data;
550+
551+
(void)driver_data->recv_func(dev, evt_buf);
552+
553+
return 0;
498554
}
499555

500-
static bool fetch_and_process_hci_msg(uint8_t *p_hci_buffer)
556+
static int fetch_hci_msg(uint8_t *p_hci_buffer, sdc_hci_msg_type_t *msg_type)
501557
{
502558
int errcode;
503-
sdc_hci_msg_type_t msg_type;
504559

505560
errcode = MULTITHREADING_LOCK_ACQUIRE();
506561
if (!errcode) {
507-
errcode = hci_internal_msg_get(p_hci_buffer, &msg_type);
562+
errcode = hci_internal_msg_get(p_hci_buffer, msg_type);
508563
MULTITHREADING_LOCK_RELEASE();
509564
}
510565

511-
if (errcode) {
512-
return false;
513-
}
566+
return errcode;
567+
}
568+
569+
static int process_hci_msg(const struct device *dev, uint8_t *p_hci_buffer,
570+
sdc_hci_msg_type_t msg_type)
571+
{
572+
int err;
514573

515574
if (msg_type == SDC_HCI_MSG_TYPE_EVT) {
516-
event_packet_process(p_hci_buffer);
575+
err = event_packet_process(dev, p_hci_buffer);
517576
} else if (msg_type == SDC_HCI_MSG_TYPE_DATA) {
518-
data_packet_process(p_hci_buffer);
577+
err = data_packet_process(dev, p_hci_buffer);
519578
} else if (msg_type == SDC_HCI_MSG_TYPE_ISO) {
520-
iso_data_packet_process(p_hci_buffer);
579+
err = iso_data_packet_process(dev, p_hci_buffer);
521580
} else {
522581
if (!IS_ENABLED(CONFIG_BT_CTLR_SDC_SILENCE_UNEXPECTED_MSG_TYPE)) {
523582
LOG_ERR("Unexpected msg_type: %u. This if-else needs a new branch",
524583
msg_type);
525584
}
585+
err = 0;
526586
}
527587

528-
return true;
588+
return err;
529589
}
530590

531591
void hci_driver_receive_process(void)
532592
{
533-
#if defined(CONFIG_BT_BUF_EVT_DISCARDABLE_COUNT)
534-
static uint8_t hci_buf[MAX(BT_BUF_RX_SIZE,
535-
BT_BUF_EVT_SIZE(CONFIG_BT_BUF_EVT_DISCARDABLE_SIZE))];
536-
#else
537-
static uint8_t hci_buf[BT_BUF_RX_SIZE];
538-
#endif
593+
const struct device *dev = DEVICE_DT_GET(DT_DRV_INST(0));
594+
int err;
539595

540-
if (fetch_and_process_hci_msg(&hci_buf[0])) {
541-
/* Let other threads of same priority run in between. */
542-
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;
543599
}
600+
601+
err = process_hci_msg(dev, &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();
608+
}
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();
544614
}
545615

546616
static void receive_work_handler(struct k_work *work)
@@ -1270,6 +1340,12 @@ static int hci_driver_open(void)
12701340

12711341
MULTITHREADING_LOCK_RELEASE();
12721342

1343+
struct hci_driver_data *driver_data = dev->data;
1344+
1345+
(void)driver_data->recv_func = recv_func;
1346+
1347+
bt_buf_rx_freed_cb_set(bt_buf_rx_freed_cb);
1348+
12731349
return 0;
12741350
}
12751351

@@ -1302,6 +1378,8 @@ static int hci_driver_close(void)
13021378

13031379
MULTITHREADING_LOCK_RELEASE();
13041380

1381+
bt_buf_rx_freed_cb_set(NULL);
1382+
13051383
return err;
13061384
}
13071385

0 commit comments

Comments
 (0)