aboutsummaryrefslogtreecommitdiffstats
path: root/net/bluetooth
diff options
context:
space:
mode:
authorLuiz Augusto von Dentz <luiz.von.dentz@intel.com>2018-09-04 06:39:21 -0400
committerMarcel Holtmann <marcel@holtmann.org>2018-09-27 06:52:08 -0400
commit96cd8eaa131f0ffd4cfae09e1b4bdfafb9570907 (patch)
tree6d5f16337fdb75ac7cc472ef78f35e82ba2b7cfc /net/bluetooth
parentfe1493101ac1313cbdbef1af65342fb17d944e71 (diff)
Bluetooth: L2CAP: Derive rx credits from MTU and MPS
Give enough rx credits for a full packet instead of using an arbitrary number which may not be enough depending on the MTU and MPS which can cause interruptions while waiting for more credits, also remove debugfs entry for l2cap_le_max_credits. With these changes the credits are restored after each SDU is received instead of using fixed threshold, this way it is garanteed that there will always be enough credits to send a packet without waiting more credits to arrive. Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Diffstat (limited to 'net/bluetooth')
-rw-r--r--net/bluetooth/l2cap_core.c42
1 files changed, 27 insertions, 15 deletions
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 8a60db6261f7..3fb2d757df88 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -51,8 +51,6 @@ static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN | L2CAP_FEAT_UCD;
51static LIST_HEAD(chan_list); 51static LIST_HEAD(chan_list);
52static DEFINE_RWLOCK(chan_list_lock); 52static DEFINE_RWLOCK(chan_list_lock);
53 53
54static u16 le_max_credits = L2CAP_LE_MAX_CREDITS;
55
56static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn, 54static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
57 u8 code, u8 ident, u16 dlen, void *data); 55 u8 code, u8 ident, u16 dlen, void *data);
58static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, 56static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len,
@@ -518,9 +516,10 @@ static void l2cap_le_flowctl_init(struct l2cap_chan *chan)
518 chan->sdu_last_frag = NULL; 516 chan->sdu_last_frag = NULL;
519 chan->sdu_len = 0; 517 chan->sdu_len = 0;
520 chan->tx_credits = 0; 518 chan->tx_credits = 0;
521 chan->rx_credits = le_max_credits;
522 /* Derive MPS from connection MTU to stop HCI fragmentation */ 519 /* Derive MPS from connection MTU to stop HCI fragmentation */
523 chan->mps = min_t(u16, chan->imtu, chan->conn->mtu - L2CAP_HDR_SIZE); 520 chan->mps = min_t(u16, chan->imtu, chan->conn->mtu - L2CAP_HDR_SIZE);
521 /* Give enough credits for a full packet */
522 chan->rx_credits = (chan->imtu / chan->mps) + 1;
524 523
525 skb_queue_head_init(&chan->tx_q); 524 skb_queue_head_init(&chan->tx_q);
526} 525}
@@ -6702,13 +6701,10 @@ static void l2cap_chan_le_send_credits(struct l2cap_chan *chan)
6702 struct l2cap_le_credits pkt; 6701 struct l2cap_le_credits pkt;
6703 u16 return_credits; 6702 u16 return_credits;
6704 6703
6705 /* We return more credits to the sender only after the amount of 6704 return_credits = ((chan->imtu / chan->mps) + 1) - chan->rx_credits;
6706 * credits falls below half of the initial amount.
6707 */
6708 if (chan->rx_credits >= (le_max_credits + 1) / 2)
6709 return;
6710 6705
6711 return_credits = le_max_credits - chan->rx_credits; 6706 if (!return_credits)
6707 return;
6712 6708
6713 BT_DBG("chan %p returning %u credits to sender", chan, return_credits); 6709 BT_DBG("chan %p returning %u credits to sender", chan, return_credits);
6714 6710
@@ -6722,6 +6718,21 @@ static void l2cap_chan_le_send_credits(struct l2cap_chan *chan)
6722 l2cap_send_cmd(conn, chan->ident, L2CAP_LE_CREDITS, sizeof(pkt), &pkt); 6718 l2cap_send_cmd(conn, chan->ident, L2CAP_LE_CREDITS, sizeof(pkt), &pkt);
6723} 6719}
6724 6720
6721static int l2cap_le_recv(struct l2cap_chan *chan, struct sk_buff *skb)
6722{
6723 int err;
6724
6725 BT_DBG("SDU reassemble complete: chan %p skb->len %u", chan, skb->len);
6726
6727 /* Wait recv to confirm reception before updating the credits */
6728 err = chan->ops->recv(chan, skb);
6729
6730 /* Update credits whenever an SDU is received */
6731 l2cap_chan_le_send_credits(chan);
6732
6733 return err;
6734}
6735
6725static int l2cap_le_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb) 6736static int l2cap_le_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb)
6726{ 6737{
6727 int err; 6738 int err;
@@ -6740,7 +6751,11 @@ static int l2cap_le_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb)
6740 chan->rx_credits--; 6751 chan->rx_credits--;
6741 BT_DBG("rx_credits %u -> %u", chan->rx_credits + 1, chan->rx_credits); 6752 BT_DBG("rx_credits %u -> %u", chan->rx_credits + 1, chan->rx_credits);
6742 6753
6743 l2cap_chan_le_send_credits(chan); 6754 /* Update if remote had run out of credits, this should only happens
6755 * if the remote is not using the entire MPS.
6756 */
6757 if (!chan->rx_credits)
6758 l2cap_chan_le_send_credits(chan);
6744 6759
6745 err = 0; 6760 err = 0;
6746 6761
@@ -6766,7 +6781,7 @@ static int l2cap_le_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb)
6766 } 6781 }
6767 6782
6768 if (skb->len == sdu_len) 6783 if (skb->len == sdu_len)
6769 return chan->ops->recv(chan, skb); 6784 return l2cap_le_recv(chan, skb);
6770 6785
6771 chan->sdu = skb; 6786 chan->sdu = skb;
6772 chan->sdu_len = sdu_len; 6787 chan->sdu_len = sdu_len;
@@ -6788,7 +6803,7 @@ static int l2cap_le_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb)
6788 skb = NULL; 6803 skb = NULL;
6789 6804
6790 if (chan->sdu->len == chan->sdu_len) { 6805 if (chan->sdu->len == chan->sdu_len) {
6791 err = chan->ops->recv(chan, chan->sdu); 6806 err = l2cap_le_recv(chan, chan->sdu);
6792 if (!err) { 6807 if (!err) {
6793 chan->sdu = NULL; 6808 chan->sdu = NULL;
6794 chan->sdu_last_frag = NULL; 6809 chan->sdu_last_frag = NULL;
@@ -7647,9 +7662,6 @@ int __init l2cap_init(void)
7647 l2cap_debugfs = debugfs_create_file("l2cap", 0444, bt_debugfs, 7662 l2cap_debugfs = debugfs_create_file("l2cap", 0444, bt_debugfs,
7648 NULL, &l2cap_debugfs_fops); 7663 NULL, &l2cap_debugfs_fops);
7649 7664
7650 debugfs_create_u16("l2cap_le_max_credits", 0644, bt_debugfs,
7651 &le_max_credits);
7652
7653 return 0; 7665 return 0;
7654} 7666}
7655 7667