Skip to content

Commit

Permalink
Bluetooth: conn: Defer bt_conn_tx callback to system wq
Browse files Browse the repository at this point in the history
This makes the transmission complete callbacks to run on system wq
context so they are not executed in TX thread which usually has a much
smaller, and non-configurable, stack size.

Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
  • Loading branch information
Vudentz authored and jhedberg committed Jun 4, 2019
1 parent 648a53d commit 8a7615f
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 27 deletions.
71 changes: 44 additions & 27 deletions subsys/bluetooth/host/conn.c
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ static struct bt_conn_cb *callback_list;
#define conn_tx(buf) ((struct bt_conn_tx_data *)net_buf_user_data(buf)) #define conn_tx(buf) ((struct bt_conn_tx_data *)net_buf_user_data(buf))


static struct bt_conn_tx conn_tx[CONFIG_BT_CONN_TX_MAX]; static struct bt_conn_tx conn_tx[CONFIG_BT_CONN_TX_MAX];
static sys_slist_t free_tx = SYS_SLIST_STATIC_INIT(&free_tx); K_FIFO_DEFINE(free_tx);


#if defined(CONFIG_BT_BREDR) #if defined(CONFIG_BT_BREDR)
static struct bt_conn sco_conns[CONFIG_BT_MAX_SCO_CONN]; static struct bt_conn sco_conns[CONFIG_BT_MAX_SCO_CONN];
Expand Down Expand Up @@ -287,6 +287,30 @@ static void conn_le_update_timeout(struct k_work *work)
atomic_set_bit(conn->flags, BT_CONN_SLAVE_PARAM_UPDATE); atomic_set_bit(conn->flags, BT_CONN_SLAVE_PARAM_UPDATE);
} }


static void tx_free(struct bt_conn_tx *tx)
{
if (tx->conn) {
bt_conn_unref(tx->conn);
tx->conn = NULL;
}

tx->data.cb = NULL;
tx->data.user_data = NULL;
k_fifo_put(&free_tx, tx);
}

static void tx_notify_cb(struct k_work *work)
{
struct bt_conn_tx *tx = CONTAINER_OF(work, struct bt_conn_tx, work);

BT_DBG("tx %p conn %p cb %p user_data %p", tx, tx->conn, tx->data.cb,
tx->data.user_data);

tx->data.cb(tx->conn, tx->data.user_data);

tx_free(tx);
}

static struct bt_conn *conn_new(void) static struct bt_conn *conn_new(void)
{ {
struct bt_conn *conn = NULL; struct bt_conn *conn = NULL;
Expand Down Expand Up @@ -1166,13 +1190,6 @@ int bt_conn_send_cb(struct bt_conn *conn, struct net_buf *buf,
return 0; return 0;
} }


static void tx_free(struct bt_conn_tx *tx)
{
tx->data.cb = NULL;
tx->data.user_data = NULL;
sys_slist_prepend(&free_tx, &tx->node);
}

void bt_conn_notify_tx(struct bt_conn *conn) void bt_conn_notify_tx(struct bt_conn *conn)
{ {
struct bt_conn_tx *tx; struct bt_conn_tx *tx;
Expand All @@ -1181,11 +1198,13 @@ void bt_conn_notify_tx(struct bt_conn *conn)


while ((tx = k_fifo_get(&conn->tx_notify, K_NO_WAIT))) { while ((tx = k_fifo_get(&conn->tx_notify, K_NO_WAIT))) {
BT_DBG("cb %p user_data %p", tx->data.cb, tx->data.user_data); BT_DBG("cb %p user_data %p", tx->data.cb, tx->data.user_data);

/* Only submit if there is a callback set */
if (tx->data.cb) { if (tx->data.cb) {
tx->data.cb(conn, tx->data.user_data); k_work_submit(&tx->work);
} else {
tx_free(tx);
} }

tx_free(tx);
} }
} }


Expand All @@ -1205,45 +1224,43 @@ static void notify_tx(void)
} }
} }


static sys_snode_t *add_pending_tx(struct bt_conn *conn, bt_conn_tx_cb_t cb, static struct bt_conn_tx *add_pending_tx(struct bt_conn *conn,
void *user_data) bt_conn_tx_cb_t cb, void *user_data)
{ {
struct bt_conn_tx *tx; struct bt_conn_tx *tx;
sys_snode_t *node;
unsigned int key; unsigned int key;


BT_DBG("conn %p cb %p user_data %p", conn, cb, user_data); BT_DBG("conn %p cb %p user_data %p", conn, cb, user_data);


__ASSERT(!sys_slist_is_empty(&free_tx), "No free conn TX contexts"); tx = k_fifo_get(&free_tx, K_FOREVER);

tx->conn = bt_conn_ref(conn);
node = sys_slist_get_not_empty(&free_tx); k_work_init(&tx->work, tx_notify_cb);
tx = CONTAINER_OF(node, struct bt_conn_tx, node);
tx->data.cb = cb; tx->data.cb = cb;
tx->data.user_data = user_data; tx->data.user_data = user_data;


key = irq_lock(); key = irq_lock();
sys_slist_append(&conn->tx_pending, node); sys_slist_append(&conn->tx_pending, &tx->node);
irq_unlock(key); irq_unlock(key);


return node; return tx;
} }


static void remove_pending_tx(struct bt_conn *conn, sys_snode_t *node) static void remove_pending_tx(struct bt_conn *conn, struct bt_conn_tx *tx)
{ {
unsigned int key; unsigned int key;


key = irq_lock(); key = irq_lock();
sys_slist_find_and_remove(&conn->tx_pending, node); sys_slist_find_and_remove(&conn->tx_pending, &tx->node);
irq_unlock(key); irq_unlock(key);


tx_free(CONTAINER_OF(node, struct bt_conn_tx, node)); tx_free(tx);
} }


static bool send_frag(struct bt_conn *conn, struct net_buf *buf, u8_t flags, static bool send_frag(struct bt_conn *conn, struct net_buf *buf, u8_t flags,
bool always_consume) bool always_consume)
{ {
struct bt_hci_acl_hdr *hdr; struct bt_hci_acl_hdr *hdr;
sys_snode_t *node; struct bt_conn_tx *tx;
int err; int err;


BT_DBG("conn %p buf %p len %u flags 0x%02x", conn, buf, buf->len, BT_DBG("conn %p buf %p len %u flags 0x%02x", conn, buf, buf->len,
Expand All @@ -1265,14 +1282,14 @@ static bool send_frag(struct bt_conn *conn, struct net_buf *buf, u8_t flags,
hdr->len = sys_cpu_to_le16(buf->len - sizeof(*hdr)); hdr->len = sys_cpu_to_le16(buf->len - sizeof(*hdr));


/* Add to pending, it must be done before bt_buf_set_type */ /* Add to pending, it must be done before bt_buf_set_type */
node = add_pending_tx(conn, conn_tx(buf)->cb, conn_tx(buf)->user_data); tx = add_pending_tx(conn, conn_tx(buf)->cb, conn_tx(buf)->user_data);


bt_buf_set_type(buf, BT_BUF_ACL_OUT); bt_buf_set_type(buf, BT_BUF_ACL_OUT);


err = bt_send(buf); err = bt_send(buf);
if (err) { if (err) {
BT_ERR("Unable to send to driver (err %d)", err); BT_ERR("Unable to send to driver (err %d)", err);
remove_pending_tx(conn, node); remove_pending_tx(conn, tx);
goto fail; goto fail;
} }


Expand Down Expand Up @@ -2294,7 +2311,7 @@ int bt_conn_init(void)
int err, i; int err, i;


for (i = 0; i < ARRAY_SIZE(conn_tx); i++) { for (i = 0; i < ARRAY_SIZE(conn_tx); i++) {
sys_slist_prepend(&free_tx, &conn_tx[i].node); k_fifo_put(&free_tx, &conn_tx[i]);
} }


bt_att_init(); bt_att_init();
Expand Down
2 changes: 2 additions & 0 deletions subsys/bluetooth/host/conn_internal.h
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -88,6 +88,8 @@ struct bt_conn_tx_data {


struct bt_conn_tx { struct bt_conn_tx {
sys_snode_t node; sys_snode_t node;
struct bt_conn *conn;
struct k_work work;
struct bt_conn_tx_data data; struct bt_conn_tx_data data;
}; };


Expand Down

0 comments on commit 8a7615f

Please sign in to comment.