Skip to content

Commit 0a925bd

Browse files
Johan Hedbergjhedberg
authored andcommitted
Bluetooth: L2CAP: Process fixed channels in the RX thread
Now that the TX path and TX context (bt_conn_tx) has been redesigned to free the contexts always in the system workqueue, it means the system workqueue is the only context where their allocation may also fail. This is particularly problematic with us having all L2CAP channels (fixed & CoC alike) deferred to the system workqueue. It is especially bad for fixed channels where being able to send responses for SM, L2CAP signaling and ATT is critical to avoid timeouts for the connection. This patch moves the processing of all fixed L2CAP channels back to the RX thread, thereby making it possible (and safe) to block while waiting for a TX context to become available. Signed-off-by: Johan Hedberg <[email protected]>
1 parent a065e57 commit 0a925bd

File tree

2 files changed

+26
-29
lines changed

2 files changed

+26
-29
lines changed

include/bluetooth/l2cap.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,9 +90,6 @@ struct bt_l2cap_chan {
9090
struct k_delayed_work rtx_work;
9191
ATOMIC_DEFINE(status, BT_L2CAP_NUM_STATUS);
9292

93-
struct k_work rx_work;
94-
struct k_fifo rx_queue;
95-
9693
#if defined(CONFIG_BT_L2CAP_DYNAMIC_CHANNEL)
9794
bt_l2cap_chan_state_t state;
9895
/** Remote PSM to be connected */
@@ -132,6 +129,9 @@ struct bt_l2cap_le_chan {
132129
/** Segment SDU packet from upper layer */
133130
struct net_buf *_sdu;
134131
u16_t _sdu_len;
132+
133+
struct k_work rx_work;
134+
struct k_fifo rx_queue;
135135
};
136136

137137
/** @def BT_L2CAP_LE_CHAN(_ch)

subsys/bluetooth/host/l2cap.c

Lines changed: 23 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
#include "l2cap_internal.h"
2828

2929
#define LE_CHAN_RTX(_w) CONTAINER_OF(_w, struct bt_l2cap_le_chan, chan.rtx_work)
30-
#define CHAN_RX(_w) CONTAINER_OF(_w, struct bt_l2cap_chan, rx_work)
30+
#define CHAN_RX(_w) CONTAINER_OF(_w, struct bt_l2cap_le_chan, rx_work)
3131

3232
#define L2CAP_LE_MIN_MTU 23
3333

@@ -221,8 +221,6 @@ void bt_l2cap_chan_set_state(struct bt_l2cap_chan *chan,
221221

222222
void bt_l2cap_chan_del(struct bt_l2cap_chan *chan)
223223
{
224-
struct net_buf *buf;
225-
226224
BT_DBG("conn %p chan %p", chan->conn, chan);
227225

228226
if (!chan->conn) {
@@ -242,11 +240,6 @@ void bt_l2cap_chan_del(struct bt_l2cap_chan *chan)
242240
chan->psm = 0U;
243241
#endif
244242

245-
/* Remove buffers on the RX queue */
246-
while ((buf = net_buf_get(&chan->rx_queue, K_NO_WAIT))) {
247-
net_buf_unref(buf);
248-
}
249-
250243
if (chan->destroy) {
251244
chan->destroy(chan);
252245
}
@@ -262,19 +255,22 @@ static void l2cap_rtx_timeout(struct k_work *work)
262255
bt_l2cap_chan_del(&chan->chan);
263256
}
264257

265-
static void l2cap_chan_recv(struct bt_l2cap_chan *chan, struct net_buf *buf);
258+
#if defined(CONFIG_BT_L2CAP_DYNAMIC_CHANNEL)
259+
static void l2cap_chan_le_recv(struct bt_l2cap_le_chan *chan,
260+
struct net_buf *buf);
266261

267262
static void l2cap_rx_process(struct k_work *work)
268263
{
269-
struct bt_l2cap_chan *chan = CHAN_RX(work);
264+
struct bt_l2cap_le_chan *ch = CHAN_RX(work);
270265
struct net_buf *buf;
271266

272-
while ((buf = net_buf_get(&chan->rx_queue, K_NO_WAIT))) {
273-
BT_DBG("chan %p buf %p", chan, buf);
274-
l2cap_chan_recv(chan, buf);
267+
while ((buf = net_buf_get(&ch->rx_queue, K_NO_WAIT))) {
268+
BT_DBG("ch %p buf %p", ch, buf);
269+
l2cap_chan_le_recv(ch, buf);
275270
net_buf_unref(buf);
276271
}
277272
}
273+
#endif /* CONFIG_BT_L2CAP_DYNAMIC_CHANNEL */
278274

279275
void bt_l2cap_chan_add(struct bt_conn *conn, struct bt_l2cap_chan *chan,
280276
bt_l2cap_chan_destroy_t destroy)
@@ -304,15 +300,16 @@ static bool l2cap_chan_add(struct bt_conn *conn, struct bt_l2cap_chan *chan,
304300
}
305301

306302
k_delayed_work_init(&chan->rtx_work, l2cap_rtx_timeout);
307-
k_work_init(&chan->rx_work, l2cap_rx_process);
308-
k_fifo_init(&chan->rx_queue);
309303

310304
bt_l2cap_chan_add(conn, chan, destroy);
311305

312-
if (IS_ENABLED(CONFIG_BT_L2CAP_DYNAMIC_CHANNEL) &&
313-
L2CAP_LE_CID_IS_DYN(ch->rx.cid)) {
306+
#if defined(CONFIG_BT_L2CAP_DYNAMIC_CHANNEL)
307+
if (L2CAP_LE_CID_IS_DYN(ch->rx.cid)) {
308+
k_work_init(&ch->rx_work, l2cap_rx_process);
309+
k_fifo_init(&ch->rx_queue);
314310
bt_l2cap_chan_set_state(chan, BT_L2CAP_CONNECT);
315311
}
312+
#endif /* CONFIG_BT_L2CAP_DYNAMIC_CHANNEL */
316313

317314
return true;
318315
}
@@ -759,6 +756,11 @@ static void l2cap_chan_destroy(struct bt_l2cap_chan *chan)
759756
net_buf_unref(buf);
760757
}
761758

759+
/* Remove buffers on the RX queue */
760+
while ((buf = net_buf_get(&ch->rx_queue, K_NO_WAIT))) {
761+
net_buf_unref(buf);
762+
}
763+
762764
/* Destroy segmented SDU if it exists */
763765
if (ch->_sdu) {
764766
net_buf_unref(ch->_sdu);
@@ -1660,7 +1662,8 @@ static void l2cap_chan_recv(struct bt_l2cap_chan *chan, struct net_buf *buf)
16601662
struct bt_l2cap_le_chan *ch = BT_L2CAP_LE_CHAN(chan);
16611663

16621664
if (L2CAP_LE_CID_IS_DYN(ch->rx.cid)) {
1663-
l2cap_chan_le_recv(ch, buf);
1665+
net_buf_put(&ch->rx_queue, net_buf_ref(buf));
1666+
k_work_submit(&ch->rx_work);
16641667
return;
16651668
}
16661669
#endif /* CONFIG_BT_L2CAP_DYNAMIC_CHANNEL */
@@ -1670,13 +1673,6 @@ static void l2cap_chan_recv(struct bt_l2cap_chan *chan, struct net_buf *buf)
16701673
chan->ops->recv(chan, buf);
16711674
}
16721675

1673-
static void l2cap_chan_recv_queue(struct bt_l2cap_chan *chan,
1674-
struct net_buf *buf)
1675-
{
1676-
net_buf_put(&chan->rx_queue, buf);
1677-
k_work_submit(&chan->rx_work);
1678-
}
1679-
16801676
void bt_l2cap_recv(struct bt_conn *conn, struct net_buf *buf)
16811677
{
16821678
struct bt_l2cap_hdr *hdr;
@@ -1707,7 +1703,8 @@ void bt_l2cap_recv(struct bt_conn *conn, struct net_buf *buf)
17071703
return;
17081704
}
17091705

1710-
l2cap_chan_recv_queue(chan, buf);
1706+
l2cap_chan_recv(chan, buf);
1707+
net_buf_unref(buf);
17111708
}
17121709

17131710
int bt_l2cap_update_conn_param(struct bt_conn *conn,

0 commit comments

Comments
 (0)