Skip to content

Commit 71ef6c6

Browse files
lylezhu2012kartben
authored andcommitted
Drivers: Bluetooth: H4: Use a semaphore to wake up HCI RX thread
There is an issue that the buffer cannot be allocated by the function `read_payload()` in UART ISR context. Then the UART RX will be disabled. The H4 driver hopes to get the receive buffer in the HCI RX thread and then open the UART RX again. However, there is a situation where the HCI RX thread is blocked in getting the received data buffer. However, since the UARt RX has been disabled, the HCI RX thread cannot get the received data buffer. Therefore, the RX thread is always blocked here, causing the Bluetooth host to not work properly. Add a semaphore `rx.ready` to notify new received data buffer has been added to H4 RX queue. Wait for the semaphore `rx.ready` instead of H4 RX queue in HCI RX thread. Wake up the HCI RX thread when failing to allocate the RX buffer. Fixes #89879. Signed-off-by: Lyle Zhu <[email protected]>
1 parent 74056a7 commit 71ef6c6

File tree

1 file changed

+24
-3
lines changed
  • drivers/bluetooth/hci

1 file changed

+24
-3
lines changed

drivers/bluetooth/hci/h4.c

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ struct h4_data {
3737
struct net_buf *buf;
3838
struct k_fifo fifo;
3939

40+
struct k_sem ready;
41+
4042
uint16_t remaining;
4143
uint16_t discard;
4244

@@ -257,8 +259,10 @@ static void rx_thread(void *p1, void *p2, void *p3)
257259
/* Let the ISR continue receiving new packets */
258260
uart_irq_rx_enable(cfg->uart);
259261

260-
buf = k_fifo_get(&h4->rx.fifo, K_FOREVER);
261-
do {
262+
k_sem_take(&h4->rx.ready, K_FOREVER);
263+
264+
buf = k_fifo_get(&h4->rx.fifo, K_NO_WAIT);
265+
while (buf != NULL) {
262266
uart_irq_rx_enable(cfg->uart);
263267

264268
LOG_DBG("Calling bt_recv(%p)", buf);
@@ -272,7 +276,7 @@ static void rx_thread(void *p1, void *p2, void *p3)
272276

273277
uart_irq_rx_disable(cfg->uart);
274278
buf = k_fifo_get(&h4->rx.fifo, K_NO_WAIT);
275-
} while (buf);
279+
}
276280
}
277281
}
278282

@@ -311,6 +315,18 @@ static inline void read_payload(const struct device *dev)
311315

312316
LOG_WRN("Failed to allocate, deferring to rx_thread");
313317
uart_irq_rx_disable(cfg->uart);
318+
/*
319+
* At this time, HCI UART RX is turned off, which means that no new
320+
* received data buffer will be put into the RX FIFO. This will cause
321+
* `rx.ready` to not be modified. It will probably remain unchanged and
322+
* the count of `rx.ready` will probably be 0.
323+
*
324+
* Since it is uncertain whether the RX thread is blocked waiting for
325+
* `rx.ready`, give a semaphore to try to wake up the RX thread.
326+
* Then there will be a renewed attempt at allocating an RX buffer in
327+
* the RX thread.
328+
*/
329+
k_sem_give(&h4->rx.ready);
314330
return;
315331
}
316332

@@ -352,6 +368,7 @@ static inline void read_payload(const struct device *dev)
352368

353369
LOG_DBG("Putting buf %p to rx fifo", buf);
354370
k_fifo_put(&h4->rx.fifo, buf);
371+
k_sem_give(&h4->rx.ready);
355372
}
356373

357374
static inline void read_header(const struct device *dev)
@@ -513,6 +530,9 @@ static int h4_open(const struct device *dev, bt_hci_recv_t recv)
513530
0, K_NO_WAIT);
514531
k_thread_name_set(tid, "bt_rx_thread");
515532

533+
/* Active rx_thread at first time */
534+
k_sem_give(&h4->rx.ready);
535+
516536
return 0;
517537
}
518538

@@ -585,6 +605,7 @@ static DEVICE_API(bt_hci, h4_driver_api) = {
585605
static struct h4_data h4_data_##inst = { \
586606
.rx = { \
587607
.fifo = Z_FIFO_INITIALIZER(h4_data_##inst.rx.fifo), \
608+
.ready = Z_SEM_INITIALIZER(h4_data_##inst.rx.ready, 0, 1), \
588609
}, \
589610
.tx = { \
590611
.fifo = Z_FIFO_INITIALIZER(h4_data_##inst.tx.fifo), \

0 commit comments

Comments
 (0)