Bluetooth: Mesh: Introduce separate workq for ADV EXT

this PR is to make the host always send packets.

Signed-off-by: Lingao Meng <menglingao@xiaomi.com>
This commit is contained in:
Lingao Meng 2024-09-24 14:41:44 +08:00 committed by Mahesh Mahadevan
commit b9fbfc9a23
19 changed files with 197 additions and 8 deletions

View file

@ -148,6 +148,11 @@ Bluetooth
* HCI Drivers * HCI Drivers
* Mesh
* Introduced a mesh-specific workqueue to increase reliability of the mesh messages
transmission. To get the old behavior enable :kconfig:option:`CONFIG_BT_MESH_WORKQ_SYS`.
Boards & SoC Support Boards & SoC Support
******************** ********************

View file

@ -103,6 +103,64 @@ menuconfig BT_MESH_ADV_EXT
if BT_MESH_ADV_EXT if BT_MESH_ADV_EXT
choice BT_MESH_WORKQ_CONTEXT
prompt "Advertising thread selection"
default BT_MESH_WORKQ_MESH
help
Defines a context for mesh messages transmission.
config BT_MESH_WORKQ_MESH
bool "Mesh-specific workqueue"
help
When this option is selected, the mesh sends messages from the
mesh-specific workqueue. This will ensure that messages are always sent.
The application needs to ensure the mesh-specific workqueue size is large
enough. Refer to BT_MESH_ADV_STACK_SIZE for the recommended minimum.
config BT_MESH_WORKQ_SYS
bool "System workqueue"
help
When this option is selected, the mesh sends messages from
the system work queue. The application needs to ensure the system
workqueue stack size (SYSTEM_WORKQUEUE_STACK_SIZE) is large enough,
refer to BT_MESH_ADV_STACK_SIZE for the recommended minimum.
When this option is enabled and the mesh tries to send a message,
and the host ran out the HCI command buffers controlled by
CONFIG_BT_BUF_CMD_TX_COUNT, the host returns -ENOBUFS immediately
and the mesh drops the message transmission. To mitigate this
issue, make sure to have sufficient number of HCI command buffers.
When this option is enabled, the latency of sending mesh messages
will be affected by other users on the system work queue, resulting in
reduced reliability for sending mesh messages.
endchoice
if BT_MESH_WORKQ_MESH
config BT_MESH_ADV_STACK_SIZE
int "Mesh extended advertiser thread stack size"
default 1536 if BT_MESH_PROXY
default 1024 if BT_HOST_CRYPTO
default 776 if BT_MESH_PRIV_BEACONS
default 768
help
Size of bt mesh adv thread stack.
NOTE: This is an advanced setting and should not be changed unless
absolutely necessary
config BT_MESH_ADV_PRIO
int "Mesh advertiser thread priority"
default 7
help
Priority of bt mesh adv thread.
NOTE: This is an advanced setting and should not be changed unless
absolutely necessary
endif # BT_MESH_WORKQ_MESH
config BT_MESH_RELAY_ADV_SETS config BT_MESH_RELAY_ADV_SETS
int "Maximum of simultaneous relay message support" int "Maximum of simultaneous relay message support"
default 0 default 0

View file

@ -123,4 +123,6 @@ int bt_mesh_scan_active_set(bool active);
int bt_mesh_adv_bt_data_send(uint8_t num_events, uint16_t adv_interval, int bt_mesh_adv_bt_data_send(uint8_t num_events, uint16_t adv_interval,
const struct bt_data *ad, size_t ad_len); const struct bt_data *ad, size_t ad_len);
int bt_mesh_wq_submit(struct k_work *work);
#endif /* ZEPHYR_SUBSYS_BLUETOOTH_MESH_ADV_H_ */ #endif /* ZEPHYR_SUBSYS_BLUETOOTH_MESH_ADV_H_ */

View file

@ -33,6 +33,14 @@ LOG_MODULE_REGISTER(bt_mesh_adv_ext);
#define CONFIG_BT_MESH_RELAY_ADV_SETS 0 #define CONFIG_BT_MESH_RELAY_ADV_SETS 0
#endif #endif
#ifdef CONFIG_BT_MESH_ADV_STACK_SIZE
#define MESH_WORKQ_PRIORITY CONFIG_BT_MESH_ADV_PRIO
#define MESH_WORKQ_STACK_SIZE CONFIG_BT_MESH_ADV_STACK_SIZE
#else
#define MESH_WORKQ_PRIORITY 0
#define MESH_WORKQ_STACK_SIZE 0
#endif
enum { enum {
/** Controller is currently advertising */ /** Controller is currently advertising */
ADV_FLAG_ACTIVE, ADV_FLAG_ACTIVE,
@ -69,6 +77,15 @@ struct bt_mesh_ext_adv {
static void send_pending_adv(struct k_work *work); static void send_pending_adv(struct k_work *work);
static bool schedule_send(struct bt_mesh_ext_adv *ext_adv); static bool schedule_send(struct bt_mesh_ext_adv *ext_adv);
static struct k_work_q bt_mesh_workq;
static K_KERNEL_STACK_DEFINE(thread_stack, MESH_WORKQ_STACK_SIZE);
#if defined(CONFIG_BT_MESH_WORKQ_MESH)
#define MESH_WORKQ &bt_mesh_workq
#else /* CONFIG_BT_MESH_WORKQ_SYS */
#define MESH_WORKQ &k_sys_work_q
#endif /* CONFIG_BT_MESH_WORKQ_MESH */
static struct bt_mesh_ext_adv advs[] = { static struct bt_mesh_ext_adv advs[] = {
[0] = { [0] = {
.tags = ( .tags = (
@ -258,7 +275,7 @@ static bool schedule_send_with_mask(struct bt_mesh_ext_adv *ext_adv, int ignore_
} }
atomic_clear_bit(ext_adv->flags, ADV_FLAG_SCHEDULE_PENDING); atomic_clear_bit(ext_adv->flags, ADV_FLAG_SCHEDULE_PENDING);
k_work_submit(&ext_adv->work); bt_mesh_wq_submit(&ext_adv->work);
return true; return true;
} }
@ -407,7 +424,7 @@ int bt_mesh_adv_terminate(struct bt_mesh_adv *adv)
atomic_set_bit(ext_adv->flags, ADV_FLAG_SENT); atomic_set_bit(ext_adv->flags, ADV_FLAG_SENT);
k_work_submit(&ext_adv->work); bt_mesh_wq_submit(&ext_adv->work);
return 0; return 0;
} }
@ -429,6 +446,13 @@ void bt_mesh_adv_init(void)
for (int i = 0; i < ARRAY_SIZE(advs); i++) { for (int i = 0; i < ARRAY_SIZE(advs); i++) {
(void)memcpy(&advs[i].adv_param, &adv_param, sizeof(adv_param)); (void)memcpy(&advs[i].adv_param, &adv_param, sizeof(adv_param));
} }
if (IS_ENABLED(CONFIG_BT_MESH_WORKQ_MESH)) {
k_work_queue_init(&bt_mesh_workq);
k_work_queue_start(&bt_mesh_workq, thread_stack, MESH_WORKQ_STACK_SIZE,
K_PRIO_COOP(MESH_WORKQ_PRIORITY), NULL);
k_thread_name_set(&bt_mesh_workq.thread, "BT MESH WQ");
}
} }
static struct bt_mesh_ext_adv *adv_instance_find(struct bt_le_ext_adv *instance) static struct bt_mesh_ext_adv *adv_instance_find(struct bt_le_ext_adv *instance)
@ -458,7 +482,7 @@ static void adv_sent(struct bt_le_ext_adv *instance,
atomic_set_bit(ext_adv->flags, ADV_FLAG_SENT); atomic_set_bit(ext_adv->flags, ADV_FLAG_SENT);
k_work_submit(&ext_adv->work); bt_mesh_wq_submit(&ext_adv->work);
} }
#if defined(CONFIG_BT_MESH_GATT_SERVER) #if defined(CONFIG_BT_MESH_GATT_SERVER)
@ -503,13 +527,13 @@ int bt_mesh_adv_enable(void)
int bt_mesh_adv_disable(void) int bt_mesh_adv_disable(void)
{ {
int err;
struct k_work_sync sync; struct k_work_sync sync;
int err;
for (int i = 0; i < ARRAY_SIZE(advs); i++) { for (int i = 0; i < ARRAY_SIZE(advs); i++) {
atomic_set_bit(advs[i].flags, ADV_FLAG_SUSPENDING); atomic_set_bit(advs[i].flags, ADV_FLAG_SUSPENDING);
if (k_current_get() != &k_sys_work_q.thread || if (k_current_get() != k_work_queue_thread_get(MESH_WORKQ) ||
(k_work_busy_get(&advs[i].work) & K_WORK_RUNNING) == 0) { (k_work_busy_get(&advs[i].work) & K_WORK_RUNNING) == 0) {
k_work_flush(&advs[i].work, &sync); k_work_flush(&advs[i].work, &sync);
} }
@ -562,3 +586,8 @@ int bt_mesh_adv_bt_data_send(uint8_t num_events, uint16_t adv_interval,
{ {
return bt_data_send(advs, num_events, adv_interval, ad, ad_len); return bt_data_send(advs, num_events, adv_interval, ad, ad_len);
} }
int bt_mesh_wq_submit(struct k_work *work)
{
return k_work_submit_to_queue(MESH_WORKQ, work);
}

View file

@ -277,3 +277,8 @@ int bt_mesh_adv_gatt_start(const struct bt_le_adv_param *param, int32_t duration
adv_timeout = duration; adv_timeout = duration;
return bt_le_adv_start(param, ad, ad_len, sd, sd_len); return bt_le_adv_start(param, ad, ad_len, sd, sd_len);
} }
int bt_mesh_wq_submit(struct k_work *work)
{
return k_work_submit(work);
}

View file

@ -64,6 +64,15 @@ static void proxy_sar_timeout(struct k_work *work)
LOG_WRN("Proxy SAR timeout"); LOG_WRN("Proxy SAR timeout");
role = CONTAINER_OF(dwork, struct bt_mesh_proxy_role, sar_timer); role = CONTAINER_OF(dwork, struct bt_mesh_proxy_role, sar_timer);
while (!k_fifo_is_empty(&role->pending)) {
struct bt_mesh_adv *adv = k_fifo_get(&role->pending, K_NO_WAIT);
__ASSERT_NO_MSG(adv);
bt_mesh_adv_unref(adv);
}
if (role->conn) { if (role->conn) {
bt_conn_disconnect(role->conn, bt_conn_disconnect(role->conn,
BT_HCI_ERR_REMOTE_USER_TERM_CONN); BT_HCI_ERR_REMOTE_USER_TERM_CONN);
@ -200,7 +209,7 @@ static void buf_send_end(struct bt_conn *conn, void *user_data)
bt_mesh_adv_unref(adv); bt_mesh_adv_unref(adv);
} }
int bt_mesh_proxy_relay_send(struct bt_conn *conn, struct bt_mesh_adv *adv) static int proxy_relay_send(struct bt_conn *conn, struct bt_mesh_adv *adv)
{ {
int err; int err;
@ -230,6 +239,41 @@ int bt_mesh_proxy_relay_send(struct bt_conn *conn, struct bt_mesh_adv *adv)
return err; return err;
} }
int bt_mesh_proxy_relay_send(struct bt_conn *conn, struct bt_mesh_adv *adv)
{
struct bt_mesh_proxy_role *role = &roles[bt_conn_index(conn)];
k_fifo_put(&role->pending, bt_mesh_adv_ref(adv));
bt_mesh_wq_submit(&role->work);
return 0;
}
static void proxy_msg_send_pending(struct k_work *work)
{
struct bt_mesh_proxy_role *role;
struct k_work_delayable *dwork = k_work_delayable_from_work(work);
struct bt_mesh_adv *adv;
role = CONTAINER_OF(dwork, struct bt_mesh_proxy_role, sar_timer);
if (!role->conn) {
return;
}
adv = k_fifo_get(&role->pending, K_NO_WAIT);
if (!adv) {
return;
}
(void)proxy_relay_send(role->conn, adv);
bt_mesh_adv_unref(adv);
if (!k_fifo_is_empty(&role->pending)) {
bt_mesh_wq_submit(&role->work);
}
}
static void proxy_msg_init(struct bt_mesh_proxy_role *role) static void proxy_msg_init(struct bt_mesh_proxy_role *role)
{ {
/* Check if buf has been allocated, in this way, we no longer need /* Check if buf has been allocated, in this way, we no longer need
@ -247,6 +291,9 @@ static void proxy_msg_init(struct bt_mesh_proxy_role *role)
net_buf_simple_reset(&role->buf); net_buf_simple_reset(&role->buf);
k_fifo_init(&role->pending);
k_work_init(&role->work, proxy_msg_send_pending);
k_work_init_delayable(&role->sar_timer, proxy_sar_timeout); k_work_init_delayable(&role->sar_timer, proxy_sar_timeout);
} }

View file

@ -37,6 +37,9 @@ struct bt_mesh_proxy_role {
struct bt_conn *conn; struct bt_conn *conn;
uint8_t msg_type; uint8_t msg_type;
struct k_fifo pending;
struct k_work work;
struct { struct {
proxy_send_cb_t send; proxy_send_cb_t send;
proxy_recv_cb_t recv; proxy_recv_cb_t recv;

View file

@ -916,7 +916,7 @@ static ssize_t proxy_ccc_write(struct bt_conn *conn,
client = find_client(conn); client = find_client(conn);
if (client->filter_type == NONE) { if (client->filter_type == NONE) {
client->filter_type = ACCEPT; client->filter_type = ACCEPT;
k_work_submit(&client->send_beacons); bt_mesh_wq_submit(&client->send_beacons);
} }
return sizeof(value); return sizeof(value);

View file

@ -15,12 +15,15 @@ app=tests/bsim/bluetooth/mesh conf_overlay=overlay_pst.conf compile
app=tests/bsim/bluetooth/mesh conf_overlay=overlay_gatt.conf compile app=tests/bsim/bluetooth/mesh conf_overlay=overlay_gatt.conf compile
app=tests/bsim/bluetooth/mesh conf_overlay=overlay_low_lat.conf compile app=tests/bsim/bluetooth/mesh conf_overlay=overlay_low_lat.conf compile
app=tests/bsim/bluetooth/mesh conf_overlay=overlay_psa.conf compile app=tests/bsim/bluetooth/mesh conf_overlay=overlay_psa.conf compile
app=tests/bsim/bluetooth/mesh conf_overlay=overlay_workq_sys.conf compile
app=tests/bsim/bluetooth/mesh conf_overlay="overlay_pst.conf;overlay_psa.conf" compile app=tests/bsim/bluetooth/mesh conf_overlay="overlay_pst.conf;overlay_psa.conf" compile
app=tests/bsim/bluetooth/mesh conf_overlay="overlay_gatt.conf;overlay_psa.conf" compile app=tests/bsim/bluetooth/mesh conf_overlay="overlay_gatt.conf;overlay_psa.conf" compile
app=tests/bsim/bluetooth/mesh conf_overlay="overlay_gatt.conf;overlay_workq_sys.conf" compile
app=tests/bsim/bluetooth/mesh conf_overlay="overlay_low_lat.conf;overlay_psa.conf" compile app=tests/bsim/bluetooth/mesh conf_overlay="overlay_low_lat.conf;overlay_psa.conf" compile
app=tests/bsim/bluetooth/mesh conf_overlay="overlay_gatt.conf;overlay_low_lat.conf" compile app=tests/bsim/bluetooth/mesh conf_overlay="overlay_gatt.conf;overlay_low_lat.conf" compile
app=tests/bsim/bluetooth/mesh conf_overlay="overlay_pst.conf;overlay_gatt.conf" compile app=tests/bsim/bluetooth/mesh conf_overlay="overlay_pst.conf;overlay_gatt.conf" compile
app=tests/bsim/bluetooth/mesh \ app=tests/bsim/bluetooth/mesh \
conf_overlay="overlay_pst.conf;overlay_gatt.conf;overlay_psa.conf" compile conf_overlay="overlay_pst.conf;overlay_gatt.conf;overlay_psa.conf" compile
app=tests/bsim/bluetooth/mesh \
conf_overlay="overlay_pst.conf;overlay_gatt.conf;overlay_workq_sys.conf" compile
wait_for_background_jobs wait_for_background_jobs

View file

@ -0,0 +1 @@
CONFIG_BT_MESH_WORKQ_SYS=y

View file

@ -295,6 +295,9 @@ static void dut_pub_common(bool disable_bt)
ASSERT_OK_MSG(k_sem_take(&publish_sem, K_SECONDS(30)), "Pub timed out"); ASSERT_OK_MSG(k_sem_take(&publish_sem, K_SECONDS(30)), "Pub timed out");
} }
/* Allow publishing to finish before suspending. */
k_sleep(K_MSEC(100));
ASSERT_OK_MSG(bt_mesh_suspend(), "Failed to suspend Mesh."); ASSERT_OK_MSG(bt_mesh_suspend(), "Failed to suspend Mesh.");
if (disable_bt) { if (disable_bt) {

View file

@ -36,3 +36,6 @@ RunTest mesh_adv_disable adv_tx_disable adv_rx_disable
# Low latency overlay uses legacy advertiser # Low latency overlay uses legacy advertiser
overlay=overlay_low_lat_conf overlay=overlay_low_lat_conf
RunTest mesh_adv_disable adv_tx_disable adv_rx_disable RunTest mesh_adv_disable adv_tx_disable adv_rx_disable
overlay=overlay_workq_sys_conf
RunTest mesh_adv_disable_workq adv_tx_disable adv_rx_disable

View file

@ -21,5 +21,8 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh
overlay=overlay_gatt_conf overlay=overlay_gatt_conf
RunTest mesh_adv_proxy_mixin adv_tx_proxy_mixin adv_rx_proxy_mixin RunTest mesh_adv_proxy_mixin adv_tx_proxy_mixin adv_rx_proxy_mixin
overlay=overlay_gatt_conf_overlay_workq_sys_conf
RunTest mesh_adv_proxy_mixin_workq adv_tx_proxy_mixin adv_rx_proxy_mixin
overlay="overlay_gatt_conf_overlay_psa_conf" overlay="overlay_gatt_conf_overlay_psa_conf"
RunTest mesh_adv_proxy_mixin_psa adv_tx_proxy_mixin adv_rx_proxy_mixin RunTest mesh_adv_proxy_mixin_psa adv_tx_proxy_mixin adv_rx_proxy_mixin

View file

@ -7,5 +7,8 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh
# test buffer management by filling buffers and sending them in random order. # test buffer management by filling buffers and sending them in random order.
RunTest mesh_adv_random_order adv_tx_random_order adv_rx_random_order RunTest mesh_adv_random_order adv_tx_random_order adv_rx_random_order
overlay=overlay_workq_sys_conf
RunTest mesh_adv_random_order_workq adv_tx_random_order adv_rx_random_order
overlay=overlay_psa_conf overlay=overlay_psa_conf
RunTest mesh_adv_random_order_psa adv_tx_random_order adv_rx_random_order RunTest mesh_adv_random_order_psa adv_tx_random_order adv_rx_random_order

View file

@ -7,5 +7,8 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh
# test buffer management by filling all the buffer and sending them in reversed order. # test buffer management by filling all the buffer and sending them in reversed order.
RunTest mesh_adv_reverse_order adv_tx_reverse_order adv_rx_receive_order RunTest mesh_adv_reverse_order adv_tx_reverse_order adv_rx_receive_order
overlay=overlay_workq_sys_conf
RunTest mesh_adv_reverse_order_workq adv_tx_reverse_order adv_rx_receive_order
overlay=overlay_psa_conf overlay=overlay_psa_conf
RunTest mesh_adv_reverse_order_psa adv_tx_reverse_order adv_rx_receive_order RunTest mesh_adv_reverse_order_psa adv_tx_reverse_order adv_rx_receive_order

View file

@ -7,5 +7,8 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh
# test buffer management by filling all the buffer and sending them all in order. # test buffer management by filling all the buffer and sending them all in order.
RunTest mesh_adv_send_order adv_tx_send_order adv_rx_receive_order RunTest mesh_adv_send_order adv_tx_send_order adv_rx_receive_order
overlay=overlay_workq_sys_conf
RunTest mesh_adv_send_order_workq adv_tx_send_order adv_rx_receive_order
overlay=overlay_psa_conf overlay=overlay_psa_conf
RunTest mesh_adv_send_order_psa adv_tx_send_order adv_rx_receive_order RunTest mesh_adv_send_order_psa adv_tx_send_order adv_rx_receive_order

View file

@ -7,5 +7,8 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh
# test tx callbacks sequence for multiple advs # test tx callbacks sequence for multiple advs
RunTest mesh_adv_tx_cb_multi adv_tx_cb_multi RunTest mesh_adv_tx_cb_multi adv_tx_cb_multi
overlay=overlay_workq_sys_conf
RunTest mesh_adv_tx_cb_multi_workq adv_tx_cb_multi
overlay=overlay_psa_conf overlay=overlay_psa_conf
RunTest mesh_adv_tx_cb_multi_psa adv_tx_cb_multi RunTest mesh_adv_tx_cb_multi_psa adv_tx_cb_multi

View file

@ -7,5 +7,8 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh
# test tx callbacks parameters and xmit sequence for single adv # test tx callbacks parameters and xmit sequence for single adv
RunTest mesh_adv_tx_cb_single adv_tx_cb_single adv_rx_xmit RunTest mesh_adv_tx_cb_single adv_tx_cb_single adv_rx_xmit
overlay=overlay_workq_sys_conf
RunTest mesh_adv_tx_cb_single_workq adv_tx_cb_single adv_rx_xmit
overlay=overlay_psa_conf overlay=overlay_psa_conf
RunTest mesh_adv_tx_cb_single_psa adv_tx_cb_single adv_rx_xmit RunTest mesh_adv_tx_cb_single_psa adv_tx_cb_single adv_rx_xmit

View file

@ -32,6 +32,18 @@ RunTest mesh_srpl_replay_attack \
proxy_sol_iut_power_replay_attack \ proxy_sol_iut_power_replay_attack \
-flash=../results/mesh_srpl_replay_attack/flash.bin -flash_rm -flash=../results/mesh_srpl_replay_attack/flash.bin -flash_rm
overlay="overlay_pst_conf_overlay_gatt_conf_overlay_workq_sys_conf"
RunTest mesh_srpl_replay_attack_workq \
proxy_sol_tester_immediate_replay_attack \
proxy_sol_iut_immediate_replay_attack \
-flash=../results/mesh_srpl_replay_attack/flash.bin -flash_erase
overlay="overlay_pst_conf_overlay_gatt_conf_overlay_workq_sys_conf"
RunTest mesh_srpl_replay_attack_workq \
proxy_sol_tester_power_replay_attack \
proxy_sol_iut_power_replay_attack \
-flash=../results/mesh_srpl_replay_attack/flash.bin -flash_rm
overlay="overlay_pst_conf_overlay_gatt_conf_overlay_psa_conf" overlay="overlay_pst_conf_overlay_gatt_conf_overlay_psa_conf"
RunTest mesh_srpl_replay_attack_psa \ RunTest mesh_srpl_replay_attack_psa \
proxy_sol_tester_immediate_replay_attack \ proxy_sol_tester_immediate_replay_attack \