Skip to content

Commit b1913fb

Browse files
ubiedanashif
authored andcommitted
drivers: serial: bt: Use dedicated Workqueue
Stop relying on the system workqueue, as the BT TX APIs should potentially block and now by design this will not work with the Bluetooth Stack (for good reasons). Now the UART NUS driver has a dedicated workqueue, which all NUS instances share. Signed-off-by: Luis Ubieda <luisf@croxel.com>
1 parent cd6c948 commit b1913fb

File tree

1 file changed

+24
-7
lines changed

1 file changed

+24
-7
lines changed

drivers/serial/uart_bt.c

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
* SPDX-License-Identifier: Apache-2.0
55
*/
66

7+
#include <zephyr/kernel.h>
78
#include <zephyr/drivers/uart.h>
89
#include <zephyr/sys/ring_buffer.h>
910
#include <zephyr/sys/atomic.h>
@@ -14,6 +15,9 @@
1415
#include <zephyr/logging/log.h>
1516
LOG_MODULE_REGISTER(uart_nus, CONFIG_UART_LOG_LEVEL);
1617

18+
K_THREAD_STACK_DEFINE(nus_work_queue_stack, 2048);
19+
static struct k_work_q nus_work_queue;
20+
1721
struct uart_bt_data {
1822
struct {
1923
struct bt_nus_inst *inst;
@@ -47,7 +51,7 @@ static void bt_notif_enabled(bool enabled, void *ctx)
4751
LOG_DBG("%s() - %s", __func__, enabled ? "enabled" : "disabled");
4852

4953
if (!ring_buf_is_empty(dev_data->uart.tx_ringbuf)) {
50-
k_work_reschedule(&dev_data->uart.tx_work, K_NO_WAIT);
54+
k_work_reschedule_for_queue(&nus_work_queue, &dev_data->uart.tx_work, K_NO_WAIT);
5155
}
5256
}
5357

@@ -71,7 +75,7 @@ static void bt_received(struct bt_conn *conn, const void *data, uint16_t len, vo
7175
LOG_ERR("RX Ring buffer full. received: %d, added to queue: %d", len, put_len);
7276
}
7377

74-
k_work_submit(&dev_data->uart.cb_work);
78+
k_work_submit_to_queue(&nus_work_queue, &dev_data->uart.cb_work);
7579
}
7680

7781
static void cb_work_handler(struct k_work *work)
@@ -113,7 +117,7 @@ static void tx_work_handler(struct k_work *work)
113117
} while (len > 0 && !err);
114118

115119
if ((ring_buf_space_get(dev_data->uart.tx_ringbuf) > 0) && dev_data->uart.tx_irq_ena) {
116-
k_work_submit(&dev_data->uart.cb_work);
120+
k_work_submit_to_queue(&nus_work_queue, &dev_data->uart.cb_work);
117121
}
118122
}
119123

@@ -128,7 +132,7 @@ static int uart_bt_fifo_fill(const struct device *dev, const uint8_t *tx_data, i
128132
}
129133

130134
if (atomic_get(&dev_data->bt.enabled)) {
131-
k_work_reschedule(&dev_data->uart.tx_work, K_NO_WAIT);
135+
k_work_reschedule_for_queue(&nus_work_queue, &dev_data->uart.tx_work, K_NO_WAIT);
132136
}
133137

134138
return wrote;
@@ -169,7 +173,7 @@ static void uart_bt_poll_out(const struct device *dev, unsigned char c)
169173
* data, so more than one byte is transmitted (e.g: when poll_out is
170174
* called inside a for-loop).
171175
*/
172-
k_work_schedule(&dev_data->uart.tx_work, K_MSEC(1));
176+
k_work_schedule_for_queue(&nus_work_queue, &dev_data->uart.tx_work, K_MSEC(1));
173177
}
174178
}
175179

@@ -191,7 +195,7 @@ static void uart_bt_irq_tx_enable(const struct device *dev)
191195
dev_data->uart.tx_irq_ena = true;
192196

193197
if (uart_bt_irq_tx_ready(dev)) {
194-
k_work_submit(&dev_data->uart.cb_work);
198+
k_work_submit_to_queue(&nus_work_queue, &dev_data->uart.cb_work);
195199
}
196200
}
197201

@@ -219,7 +223,7 @@ static void uart_bt_irq_rx_enable(const struct device *dev)
219223

220224
dev_data->uart.rx_irq_ena = true;
221225

222-
k_work_submit(&dev_data->uart.cb_work);
226+
k_work_submit_to_queue(&nus_work_queue, &dev_data->uart.cb_work);
223227
}
224228

225229
static void uart_bt_irq_rx_disable(const struct device *dev)
@@ -267,6 +271,19 @@ static const struct uart_driver_api uart_bt_driver_api = {
267271
.irq_callback_set = uart_bt_irq_callback_set,
268272
};
269273

274+
static int uart_bt_workqueue_init(void)
275+
{
276+
k_work_queue_init(&nus_work_queue);
277+
k_work_queue_start(&nus_work_queue, nus_work_queue_stack,
278+
K_THREAD_STACK_SIZEOF(nus_work_queue_stack),
279+
K_LOWEST_APPLICATION_THREAD_PRIO, NULL);
280+
281+
return 0;
282+
}
283+
284+
/** The work-queue is shared across all instances, hence we initialize it separatedly */
285+
SYS_INIT(uart_bt_workqueue_init, POST_KERNEL, CONFIG_SERIAL_INIT_PRIORITY);
286+
270287
static int uart_bt_init(const struct device *dev)
271288
{
272289
int err;

0 commit comments

Comments
 (0)