Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions samples/bluetooth/peripheral_hr/prj_minimal.conf
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,10 @@ CONFIG_BUILTIN_STACK_GUARD=n
CONFIG_BT_RX_STACK_SIZE=1024
CONFIG_BT_HCI_TX_STACK_SIZE_WITH_PROMPT=y
CONFIG_BT_HCI_TX_STACK_SIZE=640
CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=1100
CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=200
CONFIG_BT_LONG_WQ_STACK_SIZE=1100
CONFIG_IDLE_STACK_SIZE=128
CONFIG_MAIN_STACK_SIZE=640
CONFIG_IDLE_STACK_SIZE=64
CONFIG_MAIN_STACK_SIZE=500
CONFIG_ISR_STACK_SIZE=1024

# Disable features not needed
Expand Down
1 change: 1 addition & 0 deletions subsys/bluetooth/host/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ zephyr_library_sources_ifdef(CONFIG_BT_MONITOR monitor.c)
zephyr_library_sources_ifdef(CONFIG_BT_SETTINGS settings.c)
zephyr_library_sources_ifdef(CONFIG_BT_HOST_CCM aes_ccm.c)
zephyr_library_sources_ifdef(CONFIG_BT_LONG_WQ long_wq.c)
zephyr_library_sources(bt_taskq.c)

if(CONFIG_BT_HCI_HOST)
zephyr_library_sources(
Expand Down
14 changes: 14 additions & 0 deletions subsys/bluetooth/host/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,20 @@ config BT_LONG_WQ_INIT_PRIO

endif # BT_LONG_WQ

config BT_TASKQ_STACK_SIZE_WITH_PROMPT
bool "Override BT taskq thread stack size"

config BT_TASKQ_STACK_SIZE
int
prompt "BT taskq thread stack size" if BT_HCI_TX_STACK_SIZE_WITH_PROMPT
default 1024

config BT_TASKQ_THREAD_PRIO
int
# -1 is the least urgent cooperative priority.
# tx_processor() needs a cooperative thread for now.
default -1

config BT_HCI_HOST
# Hidden option to make the conditions more intuitive
bool
Expand Down
17 changes: 16 additions & 1 deletion subsys/bluetooth/host/att.c
Original file line number Diff line number Diff line change
Expand Up @@ -248,8 +248,13 @@ const char *bt_att_err_to_str(uint8_t att_err)
}
#endif /* CONFIG_BT_ATT_ERR_TO_STR */

static void att_tx_destroy(struct net_buf *buf)
static void att_tx_destroy_work_handler(struct k_work *work);
static K_WORK_DEFINE(att_tx_destroy_work, att_tx_destroy_work_handler);
static sys_slist_t tx_destroy_queue;

static void att_tx_destroy_work_handler(struct k_work *work)
{
struct net_buf *buf = net_buf_slist_get(&tx_destroy_queue);
struct bt_att_tx_meta_data *p_meta = att_get_tx_meta_data(buf);
struct bt_att_tx_meta_data meta;

Expand Down Expand Up @@ -278,6 +283,16 @@ static void att_tx_destroy(struct net_buf *buf)
if (meta.opcode != 0) {
att_on_sent_cb(&meta);
}

if (!sys_slist_is_empty(&tx_destroy_queue)) {
k_work_submit(&att_tx_destroy_work);
}
}

static void att_tx_destroy(struct net_buf *buf)
{
net_buf_slist_put(&tx_destroy_queue, buf);
k_work_submit(&att_tx_destroy_work);
}

NET_BUF_POOL_DEFINE(att_pool, CONFIG_BT_ATT_TX_COUNT,
Expand Down
32 changes: 32 additions & 0 deletions subsys/bluetooth/host/bt_taskq.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/* bt_taskq.c - Workqueue for quick non-blocking Bluetooth tasks */

/*
* Copyright (c) 2025 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/

#include <zephyr/autoconf.h>
#include <zephyr/kernel.h>
#include <zephyr/init.h>
#include <zephyr/kernel/thread_stack.h>

static K_THREAD_STACK_DEFINE(bt_taskq_stack, CONFIG_BT_TASKQ_STACK_SIZE);
struct k_work_q bt_taskq;

static int bt_taskq_init(void)
{
struct k_work_queue_config cfg = {
.name = "bt_taskq",
};

k_work_queue_start(&bt_taskq, bt_taskq_stack, K_THREAD_STACK_SIZEOF(bt_taskq_stack),
CONFIG_BT_TASKQ_THREAD_PRIO, &cfg);

return 0;
}

/* The init priority is set to POST_KERNEL 999, the last level
* before APPLICATION.
*/
SYS_INIT(bt_taskq_init, POST_KERNEL, 999);
40 changes: 40 additions & 0 deletions subsys/bluetooth/host/bt_taskq.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/* bt_taskq.h - Workqueue for quick non-blocking Bluetooth tasks */

/*
* Copyright (c) 2025 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/

#include <zephyr/kernel.h>

/**
* @brief Bluetooth task workqueue
*
* bt_taskq is a workqueue intended for quick non-blocking work
* items ("tasks") in the Bluetooth subsystem. This workqueue
* must always exist and is not controlled by any Kconfig
* option.
*
* Blocking means "waiting for something while running". A
* task is NOT allowed to block. If a task need to "wait", it
* should instead return immediately and schedule itself to run
* later.
*
* Work items submitted to this queue should be:
* - Quick to execute (non-blocking).
* - Not perform long-running operations.
* - Not block.
*
* @warning Non-blocking violation pitfalls:
* - net_buf_unref() on a foreign buffer could have a blocking
* destroy callback
* - Any user-defined callback might be blocking
* - Avoid any operations that could sleep or block the thread
*
* Use bt_long_wq for long-running or potentially blocking
* operations instead.
*
* Available in APPLICATION initialization level and later.
*/
extern struct k_work_q bt_taskq;
32 changes: 2 additions & 30 deletions subsys/bluetooth/host/hci_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@

#include "addr_internal.h"
#include "adv.h"
#include "bt_taskq.h"
#include "common/hci_common_internal.h"
#include "common/bt_str.h"
#include "common/rpa.h"
Expand Down Expand Up @@ -470,35 +471,6 @@ int bt_hci_cmd_send_sync(uint16_t opcode, struct net_buf *buf,
return err;
}

/* TODO: disallow sending sync commands from syswq altogether */

/* Since the commands are now processed in the syswq, we cannot suspend
* and wait. We have to send the command from the current context.
*/
if (k_current_get() == &k_sys_work_q.thread) {
/* drain the command queue until we get to send the command of interest. */
struct net_buf *cmd = NULL;

do {
cmd = k_fifo_peek_head(&bt_dev.cmd_tx_queue);
LOG_DBG("process cmd %p want %p", cmd, buf);

/* Wait for a response from the Bluetooth Controller.
* The Controller may fail to respond if:
* - It was never programmed or connected.
* - There was a fatal error.
*
* See the `BT_HCI_OP_` macros in hci_types.h or
* Core_v5.4, Vol 4, Part E, Section 5.4.1 and Section 7
* to map the opcode to the HCI command documentation.
* Example: 0x0c03 represents HCI_Reset command.
*/
__maybe_unused bool success = process_pending_cmd(HCI_CMD_TIMEOUT);

BT_ASSERT_MSG(success, "command opcode 0x%04x timeout", opcode);
} while (buf != cmd);
}

/* Now that we have sent the command, suspend until the LL replies */
err = k_sem_take(&sync_sem, HCI_CMD_TIMEOUT);
BT_ASSERT_MSG(err == 0,
Expand Down Expand Up @@ -5036,5 +5008,5 @@ static K_WORK_DEFINE(tx_work, tx_processor);
void bt_tx_irq_raise(void)
{
LOG_DBG("kick TX");
k_work_submit(&tx_work);
k_work_submit_to_queue(&bt_taskq, &tx_work);
}