Skip to content

Commit 66b53a9

Browse files
MarekPietarlubos
authored andcommitted
[nrf fromtree] bluetooth: conn: Use a separate workqueue for connection TX notify
Use a separate workqueue instead of system workqueue for connection TX notify processing. This makes Bluetooth stack more independent from the system workqueue. Signed-off-by: Marek Pieta <[email protected]> (cherry picked from commit 341f1f5)
1 parent d02b0d9 commit 66b53a9

File tree

4 files changed

+99
-37
lines changed

4 files changed

+99
-37
lines changed

subsys/bluetooth/host/Kconfig

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,35 @@ config BT_DRIVER_RX_HIGH_PRIO
129129
int
130130
default 6
131131

132+
config BT_CONN_TX_NOTIFY_WQ
133+
bool "Use a separate workqueue for connection TX notify processing [EXPERIMENTAL]"
134+
depends on BT_CONN_TX
135+
select EXPERIMENTAL
136+
help
137+
Use a separate workqueue instead of system workqueue for
138+
bt_conn_tx_notify processing. The option can be used to make Bluetooth
139+
stack more independent from the system workqueue.
140+
141+
if BT_CONN_TX_NOTIFY_WQ
142+
143+
config BT_CONN_TX_NOTIFY_WQ_STACK_SIZE
144+
int "Stack size of workqueue for connection TX notify processing"
145+
default SYSTEM_WORKQUEUE_STACK_SIZE
146+
147+
config BT_CONN_TX_NOTIFY_WQ_PRIO
148+
int "Cooperative priority of workqueue for connection TX notify processing"
149+
default 8
150+
151+
config BT_CONN_TX_NOTIFY_WQ_INIT_PRIORITY
152+
int "Init priority of workqueue for connection TX notify processing"
153+
default 50
154+
help
155+
The connection TX notify processing workqueue is initialized during
156+
system initialization (at POST_KERNEL level). The Kconfig option
157+
controls the initialization priority within level.
158+
159+
endif # BT_CONN_TX_NOTIFY_WQ
160+
132161
menu "Bluetooth Host"
133162

134163
if BT_HCI_HOST

subsys/bluetooth/host/conn.c

Lines changed: 67 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,11 @@ LOG_MODULE_REGISTER(bt_conn);
5252

5353
K_FIFO_DEFINE(free_tx);
5454

55+
#if defined(CONFIG_BT_CONN_TX_NOTIFY_WQ)
56+
static struct k_work_q conn_tx_workq;
57+
static K_KERNEL_STACK_DEFINE(conn_tx_workq_thread_stack, CONFIG_BT_CONN_TX_NOTIFY_WQ_STACK_SIZE);
58+
#endif /* CONFIG_BT_CONN_TX_NOTIFY_WQ */
59+
5560
static void tx_free(struct bt_conn_tx *tx);
5661

5762
static void conn_tx_destroy(struct bt_conn *conn, struct bt_conn_tx *tx)
@@ -254,12 +259,21 @@ static void tx_free(struct bt_conn_tx *tx)
254259
}
255260

256261
#if defined(CONFIG_BT_CONN_TX)
257-
static void tx_notify(struct bt_conn *conn)
262+
static struct k_work_q *tx_notify_workqueue_get(void)
258263
{
259-
__ASSERT_NO_MSG(k_current_get() ==
260-
k_work_queue_thread_get(&k_sys_work_q));
264+
#if defined(CONFIG_BT_CONN_TX_NOTIFY_WQ)
265+
return &conn_tx_workq;
266+
#else
267+
return &k_sys_work_q;
268+
#endif /* CONFIG_BT_CONN_TX_NOTIFY_WQ */
269+
}
261270

262-
LOG_DBG("conn %p", conn);
271+
static void tx_notify_process(struct bt_conn *conn)
272+
{
273+
/* TX notify processing is done only from a single thread. */
274+
__ASSERT_NO_MSG(k_current_get() == k_work_queue_thread_get(tx_notify_workqueue_get()));
275+
276+
LOG_DBG("conn %p", (void *)conn);
263277

264278
while (1) {
265279
struct bt_conn_tx *tx = NULL;
@@ -300,7 +314,30 @@ static void tx_notify(struct bt_conn *conn)
300314
bt_tx_irq_raise();
301315
}
302316
}
303-
#endif /* CONFIG_BT_CONN_TX */
317+
#endif /* CONFIG_BT_CONN_TX */
318+
319+
void bt_conn_tx_notify(struct bt_conn *conn, bool wait_for_completion)
320+
{
321+
#if defined(CONFIG_BT_CONN_TX)
322+
/* Ensure that function is called only from a single context. */
323+
if (k_current_get() == k_work_queue_thread_get(tx_notify_workqueue_get())) {
324+
tx_notify_process(conn);
325+
} else {
326+
struct k_work_sync sync;
327+
int err;
328+
329+
err = k_work_submit_to_queue(tx_notify_workqueue_get(), &conn->tx_complete_work);
330+
__ASSERT(err >= 0, "couldn't submit (err %d)", err);
331+
332+
if (wait_for_completion) {
333+
(void)k_work_flush(&conn->tx_complete_work, &sync);
334+
}
335+
}
336+
#else
337+
ARG_UNUSED(conn);
338+
ARG_UNUSED(wait_for_completion);
339+
#endif /* CONFIG_BT_CONN_TX */
340+
}
304341

305342
struct bt_conn *bt_conn_new(struct bt_conn *conns, size_t size)
306343
{
@@ -439,38 +476,15 @@ static void bt_acl_recv(struct bt_conn *conn, struct net_buf *buf, uint8_t flags
439476
bt_l2cap_recv(conn, buf, true);
440477
}
441478

442-
static void wait_for_tx_work(struct bt_conn *conn)
443-
{
444-
#if defined(CONFIG_BT_CONN_TX)
445-
LOG_DBG("conn %p", conn);
446-
447-
if (IS_ENABLED(CONFIG_BT_RECV_WORKQ_SYS) ||
448-
k_current_get() == k_work_queue_thread_get(&k_sys_work_q)) {
449-
tx_notify(conn);
450-
} else {
451-
struct k_work_sync sync;
452-
int err;
453-
454-
err = k_work_submit(&conn->tx_complete_work);
455-
__ASSERT(err >= 0, "couldn't submit (err %d)", err);
456-
457-
k_work_flush(&conn->tx_complete_work, &sync);
458-
}
459-
LOG_DBG("done");
460-
#else
461-
ARG_UNUSED(conn);
462-
#endif /* CONFIG_BT_CONN_TX */
463-
}
464-
465479
void bt_conn_recv(struct bt_conn *conn, struct net_buf *buf, uint8_t flags)
466480
{
467481
/* Make sure we notify any pending TX callbacks before processing
468482
* new data for this connection.
469483
*
470484
* Always do so from the same context for sanity. In this case that will
471-
* be the system workqueue.
485+
* be either a dedicated Bluetooth connection TX workqueue or system workqueue.
472486
*/
473-
wait_for_tx_work(conn);
487+
bt_conn_tx_notify(conn, true);
474488

475489
LOG_DBG("handle %u len %u flags %02x", conn->handle, buf->len, flags);
476490

@@ -1250,7 +1264,7 @@ void bt_conn_set_state(struct bt_conn *conn, bt_conn_state_t state)
12501264
*/
12511265
switch (old_state) {
12521266
case BT_CONN_DISCONNECT_COMPLETE:
1253-
wait_for_tx_work(conn);
1267+
bt_conn_tx_notify(conn, true);
12541268

12551269
bt_conn_reset_rx_state(conn);
12561270

@@ -1641,12 +1655,9 @@ struct net_buf *bt_conn_create_pdu_timeout(struct net_buf_pool *pool,
16411655
#if defined(CONFIG_BT_CONN_TX)
16421656
static void tx_complete_work(struct k_work *work)
16431657
{
1644-
struct bt_conn *conn = CONTAINER_OF(work, struct bt_conn,
1645-
tx_complete_work);
1658+
struct bt_conn *conn = CONTAINER_OF(work, struct bt_conn, tx_complete_work);
16461659

1647-
LOG_DBG("conn %p", conn);
1648-
1649-
tx_notify(conn);
1660+
tx_notify_process(conn);
16501661
}
16511662
#endif /* CONFIG_BT_CONN_TX */
16521663

@@ -4171,3 +4182,23 @@ void bt_hci_le_df_cte_req_failed(struct net_buf *buf)
41714182
#endif /* CONFIG_BT_DF_CONNECTION_CTE_REQ */
41724183

41734184
#endif /* CONFIG_BT_CONN */
4185+
4186+
#if defined(CONFIG_BT_CONN_TX_NOTIFY_WQ)
4187+
static int bt_conn_tx_workq_init(void)
4188+
{
4189+
const struct k_work_queue_config cfg = {
4190+
.name = "BT CONN TX WQ",
4191+
.no_yield = false,
4192+
.essential = false,
4193+
};
4194+
4195+
k_work_queue_init(&conn_tx_workq);
4196+
k_work_queue_start(&conn_tx_workq, conn_tx_workq_thread_stack,
4197+
K_THREAD_STACK_SIZEOF(conn_tx_workq_thread_stack),
4198+
K_PRIO_COOP(CONFIG_BT_CONN_TX_NOTIFY_WQ_PRIO), &cfg);
4199+
4200+
return 0;
4201+
}
4202+
4203+
SYS_INIT(bt_conn_tx_workq_init, POST_KERNEL, CONFIG_BT_CONN_TX_NOTIFY_WQ_INIT_PRIORITY);
4204+
#endif /* CONFIG_BT_CONN_TX_NOTIFY_WQ */

subsys/bluetooth/host/conn_internal.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,8 @@ static inline void *closure_data(void *storage)
358358
return ((struct closure *)storage)->data;
359359
}
360360

361+
void bt_conn_tx_notify(struct bt_conn *conn, bool wait_for_completion);
362+
361363
void bt_conn_reset_rx_state(struct bt_conn *conn);
362364

363365
/* Process incoming data for a connection */

subsys/bluetooth/host/hci_core.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -605,7 +605,7 @@ static void hci_num_completed_packets(struct net_buf *buf)
605605
atomic_dec(&conn->in_ll);
606606

607607
/* TX context free + callback happens in there */
608-
k_work_submit(&conn->tx_complete_work);
608+
bt_conn_tx_notify(conn, false);
609609
}
610610

611611
bt_conn_unref(conn);

0 commit comments

Comments
 (0)