Commit fadd192e authored by Mat Martineau's avatar Mat Martineau Committed by Gustavo F. Padovan

Bluetooth: Remove L2CAP busy queue

The ERTM receive buffer is now handled in a way that does not require
the busy queue and the associated polling code.
Signed-off-by: default avatarMat Martineau <mathewm@codeaurora.org>
Signed-off-by: default avatarGustavo F. Padovan <padovan@profusion.mobi>
parent e328140f
...@@ -37,7 +37,6 @@ ...@@ -37,7 +37,6 @@
#define L2CAP_DEFAULT_MONITOR_TO 12000 /* 12 seconds */ #define L2CAP_DEFAULT_MONITOR_TO 12000 /* 12 seconds */
#define L2CAP_DEFAULT_MAX_PDU_SIZE 1009 /* Sized for 3-DH5 packet */ #define L2CAP_DEFAULT_MAX_PDU_SIZE 1009 /* Sized for 3-DH5 packet */
#define L2CAP_DEFAULT_ACK_TO 200 #define L2CAP_DEFAULT_ACK_TO 200
#define L2CAP_LOCAL_BUSY_TRIES 12
#define L2CAP_LE_DEFAULT_MTU 23 #define L2CAP_LE_DEFAULT_MTU 23
#define L2CAP_CONN_TIMEOUT (40000) /* 40 seconds */ #define L2CAP_CONN_TIMEOUT (40000) /* 40 seconds */
...@@ -352,8 +351,6 @@ struct l2cap_chan { ...@@ -352,8 +351,6 @@ struct l2cap_chan {
struct sk_buff *tx_send_head; struct sk_buff *tx_send_head;
struct sk_buff_head tx_q; struct sk_buff_head tx_q;
struct sk_buff_head srej_q; struct sk_buff_head srej_q;
struct sk_buff_head busy_q;
struct work_struct busy_work;
struct list_head srej_l; struct list_head srej_l;
struct list_head list; struct list_head list;
...@@ -450,7 +447,6 @@ enum { ...@@ -450,7 +447,6 @@ enum {
CONN_REJ_ACT, CONN_REJ_ACT,
CONN_SEND_FBIT, CONN_SEND_FBIT,
CONN_RNR_SENT, CONN_RNR_SENT,
CONN_SAR_RETRY,
}; };
#define __set_chan_timer(c, t) l2cap_set_timer(c, &c->chan_timer, (t)) #define __set_chan_timer(c, t) l2cap_set_timer(c, &c->chan_timer, (t))
......
...@@ -61,13 +61,9 @@ int disable_ertm; ...@@ -61,13 +61,9 @@ int disable_ertm;
static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN; static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN;
static u8 l2cap_fixed_chan[8] = { 0x02, }; static u8 l2cap_fixed_chan[8] = { 0x02, };
static struct workqueue_struct *_busy_wq;
static LIST_HEAD(chan_list); static LIST_HEAD(chan_list);
static DEFINE_RWLOCK(chan_list_lock); static DEFINE_RWLOCK(chan_list_lock);
static void l2cap_busy_work(struct work_struct *work);
static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn, static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
u8 code, u8 ident, u16 dlen, void *data); u8 code, u8 ident, u16 dlen, void *data);
static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len,
...@@ -395,7 +391,6 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err) ...@@ -395,7 +391,6 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err)
__clear_ack_timer(chan); __clear_ack_timer(chan);
skb_queue_purge(&chan->srej_q); skb_queue_purge(&chan->srej_q);
skb_queue_purge(&chan->busy_q);
list_for_each_entry_safe(l, tmp, &chan->srej_l, list) { list_for_each_entry_safe(l, tmp, &chan->srej_l, list) {
list_del(&l->list); list_del(&l->list);
...@@ -1873,11 +1868,9 @@ static inline void l2cap_ertm_init(struct l2cap_chan *chan) ...@@ -1873,11 +1868,9 @@ static inline void l2cap_ertm_init(struct l2cap_chan *chan)
setup_timer(&chan->ack_timer, l2cap_ack_timeout, (unsigned long) chan); setup_timer(&chan->ack_timer, l2cap_ack_timeout, (unsigned long) chan);
skb_queue_head_init(&chan->srej_q); skb_queue_head_init(&chan->srej_q);
skb_queue_head_init(&chan->busy_q);
INIT_LIST_HEAD(&chan->srej_l); INIT_LIST_HEAD(&chan->srej_l);
INIT_WORK(&chan->busy_work, l2cap_busy_work);
sk->sk_backlog_rcv = l2cap_ertm_data_rcv; sk->sk_backlog_rcv = l2cap_ertm_data_rcv;
} }
...@@ -3182,32 +3175,27 @@ static int l2cap_ertm_reassembly_sdu(struct l2cap_chan *chan, struct sk_buff *sk ...@@ -3182,32 +3175,27 @@ static int l2cap_ertm_reassembly_sdu(struct l2cap_chan *chan, struct sk_buff *sk
if (!chan->sdu) if (!chan->sdu)
goto disconnect; goto disconnect;
if (!test_bit(CONN_SAR_RETRY, &chan->conn_state)) { chan->partial_sdu_len += skb->len;
chan->partial_sdu_len += skb->len;
if (chan->partial_sdu_len > chan->imtu) if (chan->partial_sdu_len > chan->imtu)
goto drop; goto drop;
if (chan->partial_sdu_len != chan->sdu_len) if (chan->partial_sdu_len != chan->sdu_len)
goto drop; goto drop;
memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len); memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
}
_skb = skb_clone(chan->sdu, GFP_ATOMIC); _skb = skb_clone(chan->sdu, GFP_ATOMIC);
if (!_skb) { if (!_skb) {
set_bit(CONN_SAR_RETRY, &chan->conn_state);
return -ENOMEM; return -ENOMEM;
} }
err = chan->ops->recv(chan->data, _skb); err = chan->ops->recv(chan->data, _skb);
if (err < 0) { if (err < 0) {
kfree_skb(_skb); kfree_skb(_skb);
set_bit(CONN_SAR_RETRY, &chan->conn_state);
return err; return err;
} }
clear_bit(CONN_SAR_RETRY, &chan->conn_state);
clear_bit(CONN_SAR_SDU, &chan->conn_state); clear_bit(CONN_SAR_SDU, &chan->conn_state);
kfree_skb(chan->sdu); kfree_skb(chan->sdu);
...@@ -3268,93 +3256,6 @@ static void l2cap_ertm_exit_local_busy(struct l2cap_chan *chan) ...@@ -3268,93 +3256,6 @@ static void l2cap_ertm_exit_local_busy(struct l2cap_chan *chan)
BT_DBG("chan %p, Exit local busy", chan); BT_DBG("chan %p, Exit local busy", chan);
} }
static int l2cap_try_push_rx_skb(struct l2cap_chan *chan)
{
struct sk_buff *skb;
u16 control;
int err;
while ((skb = skb_dequeue(&chan->busy_q))) {
control = bt_cb(skb)->sar << L2CAP_CTRL_SAR_SHIFT;
err = l2cap_ertm_reassembly_sdu(chan, skb, control);
if (err < 0) {
skb_queue_head(&chan->busy_q, skb);
return -EBUSY;
}
chan->buffer_seq = (chan->buffer_seq + 1) % 64;
}
l2cap_ertm_exit_local_busy(chan);
return 0;
}
static void l2cap_busy_work(struct work_struct *work)
{
DECLARE_WAITQUEUE(wait, current);
struct l2cap_chan *chan =
container_of(work, struct l2cap_chan, busy_work);
struct sock *sk = chan->sk;
int n_tries = 0, timeo = HZ/5, err;
struct sk_buff *skb;
lock_sock(sk);
add_wait_queue(sk_sleep(sk), &wait);
while ((skb = skb_peek(&chan->busy_q))) {
set_current_state(TASK_INTERRUPTIBLE);
if (n_tries++ > L2CAP_LOCAL_BUSY_TRIES) {
err = -EBUSY;
l2cap_send_disconn_req(chan->conn, chan, EBUSY);
break;
}
if (!timeo)
timeo = HZ/5;
if (signal_pending(current)) {
err = sock_intr_errno(timeo);
break;
}
release_sock(sk);
timeo = schedule_timeout(timeo);
lock_sock(sk);
err = sock_error(sk);
if (err)
break;
if (l2cap_try_push_rx_skb(chan) == 0)
break;
}
set_current_state(TASK_RUNNING);
remove_wait_queue(sk_sleep(sk), &wait);
release_sock(sk);
}
static int l2cap_push_rx_skb(struct l2cap_chan *chan, struct sk_buff *skb, u16 control)
{
int err;
if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
bt_cb(skb)->sar = control >> L2CAP_CTRL_SAR_SHIFT;
__skb_queue_tail(&chan->busy_q, skb);
return l2cap_try_push_rx_skb(chan);
}
err = l2cap_ertm_reassembly_sdu(chan, skb, control);
chan->buffer_seq = (chan->buffer_seq + 1) % 64;
return err;
}
void l2cap_chan_busy(struct l2cap_chan *chan, int busy) void l2cap_chan_busy(struct l2cap_chan *chan, int busy)
{ {
if (chan->mode == L2CAP_MODE_ERTM) { if (chan->mode == L2CAP_MODE_ERTM) {
...@@ -3612,7 +3513,6 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_cont ...@@ -3612,7 +3513,6 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_cont
chan->buffer_seq_srej = chan->buffer_seq; chan->buffer_seq_srej = chan->buffer_seq;
__skb_queue_head_init(&chan->srej_q); __skb_queue_head_init(&chan->srej_q);
__skb_queue_head_init(&chan->busy_q);
l2cap_add_to_srej_queue(chan, skb, tx_seq, sar); l2cap_add_to_srej_queue(chan, skb, tx_seq, sar);
set_bit(CONN_SEND_PBIT, &chan->conn_state); set_bit(CONN_SEND_PBIT, &chan->conn_state);
...@@ -3633,7 +3533,8 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_cont ...@@ -3633,7 +3533,8 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_cont
return 0; return 0;
} }
err = l2cap_push_rx_skb(chan, skb, rx_control); err = l2cap_ertm_reassembly_sdu(chan, skb, rx_control);
chan->buffer_seq = (chan->buffer_seq + 1) % 64;
if (err < 0) { if (err < 0) {
l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
return err; return err;
...@@ -4439,12 +4340,6 @@ int __init l2cap_init(void) ...@@ -4439,12 +4340,6 @@ int __init l2cap_init(void)
if (err < 0) if (err < 0)
return err; return err;
_busy_wq = create_singlethread_workqueue("l2cap");
if (!_busy_wq) {
err = -ENOMEM;
goto error;
}
err = hci_register_proto(&l2cap_hci_proto); err = hci_register_proto(&l2cap_hci_proto);
if (err < 0) { if (err < 0) {
BT_ERR("L2CAP protocol registration failed"); BT_ERR("L2CAP protocol registration failed");
...@@ -4462,7 +4357,6 @@ int __init l2cap_init(void) ...@@ -4462,7 +4357,6 @@ int __init l2cap_init(void)
return 0; return 0;
error: error:
destroy_workqueue(_busy_wq);
l2cap_cleanup_sockets(); l2cap_cleanup_sockets();
return err; return err;
} }
...@@ -4471,9 +4365,6 @@ void l2cap_exit(void) ...@@ -4471,9 +4365,6 @@ void l2cap_exit(void)
{ {
debugfs_remove(l2cap_debugfs); debugfs_remove(l2cap_debugfs);
flush_workqueue(_busy_wq);
destroy_workqueue(_busy_wq);
if (hci_unregister_proto(&l2cap_hci_proto) < 0) if (hci_unregister_proto(&l2cap_hci_proto) < 0)
BT_ERR("L2CAP protocol unregistration failed"); BT_ERR("L2CAP protocol unregistration failed");
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment