diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 8a1b26255f03e4c10470565cc144118515fea260..9f5ecef297e5db5f9723d7a18a07e49e35e334c9 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -781,8 +781,10 @@ static inline void mwl8k_remove_dma_header(struct sk_buff *skb, __le16 qos) skb_pull(skb, sizeof(*tr) - hdrlen); } +#define REDUCED_TX_HEADROOM 8 + static void -mwl8k_add_dma_header(struct sk_buff *skb, int tail_pad) +mwl8k_add_dma_header(struct mwl8k_priv *priv, struct sk_buff *skb, int tail_pad) { struct ieee80211_hdr *wh; int hdrlen; @@ -798,6 +800,22 @@ mwl8k_add_dma_header(struct sk_buff *skb, int tail_pad) wh = (struct ieee80211_hdr *)skb->data; hdrlen = ieee80211_hdrlen(wh->frame_control); + + /* + * Check if skb_resize is required because of + * tx_headroom adjustment. + */ + if (priv->ap_fw && (hdrlen < (sizeof(struct ieee80211_cts) + + REDUCED_TX_HEADROOM))) { + if (pskb_expand_head(skb, REDUCED_TX_HEADROOM, 0, GFP_ATOMIC)) { + + wiphy_err(priv->hw->wiphy, + "Failed to reallocate TX buffer\n"); + return; + } + skb->truesize += REDUCED_TX_HEADROOM; + } + reqd_hdrlen = sizeof(*tr); if (hdrlen != reqd_hdrlen) @@ -820,7 +838,8 @@ mwl8k_add_dma_header(struct sk_buff *skb, int tail_pad) tr->fwlen = cpu_to_le16(skb->len - sizeof(*tr) + tail_pad); } -static void mwl8k_encapsulate_tx_frame(struct sk_buff *skb) +static void mwl8k_encapsulate_tx_frame(struct mwl8k_priv *priv, + struct sk_buff *skb) { struct ieee80211_hdr *wh; struct ieee80211_tx_info *tx_info; @@ -861,7 +880,7 @@ static void mwl8k_encapsulate_tx_frame(struct sk_buff *skb) break; } } - mwl8k_add_dma_header(skb, data_pad); + mwl8k_add_dma_header(priv, skb, data_pad); } /* @@ -1816,9 +1835,9 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) mgmtframe = true; if (priv->ap_fw) - mwl8k_encapsulate_tx_frame(skb); + mwl8k_encapsulate_tx_frame(priv, skb); else - mwl8k_add_dma_header(skb, 0); + mwl8k_add_dma_header(priv, skb, 0); wh = &((struct mwl8k_dma_data *)skb->data)->wh; @@ -5474,6 +5493,8 @@ static int mwl8k_firmware_load_success(struct mwl8k_priv *priv) hw->extra_tx_headroom = sizeof(struct mwl8k_dma_data) - sizeof(struct ieee80211_cts); + hw->extra_tx_headroom -= priv->ap_fw ? REDUCED_TX_HEADROOM : 0; + hw->channel_change_time = 10; hw->queues = MWL8K_TX_WMM_QUEUES;