From a50a21e8eebb1d2d0faf985870d3dee14a32ba87 Mon Sep 17 00:00:00 2001 From: Mat Martineau Date: Wed, 18 May 2011 09:02:02 -0700 Subject: [PATCH] Bluetooth: Add socket buffer headroom for Qualcomm PAL headers. The Qualcomm AMP PAL needs room to add 802.11 headers to outgoing frames, but the extra memory overhead is not necessary in other cases. CRs-fixed: 288438 Change-Id: Ie546bf702d56e80918c54019b4b0bb4c8bb40e0b Signed-off-by: Mat Martineau --- include/net/bluetooth/bluetooth.h | 1 + net/bluetooth/l2cap_core.c | 28 +++++++++++++++++++++++++--- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index e176c63b2a3..c3d5d63ba90 100644 --- a/include/net/bluetooth/bluetooth.h +++ b/include/net/bluetooth/bluetooth.h @@ -38,6 +38,7 @@ /* Reserv for core and drivers use */ #define BT_SKB_RESERVE 8 +#define BT_SKB_RESERVE_80211 32 #define BTPROTO_L2CAP 0 #define BTPROTO_HCI 1 diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index c56857dafc2..6c8053b5809 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1632,6 +1632,7 @@ struct sk_buff *l2cap_create_iframe_pdu(struct sock *sk, { struct sk_buff *skb; int err, count, hlen; + int reserve = 0; struct l2cap_hdr *lh; u8 fcs = l2cap_pi(sk)->fcs; @@ -1651,20 +1652,32 @@ struct sk_buff *l2cap_create_iframe_pdu(struct sock *sk, count = min_t(unsigned int, (l2cap_pi(sk)->conn->mtu - hlen), len); + /* Allocate extra headroom for Qualcomm PAL. This is only + * necessary in two places (here and when creating sframes) + * because only unfragmented iframes and sframes are sent + * using AMP controllers. + */ + if (l2cap_pi(sk)->ampcon && + l2cap_pi(sk)->ampcon->hdev->manufacturer == 0x001d) + reserve = BT_SKB_RESERVE_80211; + /* Don't use bt_skb_send_alloc() while resegmenting, since * it is not ok to block. */ if (reseg) { - skb = bt_skb_alloc(count + hlen, GFP_ATOMIC); + skb = bt_skb_alloc(count + hlen + reserve, GFP_ATOMIC); if (skb) skb_set_owner_w(skb, sk); } else { - skb = bt_skb_send_alloc(sk, count + hlen, + skb = bt_skb_send_alloc(sk, count + hlen + reserve, msg->msg_flags & MSG_DONTWAIT, &err); } if (!skb) return ERR_PTR(err); + if (reserve) + skb_reserve(skb, reserve); + bt_cb(skb)->control.fcs = fcs; /* Create L2CAP header */ @@ -1731,6 +1744,7 @@ static struct sk_buff *l2cap_create_sframe_pdu(struct sock *sk, u32 control) { struct sk_buff *skb; int len; + int reserve = 0; struct l2cap_hdr *lh; if (l2cap_pi(sk)->extended_control) @@ -1741,11 +1755,19 @@ static struct sk_buff *l2cap_create_sframe_pdu(struct sock *sk, u32 control) if (l2cap_pi(sk)->fcs == L2CAP_FCS_CRC16) len += L2CAP_FCS_SIZE; - skb = bt_skb_alloc(len, GFP_ATOMIC); + /* Allocate extra headroom for Qualcomm PAL */ + if (l2cap_pi(sk)->ampcon && + l2cap_pi(sk)->ampcon->hdev->manufacturer == 0x001d) + reserve = BT_SKB_RESERVE_80211; + + skb = bt_skb_alloc(len + reserve, GFP_ATOMIC); if (!skb) return ERR_PTR(-ENOMEM); + if (reserve) + skb_reserve(skb, reserve); + lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE); lh->cid = cpu_to_le16(l2cap_pi(sk)->dcid); lh->len = cpu_to_le16(len - L2CAP_HDR_SIZE);