Skip to content

Commit 3c5bf50

Browse files
jori-nordiccarlescufi
authored andcommitted
Bluetooth: host: add dedicated WQ for long-running tasks
Send long-running tasks to a dedicated low-priority workqueue. This shouldn't increase memory usage since by doing this, we get rid of the ECC processing thread. This should fix issues like #43811, since the system workqueue runs at a cooperative priority, and the new dedicated one runs at a pre-emptible priority. Fixes #43811 Signed-off-by: Jonathan Rico <[email protected]>
1 parent cf19d7e commit 3c5bf50

File tree

9 files changed

+106
-48
lines changed

9 files changed

+106
-48
lines changed

subsys/bluetooth/host/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ zephyr_library_sources_ifdef(CONFIG_BT_RFCOMM rfcomm.c)
1212
zephyr_library_sources_ifdef(CONFIG_BT_TESTING testing.c)
1313
zephyr_library_sources_ifdef(CONFIG_BT_SETTINGS settings.c)
1414
zephyr_library_sources_ifdef(CONFIG_BT_HOST_CCM aes_ccm.c)
15+
zephyr_library_sources_ifdef(CONFIG_BT_LONG_WQ long_wq.c)
1516

1617
zephyr_library_sources_ifdef(
1718
CONFIG_BT_BREDR

subsys/bluetooth/host/Kconfig

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,26 @@
44
# Copyright (c) 2015-2016 Intel Corporation
55
# SPDX-License-Identifier: Apache-2.0
66

7+
config BT_LONG_WQ
8+
bool "Dedicated workqueue for long-running tasks."
9+
default y if BT_GATT_CACHING
10+
help
11+
Adds an API for a workqueue dedicated to long-running tasks.
12+
13+
if BT_LONG_WQ
14+
config BT_LONG_WQ_STACK_SIZE
15+
# Hidden: Long workqueue stack size. Should be derived from system
16+
# requirements.
17+
int
18+
default BT_HCI_ECC_STACK_SIZE if BT_TINYCRYPT_ECC
19+
default 1024
20+
21+
config BT_LONG_WQ_PRIO
22+
int "Long workqueue priority. Should be pre-emptible."
23+
default 10
24+
range 0 NUM_PREEMPT_PRIORITIES
25+
endif # BT_LONG_WQ
26+
727
config BT_HCI_HOST
828
# Hidden option to make the conditions more intuitive
929
bool
@@ -700,6 +720,7 @@ config BT_TINYCRYPT_ECC
700720
bool "Emulate ECDH in the Host using TinyCrypt library"
701721
select TINYCRYPT
702722
select TINYCRYPT_ECC_DH
723+
select BT_LONG_WQ
703724
depends on BT_ECC && (BT_HCI_RAW || BT_HCI_HOST)
704725
default y if BT_CTLR && !BT_CTLR_ECDH
705726
help

subsys/bluetooth/host/gatt.c

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
#include "smp.h"
4545
#include "settings.h"
4646
#include "gatt_internal.h"
47+
#include "long_wq.h"
4748

4849
#define SC_TIMEOUT K_MSEC(10)
4950
#define CCC_STORE_DELAY K_SECONDS(1)
@@ -1307,7 +1308,11 @@ void bt_gatt_init(void)
13071308
/* Submit work to Generate initial hash as there could be static
13081309
* services already in the database.
13091310
*/
1310-
k_work_schedule(&db_hash.work, DB_HASH_TIMEOUT);
1311+
if (IS_ENABLED(CONFIG_BT_LONG_WQ)) {
1312+
bt_long_wq_schedule(&db_hash.work, DB_HASH_TIMEOUT);
1313+
} else {
1314+
k_work_schedule(&db_hash.work, DB_HASH_TIMEOUT);
1315+
}
13111316
#endif /* CONFIG_BT_GATT_CACHING */
13121317

13131318
#if defined(CONFIG_BT_GATT_SERVICE_CHANGED)
@@ -1377,7 +1382,12 @@ static void db_changed(void)
13771382
int i;
13781383

13791384
atomic_clear_bit(gatt_sc.flags, DB_HASH_VALID);
1380-
k_work_reschedule(&db_hash.work, DB_HASH_TIMEOUT);
1385+
1386+
if (IS_ENABLED(CONFIG_BT_LONG_WQ)) {
1387+
bt_long_wq_reschedule(&db_hash.work, DB_HASH_TIMEOUT);
1388+
} else {
1389+
k_work_reschedule(&db_hash.work, DB_HASH_TIMEOUT);
1390+
}
13811391

13821392
for (i = 0; i < ARRAY_SIZE(cf_cfg); i++) {
13831393
struct gatt_cf_cfg *cfg = &cf_cfg[i];
@@ -5586,9 +5596,12 @@ static int db_hash_commit(void)
55865596
/* Reschedule work to calculate and compare against the Hash value
55875597
* loaded from flash.
55885598
*/
5589-
k_work_reschedule(&db_hash.work, K_NO_WAIT);
5599+
if (IS_ENABLED(CONFIG_BT_LONG_WQ)) {
5600+
return bt_long_wq_reschedule(&db_hash.work, K_NO_WAIT);
5601+
} else {
5602+
return k_work_reschedule(&db_hash.work, K_NO_WAIT);
5603+
}
55905604

5591-
return 0;
55925605
}
55935606

55945607
SETTINGS_STATIC_HANDLER_DEFINE(bt_hash, "bt/hash", NULL, db_hash_set,

subsys/bluetooth/host/hci_core.c

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3676,10 +3676,6 @@ int bt_enable(bt_ready_cb_t cb)
36763676
k_thread_name_set(&bt_workq.thread, "BT RX");
36773677
#endif
36783678

3679-
if (IS_ENABLED(CONFIG_BT_TINYCRYPT_ECC)) {
3680-
bt_hci_ecc_init();
3681-
}
3682-
36833679
err = bt_dev.drv->open();
36843680
if (err) {
36853681
BT_ERR("HCI driver open failed (%d)", err);
@@ -3737,10 +3733,6 @@ int bt_disable(void)
37373733
k_thread_abort(&bt_workq.thread);
37383734
#endif
37393735

3740-
if (IS_ENABLED(CONFIG_BT_TINYCRYPT_ECC)) {
3741-
bt_hci_ecc_deinit();
3742-
}
3743-
37443736
bt_monitor_send(BT_MONITOR_CLOSE_INDEX, NULL, 0);
37453737

37463738
/* Clear BT_DEV_ENABLE here to prevent early bt_enable() calls */

subsys/bluetooth/host/hci_ecc.c

Lines changed: 12 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,10 @@
3636
#else
3737
#include "hci_core.h"
3838
#endif
39+
#include "long_wq.h"
3940

40-
static struct k_thread ecc_thread_data;
41-
static K_KERNEL_STACK_DEFINE(ecc_thread_stack, CONFIG_BT_HCI_ECC_STACK_SIZE);
41+
static void ecc_process(struct k_work *work);
42+
K_WORK_DEFINE(ecc_work, ecc_process);
4243

4344
/* based on Core Specification 4.2 Vol 3. Part H 2.3.5.6.1 */
4445
static const uint8_t debug_private_key_be[BT_PRIV_KEY_LEN] = {
@@ -60,8 +61,6 @@ enum {
6061

6162
static ATOMIC_DEFINE(flags, NUM_FLAGS);
6263

63-
static K_SEM_DEFINE(cmd_sem, 0, 1);
64-
6564
static struct {
6665
uint8_t private_key_be[BT_PRIV_KEY_LEN];
6766

@@ -208,18 +207,14 @@ static void emulate_le_generate_dhkey(void)
208207
bt_recv(buf);
209208
}
210209

211-
static void ecc_thread(void *p1, void *p2, void *p3)
210+
static void ecc_process(struct k_work *work)
212211
{
213-
while (true) {
214-
k_sem_take(&cmd_sem, K_FOREVER);
215-
216-
if (atomic_test_bit(flags, PENDING_PUB_KEY)) {
217-
emulate_le_p256_public_key_cmd();
218-
} else if (atomic_test_bit(flags, PENDING_DHKEY)) {
219-
emulate_le_generate_dhkey();
220-
} else {
221-
__ASSERT(0, "Unhandled ECC command");
222-
}
212+
if (atomic_test_bit(flags, PENDING_PUB_KEY)) {
213+
emulate_le_p256_public_key_cmd();
214+
} else if (atomic_test_bit(flags, PENDING_DHKEY)) {
215+
emulate_le_generate_dhkey();
216+
} else {
217+
__ASSERT(0, "Unhandled ECC command");
223218
}
224219
}
225220

@@ -261,7 +256,7 @@ static uint8_t le_gen_dhkey(uint8_t *key, uint8_t key_type)
261256
atomic_set_bit_to(flags, USE_DEBUG_KEY,
262257
key_type == BT_HCI_LE_KEY_TYPE_DEBUG);
263258

264-
k_sem_give(&cmd_sem);
259+
bt_long_wq_submit(&ecc_work);
265260

266261
return BT_HCI_ERR_SUCCESS;
267262
}
@@ -301,7 +296,7 @@ static void le_p256_pub_key(struct net_buf *buf)
301296
} else if (atomic_test_and_set_bit(flags, PENDING_PUB_KEY)) {
302297
status = BT_HCI_ERR_CMD_DISALLOWED;
303298
} else {
304-
k_sem_give(&cmd_sem);
299+
bt_long_wq_submit(&ecc_work);
305300
status = BT_HCI_ERR_SUCCESS;
306301
}
307302

@@ -351,16 +346,3 @@ int default_CSPRNG(uint8_t *dst, unsigned int len)
351346
{
352347
return !bt_rand(dst, len);
353348
}
354-
355-
void bt_hci_ecc_init(void)
356-
{
357-
k_thread_create(&ecc_thread_data, ecc_thread_stack,
358-
K_KERNEL_STACK_SIZEOF(ecc_thread_stack), ecc_thread,
359-
NULL, NULL, NULL, K_PRIO_PREEMPT(10), 0, K_NO_WAIT);
360-
k_thread_name_set(&ecc_thread_data, "BT ECC");
361-
}
362-
363-
void bt_hci_ecc_deinit(void)
364-
{
365-
k_thread_abort(&ecc_thread_data);
366-
}

subsys/bluetooth/host/hci_ecc.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,5 @@
66
* SPDX-License-Identifier: Apache-2.0
77
*/
88

9-
void bt_hci_ecc_init(void);
10-
void bt_hci_ecc_deinit(void);
119
int bt_hci_ecc_send(struct net_buf *buf);
1210
void bt_hci_ecc_supported_commands(uint8_t *supported_commands);

subsys/bluetooth/host/hci_raw.c

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -372,10 +372,6 @@ int bt_enable_raw(struct k_fifo *rx_queue)
372372
return -ENODEV;
373373
}
374374

375-
if (IS_ENABLED(CONFIG_BT_TINYCRYPT_ECC)) {
376-
bt_hci_ecc_init();
377-
}
378-
379375
err = drv->open();
380376
if (err) {
381377
BT_ERR("HCI driver open failed (%d)", err);

subsys/bluetooth/host/long_wq.c

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/* long_work.c - Workqueue intended for long-running operations. */
2+
3+
/*
4+
* Copyright (c) 2022 Nordic Semiconductor ASA
5+
*
6+
* SPDX-License-Identifier: Apache-2.0
7+
*/
8+
#include <zephyr/kernel.h>
9+
#include <zephyr/init.h>
10+
11+
K_THREAD_STACK_DEFINE(bt_lw_stack_area, CONFIG_BT_LONG_WQ_STACK_SIZE);
12+
static struct k_work_q bt_long_wq;
13+
14+
int bt_long_wq_schedule(struct k_work_delayable *dwork, k_timeout_t timeout)
15+
{
16+
return k_work_schedule_for_queue(&bt_long_wq, dwork, timeout);
17+
}
18+
19+
int bt_long_wq_reschedule(struct k_work_delayable *dwork, k_timeout_t timeout)
20+
{
21+
return k_work_reschedule_for_queue(&bt_long_wq, dwork, timeout);
22+
}
23+
24+
int bt_long_wq_submit(struct k_work *work)
25+
{
26+
return k_work_submit_to_queue(&bt_long_wq, work);
27+
}
28+
29+
static int long_wq_init(const struct device *d)
30+
{
31+
ARG_UNUSED(d);
32+
33+
const struct k_work_queue_config cfg = {.name = "BT_LW_WQ"};
34+
35+
k_work_queue_init(&bt_long_wq);
36+
37+
k_work_queue_start(&bt_long_wq, bt_lw_stack_area,
38+
K_THREAD_STACK_SIZEOF(bt_lw_stack_area),
39+
CONFIG_BT_LONG_WQ_PRIO, &cfg);
40+
41+
return 0;
42+
}
43+
44+
SYS_INIT(long_wq_init, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);

subsys/bluetooth/host/long_wq.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/* long_wq.h - Workqueue API intended for long-running operations. */
2+
3+
/*
4+
* Copyright (c) 2022 Nordic Semiconductor ASA
5+
*
6+
* SPDX-License-Identifier: Apache-2.0
7+
*/
8+
9+
int bt_long_wq_schedule(struct k_work_delayable *dwork, k_timeout_t timeout);
10+
int bt_long_wq_reschedule(struct k_work_delayable *dwork, k_timeout_t timeout);
11+
int bt_long_wq_submit(struct k_work *dwork);

0 commit comments

Comments
 (0)