diff --git a/doc/releases/release-notes-4.0.rst b/doc/releases/release-notes-4.0.rst index 76eaa3ac62f..44527737e3b 100644 --- a/doc/releases/release-notes-4.0.rst +++ b/doc/releases/release-notes-4.0.rst @@ -107,6 +107,11 @@ Bluetooth * 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 ******************** diff --git a/subsys/bluetooth/mesh/Kconfig b/subsys/bluetooth/mesh/Kconfig index 5ae770a8a41..5232ed081d6 100644 --- a/subsys/bluetooth/mesh/Kconfig +++ b/subsys/bluetooth/mesh/Kconfig @@ -107,6 +107,64 @@ menuconfig 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 int "Maximum of simultaneous relay message support" default 0 diff --git a/subsys/bluetooth/mesh/adv.h b/subsys/bluetooth/mesh/adv.h index cbe4f6e9adb..563a2118b71 100644 --- a/subsys/bluetooth/mesh/adv.h +++ b/subsys/bluetooth/mesh/adv.h @@ -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, 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_ */ diff --git a/subsys/bluetooth/mesh/adv_ext.c b/subsys/bluetooth/mesh/adv_ext.c index 39e6ce87759..519485c3135 100644 --- a/subsys/bluetooth/mesh/adv_ext.c +++ b/subsys/bluetooth/mesh/adv_ext.c @@ -36,6 +36,14 @@ LOG_MODULE_REGISTER(bt_mesh_adv_ext); #define CONFIG_BT_MESH_RELAY_ADV_SETS 0 #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 { /** Controller is currently advertising */ ADV_FLAG_ACTIVE, @@ -72,6 +80,15 @@ struct bt_mesh_ext_adv { static void send_pending_adv(struct k_work *work); 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[] = { [0] = { .tags = ( @@ -283,7 +300,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); - k_work_submit(&ext_adv->work); + bt_mesh_wq_submit(&ext_adv->work); return true; } @@ -432,7 +449,7 @@ int bt_mesh_adv_terminate(struct bt_mesh_adv *adv) atomic_set_bit(ext_adv->flags, ADV_FLAG_SENT); - k_work_submit(&ext_adv->work); + bt_mesh_wq_submit(&ext_adv->work); return 0; } @@ -455,6 +472,13 @@ void bt_mesh_adv_init(void) (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"); + } + #if defined(CONFIG_BT_LL_SOFTDEVICE) const sdc_hci_cmd_vs_scan_accept_ext_adv_packets_set_t cmd_params = { .accept_ext_adv_packets = IS_ENABLED(CONFIG_BT_MESH_ADV_EXT_ACCEPT_EXT_ADV_PACKETS), @@ -495,7 +519,7 @@ static void adv_sent(struct bt_le_ext_adv *instance, 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) @@ -549,13 +573,13 @@ int bt_mesh_adv_enable(void) int bt_mesh_adv_disable(void) { - int err; struct k_work_sync sync; + int err; for (int i = 0; i < ARRAY_SIZE(advs); i++) { 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_flush(&advs[i].work, &sync); } @@ -608,3 +632,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); } + +int bt_mesh_wq_submit(struct k_work *work) +{ + return k_work_submit_to_queue(MESH_WORKQ, work); +} diff --git a/subsys/bluetooth/mesh/adv_legacy.c b/subsys/bluetooth/mesh/adv_legacy.c index c79a118cf15..8b14055bd75 100644 --- a/subsys/bluetooth/mesh/adv_legacy.c +++ b/subsys/bluetooth/mesh/adv_legacy.c @@ -258,3 +258,8 @@ int bt_mesh_adv_gatt_start(const struct bt_le_adv_param *param, int32_t duration adv_timeout = duration; 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); +} diff --git a/subsys/bluetooth/mesh/proxy_msg.c b/subsys/bluetooth/mesh/proxy_msg.c index e2818f8634b..861935f58cc 100644 --- a/subsys/bluetooth/mesh/proxy_msg.c +++ b/subsys/bluetooth/mesh/proxy_msg.c @@ -64,6 +64,15 @@ static void proxy_sar_timeout(struct k_work *work) LOG_WRN("Proxy SAR timeout"); 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) { bt_conn_disconnect(role->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); } -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; @@ -230,6 +239,41 @@ int bt_mesh_proxy_relay_send(struct bt_conn *conn, struct bt_mesh_adv *adv) 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) { /* 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); + k_fifo_init(&role->pending); + k_work_init(&role->work, proxy_msg_send_pending); + k_work_init_delayable(&role->sar_timer, proxy_sar_timeout); } diff --git a/subsys/bluetooth/mesh/proxy_msg.h b/subsys/bluetooth/mesh/proxy_msg.h index 7ad4be7ae5d..99564b71693 100644 --- a/subsys/bluetooth/mesh/proxy_msg.h +++ b/subsys/bluetooth/mesh/proxy_msg.h @@ -37,6 +37,9 @@ struct bt_mesh_proxy_role { struct bt_conn *conn; uint8_t msg_type; + struct k_fifo pending; + struct k_work work; + struct { proxy_send_cb_t send; proxy_recv_cb_t recv; diff --git a/subsys/bluetooth/mesh/proxy_srv.c b/subsys/bluetooth/mesh/proxy_srv.c index c3b33035a3f..32e865773b3 100644 --- a/subsys/bluetooth/mesh/proxy_srv.c +++ b/subsys/bluetooth/mesh/proxy_srv.c @@ -917,7 +917,7 @@ static ssize_t proxy_ccc_write(struct bt_conn *conn, client = find_client(conn); if (client->filter_type == NONE) { client->filter_type = ACCEPT; - k_work_submit(&client->send_beacons); + bt_mesh_wq_submit(&client->send_beacons); } return sizeof(value); diff --git a/tests/bsim/bluetooth/mesh/compile.sh b/tests/bsim/bluetooth/mesh/compile.sh index aa86e6ccb25..05c51f7bfe1 100755 --- a/tests/bsim/bluetooth/mesh/compile.sh +++ b/tests/bsim/bluetooth/mesh/compile.sh @@ -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_low_lat.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_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_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;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 diff --git a/tests/bsim/bluetooth/mesh/overlay_workq_sys.conf b/tests/bsim/bluetooth/mesh/overlay_workq_sys.conf new file mode 100644 index 00000000000..b4ee51bf8d5 --- /dev/null +++ b/tests/bsim/bluetooth/mesh/overlay_workq_sys.conf @@ -0,0 +1 @@ +CONFIG_BT_MESH_WORKQ_SYS=y diff --git a/tests/bsim/bluetooth/mesh/src/test_suspend.c b/tests/bsim/bluetooth/mesh/src/test_suspend.c index 5ec6a8dc685..ada25b0a22f 100644 --- a/tests/bsim/bluetooth/mesh/src/test_suspend.c +++ b/tests/bsim/bluetooth/mesh/src/test_suspend.c @@ -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"); } + /* Allow publishing to finish before suspending. */ + k_sleep(K_MSEC(100)); + ASSERT_OK_MSG(bt_mesh_suspend(), "Failed to suspend Mesh."); if (disable_bt) { diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/advertiser/disable.sh b/tests/bsim/bluetooth/mesh/tests_scripts/advertiser/disable.sh index 50d2a53a16d..d0288a3964b 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/advertiser/disable.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/advertiser/disable.sh @@ -36,3 +36,6 @@ RunTest mesh_adv_disable adv_tx_disable adv_rx_disable # Low latency overlay uses legacy advertiser overlay=overlay_low_lat_conf 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 diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/advertiser/proxy_mixin.sh b/tests/bsim/bluetooth/mesh/tests_scripts/advertiser/proxy_mixin.sh index 6c49d03fe9f..fb6af48f651 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/advertiser/proxy_mixin.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/advertiser/proxy_mixin.sh @@ -21,5 +21,8 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh overlay=overlay_gatt_conf 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" RunTest mesh_adv_proxy_mixin_psa adv_tx_proxy_mixin adv_rx_proxy_mixin diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/advertiser/random_order.sh b/tests/bsim/bluetooth/mesh/tests_scripts/advertiser/random_order.sh index a171ffd60f3..5808d2cd508 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/advertiser/random_order.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/advertiser/random_order.sh @@ -7,5 +7,8 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh # 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 +overlay=overlay_workq_sys_conf +RunTest mesh_adv_random_order_workq adv_tx_random_order adv_rx_random_order + overlay=overlay_psa_conf RunTest mesh_adv_random_order_psa adv_tx_random_order adv_rx_random_order diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/advertiser/reverse_order.sh b/tests/bsim/bluetooth/mesh/tests_scripts/advertiser/reverse_order.sh index 2b047138109..1428833a35b 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/advertiser/reverse_order.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/advertiser/reverse_order.sh @@ -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. 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 RunTest mesh_adv_reverse_order_psa adv_tx_reverse_order adv_rx_receive_order diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/advertiser/send_order.sh b/tests/bsim/bluetooth/mesh/tests_scripts/advertiser/send_order.sh index a9e8d1ea861..5122d7fdf05 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/advertiser/send_order.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/advertiser/send_order.sh @@ -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. 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 RunTest mesh_adv_send_order_psa adv_tx_send_order adv_rx_receive_order diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/advertiser/tx_cb_multi.sh b/tests/bsim/bluetooth/mesh/tests_scripts/advertiser/tx_cb_multi.sh index 4ca2838ddf9..a7e3ec95437 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/advertiser/tx_cb_multi.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/advertiser/tx_cb_multi.sh @@ -7,5 +7,8 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh # test tx callbacks sequence for multiple advs 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 RunTest mesh_adv_tx_cb_multi_psa adv_tx_cb_multi diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/advertiser/tx_cb_single.sh b/tests/bsim/bluetooth/mesh/tests_scripts/advertiser/tx_cb_single.sh index a2b1ad0e961..48d81a60136 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/advertiser/tx_cb_single.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/advertiser/tx_cb_single.sh @@ -7,5 +7,8 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh # test tx callbacks parameters and xmit sequence for single adv 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 RunTest mesh_adv_tx_cb_single_psa adv_tx_cb_single adv_rx_xmit diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/proxy_sol/sol_replay.sh b/tests/bsim/bluetooth/mesh/tests_scripts/proxy_sol/sol_replay.sh index c3da4435eb1..02f7c933254 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/proxy_sol/sol_replay.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/proxy_sol/sol_replay.sh @@ -32,6 +32,18 @@ RunTest mesh_srpl_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_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" RunTest mesh_srpl_replay_attack_psa \ proxy_sol_tester_immediate_replay_attack \