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;
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)
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;
break;
}
}
- mwl8k_add_dma_header(skb, data_pad);
+ mwl8k_add_dma_header(priv, skb, data_pad);
}
/*
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;
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;