Bluetooth: Merge HCI command and connection TX threads
We can go further with taking advantage of k_poll and merge the connection TX thread together with the HCI command thread, thereby saving even more memory. Change-Id: I1792056fd4621d62c7cd05929094033acca45c74 Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
This commit is contained in:
parent
1fb0351f9a
commit
dc70415dc4
4 changed files with 121 additions and 95 deletions
|
@ -44,8 +44,6 @@ const struct bt_conn_auth_cb *bt_auth;
|
|||
static struct bt_conn conns[CONFIG_BLUETOOTH_MAX_CONN];
|
||||
static struct bt_conn_cb *callback_list;
|
||||
|
||||
static BT_STACK_NOINIT(conn_tx_stack, CONFIG_BLUETOOTH_HCI_TX_STACK_SIZE);
|
||||
|
||||
#if defined(CONFIG_BLUETOOTH_BREDR)
|
||||
enum pairing_method {
|
||||
LEGACY, /* Legacy (pre-SSP) pairing */
|
||||
|
@ -1021,7 +1019,7 @@ static bool send_buf(struct bt_conn *conn, struct net_buf *buf)
|
|||
|
||||
static struct k_poll_signal conn_change = K_POLL_SIGNAL_INITIALIZER();
|
||||
|
||||
static int prepare_events(struct k_poll_event events[])
|
||||
int bt_conn_prepare_events(struct k_poll_event events[])
|
||||
{
|
||||
int i, ev_count = 0;
|
||||
|
||||
|
@ -1043,19 +1041,18 @@ static int prepare_events(struct k_poll_event events[])
|
|||
|
||||
BT_DBG("Adding conn %p to poll list", conn);
|
||||
|
||||
k_poll_event_init(&events[ev_count++],
|
||||
k_poll_event_init(&events[ev_count],
|
||||
K_POLL_TYPE_FIFO_DATA_AVAILABLE,
|
||||
K_POLL_MODE_NOTIFY_ONLY,
|
||||
&conn->tx_queue);
|
||||
events[ev_count++].tag = BT_EVENT_CONN_TX;
|
||||
}
|
||||
|
||||
return ev_count;
|
||||
}
|
||||
|
||||
static void process_fifo(struct k_fifo *fifo)
|
||||
void bt_conn_process_tx(struct bt_conn *conn)
|
||||
{
|
||||
struct bt_conn *conn = CONTAINER_OF(fifo, struct bt_conn,
|
||||
tx_queue);
|
||||
struct net_buf *buf;
|
||||
|
||||
BT_DBG("conn %p", conn);
|
||||
|
@ -1077,9 +1074,6 @@ static void process_fifo(struct k_fifo *fifo)
|
|||
*/
|
||||
bt_conn_unref(conn);
|
||||
|
||||
stack_analyze("conn tx stack", conn_tx_stack,
|
||||
sizeof(conn_tx_stack));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1091,53 +1085,6 @@ static void process_fifo(struct k_fifo *fifo)
|
|||
}
|
||||
}
|
||||
|
||||
static void process_events(struct k_poll_event *ev, int count)
|
||||
{
|
||||
BT_DBG("count %d", count);
|
||||
|
||||
for (; count; ev++, count--) {
|
||||
BT_DBG("ev->state %u", ev->state);
|
||||
|
||||
switch (ev->state) {
|
||||
case K_POLL_STATE_SIGNALED:
|
||||
/* prepare_events() will do the right thing */
|
||||
break;
|
||||
case K_POLL_STATE_FIFO_DATA_AVAILABLE:
|
||||
process_fifo(ev->fifo);
|
||||
break;
|
||||
case K_POLL_STATE_NOT_READY:
|
||||
break;
|
||||
default:
|
||||
BT_WARN("Unexpected k_poll event state %u", ev->state);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void conn_tx_thread(void *p1, void *p2, void *p3)
|
||||
{
|
||||
/* conn change signal + MAX_CONN */
|
||||
static struct k_poll_event events[1 + CONFIG_BLUETOOTH_MAX_CONN];
|
||||
|
||||
BT_DBG("Started");
|
||||
|
||||
while (1) {
|
||||
int ev_count, err;
|
||||
|
||||
ev_count = prepare_events(events);
|
||||
|
||||
BT_DBG("Calling k_poll with %d events", ev_count);
|
||||
|
||||
err = k_poll(events, ev_count, K_FOREVER);
|
||||
if (err && err != -EADDRINUSE) {
|
||||
BT_ERR("k_poll failed with err %d", err);
|
||||
continue;
|
||||
}
|
||||
|
||||
process_events(events, ev_count);
|
||||
}
|
||||
}
|
||||
|
||||
struct bt_conn *bt_conn_add_le(const bt_addr_le_t *peer)
|
||||
{
|
||||
struct bt_conn *conn = conn_new();
|
||||
|
@ -1804,9 +1751,6 @@ int bt_conn_init(void)
|
|||
|
||||
bt_l2cap_init();
|
||||
|
||||
k_thread_spawn(conn_tx_stack, sizeof(conn_tx_stack), conn_tx_thread,
|
||||
NULL, NULL, NULL, K_PRIO_COOP(7), 0, K_NO_WAIT);
|
||||
|
||||
/* Initialize background scan */
|
||||
if (IS_ENABLED(CONFIG_BLUETOOTH_CENTRAL)) {
|
||||
int i;
|
||||
|
|
|
@ -179,3 +179,7 @@ static inline struct k_sem *bt_conn_get_pkts(struct bt_conn *conn)
|
|||
|
||||
return &bt_dev.le.pkts;
|
||||
}
|
||||
|
||||
/* k_poll related helpers for the TX thread */
|
||||
int bt_conn_prepare_events(struct k_poll_event events[]);
|
||||
void bt_conn_process_tx(struct bt_conn *conn);
|
||||
|
|
|
@ -42,7 +42,7 @@
|
|||
#if !defined(CONFIG_BLUETOOTH_RECV_IS_RX_THREAD)
|
||||
static BT_STACK_NOINIT(rx_thread_stack, CONFIG_BLUETOOTH_RX_STACK_SIZE);
|
||||
#endif
|
||||
static BT_STACK_NOINIT(cmd_tx_thread_stack, CONFIG_BLUETOOTH_HCI_TX_STACK_SIZE);
|
||||
static BT_STACK_NOINIT(tx_thread_stack, CONFIG_BLUETOOTH_HCI_TX_STACK_SIZE);
|
||||
|
||||
static void init_work(struct k_work *work);
|
||||
|
||||
|
@ -552,8 +552,8 @@ static void hci_disconn_complete(struct net_buf *buf)
|
|||
#if !defined(CONFIG_BLUETOOTH_RECV_IS_RX_THREAD)
|
||||
stack_analyze("rx stack", rx_thread_stack, sizeof(rx_thread_stack));
|
||||
#endif
|
||||
stack_analyze("cmd tx stack", cmd_tx_thread_stack,
|
||||
sizeof(cmd_tx_thread_stack));
|
||||
stack_analyze("tx stack", tx_thread_stack,
|
||||
sizeof(tx_thread_stack));
|
||||
|
||||
bt_conn_set_state(conn, BT_CONN_DISCONNECTED);
|
||||
conn->handle = 0;
|
||||
|
@ -2669,22 +2669,20 @@ static void hci_event(struct net_buf *buf)
|
|||
net_buf_unref(buf);
|
||||
}
|
||||
|
||||
static void hci_cmd_tx_thread(void)
|
||||
static void send_cmd(void)
|
||||
{
|
||||
BT_DBG("started");
|
||||
|
||||
while (1) {
|
||||
struct net_buf *buf;
|
||||
int err;
|
||||
|
||||
/* Get next command */
|
||||
BT_DBG("calling net_buf_get");
|
||||
buf = net_buf_get(&bt_dev.cmd_tx_queue, K_NO_WAIT);
|
||||
BT_ASSERT(buf);
|
||||
|
||||
/* Wait until ncmd > 0 */
|
||||
BT_DBG("calling sem_take_wait");
|
||||
k_sem_take(&bt_dev.ncmd_sem, K_FOREVER);
|
||||
|
||||
/* Get next command - wait if necessary */
|
||||
BT_DBG("calling net_buf_get");
|
||||
buf = net_buf_get(&bt_dev.cmd_tx_queue, K_FOREVER);
|
||||
|
||||
/* Clear out any existing sent command */
|
||||
if (bt_dev.sent_cmd) {
|
||||
BT_ERR("Uncleared pending sent_cmd");
|
||||
|
@ -2707,9 +2705,83 @@ static void hci_cmd_tx_thread(void)
|
|||
bt_dev.sent_cmd = NULL;
|
||||
net_buf_unref(buf);
|
||||
}
|
||||
}
|
||||
|
||||
static void process_events(struct k_poll_event *ev, int count)
|
||||
{
|
||||
BT_DBG("count %d", count);
|
||||
|
||||
for (; count; ev++, count--) {
|
||||
BT_DBG("ev->state %u", ev->state);
|
||||
|
||||
switch (ev->state) {
|
||||
case K_POLL_STATE_SIGNALED:
|
||||
break;
|
||||
case K_POLL_STATE_FIFO_DATA_AVAILABLE:
|
||||
if (ev->tag == BT_EVENT_CMD_TX) {
|
||||
send_cmd();
|
||||
} else if (IS_ENABLED(CONFIG_BLUETOOTH_CONN) &&
|
||||
ev->tag == BT_EVENT_CONN_TX) {
|
||||
struct bt_conn *conn;
|
||||
|
||||
conn = CONTAINER_OF(ev->fifo, struct bt_conn,
|
||||
tx_queue);
|
||||
bt_conn_process_tx(conn);
|
||||
}
|
||||
break;
|
||||
case K_POLL_STATE_NOT_READY:
|
||||
break;
|
||||
default:
|
||||
BT_WARN("Unexpected k_poll event state %u", ev->state);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(CONFIG_BLUETOOTH_CONN)
|
||||
/* command FIFO + conn_change signal + MAX_CONN */
|
||||
#define EV_COUNT (2 + CONFIG_BLUETOOTH_MAX_CONN)
|
||||
#else
|
||||
/* command FIFO */
|
||||
#define EV_COUNT 1
|
||||
#endif
|
||||
|
||||
static void hci_tx_thread(void *p1, void *p2, void *p3)
|
||||
{
|
||||
static struct k_poll_event events[EV_COUNT] = {
|
||||
K_POLL_EVENT_STATIC_INITIALIZER(K_POLL_TYPE_FIFO_DATA_AVAILABLE,
|
||||
K_POLL_MODE_NOTIFY_ONLY,
|
||||
&bt_dev.cmd_tx_queue,
|
||||
BT_EVENT_CMD_TX),
|
||||
};
|
||||
|
||||
BT_DBG("Started");
|
||||
|
||||
while (1) {
|
||||
int ev_count, err;
|
||||
|
||||
events[0].state = K_POLL_STATE_NOT_READY;
|
||||
ev_count = 1;
|
||||
|
||||
if (IS_ENABLED(CONFIG_BLUETOOTH_CONN)) {
|
||||
ev_count += bt_conn_prepare_events(&events[1]);
|
||||
}
|
||||
|
||||
BT_DBG("Calling k_poll with %d events", ev_count);
|
||||
|
||||
err = k_poll(events, ev_count, K_FOREVER);
|
||||
BT_ASSERT(err == 0);
|
||||
|
||||
process_events(events, ev_count);
|
||||
|
||||
/* Make sure we don't hog the CPU if there's all the time
|
||||
* some ready events.
|
||||
*/
|
||||
k_yield();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void read_local_ver_complete(struct net_buf *buf)
|
||||
{
|
||||
struct bt_hci_rp_read_local_version_info *rp = (void *)buf->data;
|
||||
|
@ -3634,9 +3706,9 @@ int bt_enable(bt_ready_cb_t cb)
|
|||
ready_cb = cb;
|
||||
|
||||
/* TX thread */
|
||||
k_thread_spawn(cmd_tx_thread_stack, sizeof(cmd_tx_thread_stack),
|
||||
(k_thread_entry_t)hci_cmd_tx_thread, NULL, NULL, NULL,
|
||||
K_PRIO_COOP(7), 0, K_NO_WAIT);
|
||||
k_thread_spawn(tx_thread_stack, sizeof(tx_thread_stack),
|
||||
hci_tx_thread, NULL, NULL, NULL, K_PRIO_COOP(7), 0,
|
||||
K_NO_WAIT);
|
||||
|
||||
#if !defined(CONFIG_BLUETOOTH_RECV_IS_RX_THREAD)
|
||||
/* RX thread */
|
||||
|
|
|
@ -16,6 +16,12 @@
|
|||
#define LMP_FEAT_PAGES_COUNT 1
|
||||
#endif
|
||||
|
||||
/* k_poll event tags */
|
||||
enum {
|
||||
BT_EVENT_CMD_TX,
|
||||
BT_EVENT_CONN_TX,
|
||||
};
|
||||
|
||||
/* bt_dev flags: the flags defined here represent BT controller state */
|
||||
enum {
|
||||
BT_DEV_ENABLE,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue