ath10k: properly remove padding from the start of rx payload
authorVasanthakumar Thiagarajan <vthiagar@qti.qualcomm.com>
Fri, 9 Sep 2016 14:25:29 +0000 (17:25 +0300)
committerKalle Valo <kvalo@qca.qualcomm.com>
Tue, 13 Sep 2016 12:31:02 +0000 (15:31 +0300)
In QCA99X0 (QCA99X0, QCA9984, QCA9888 and QCA4019) family chips,
hw adds padding at the begining of the rx payload to make L3
header 4-byte aligned. In the chips doing this type of padding,
the number of bytes padded will be indicated through msdu_end:info1.
Define a hw_rx_desc_ops wrapper to retrieve the number of padded
bytes and use this while doing undecap. This should fix padding
related issues with ethernt decap format with QCA99X0, QCA9984,
QCA9888 and QCA4019 hw.

Signed-off-by: Vasanthakumar Thiagarajan <vthiagar@qti.qualcomm.com>
[Rename operations to hw_ops for other purposes]
Signed-off-by: Benjamin Berg <benjamin@sipsolutions.net>
Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
drivers/net/wireless/ath/ath10k/htt_rx.c
drivers/net/wireless/ath/ath10k/hw.h

index 714b0deded9cdd63a8477fa3f693a9911228194c..a3785a9aa843cddb409cbac8dc2ca661662e83cc 100644 (file)
@@ -1051,9 +1051,11 @@ static void ath10k_htt_rx_h_undecap_nwifi(struct ath10k *ar,
                                          const u8 first_hdr[64])
 {
        struct ieee80211_hdr *hdr;
+       struct htt_rx_desc *rxd;
        size_t hdr_len;
        u8 da[ETH_ALEN];
        u8 sa[ETH_ALEN];
+       int l3_pad_bytes;
 
        /* Delivered decapped frame:
         * [nwifi 802.11 header] <-- replaced with 802.11 hdr
@@ -1067,19 +1069,12 @@ static void ath10k_htt_rx_h_undecap_nwifi(struct ath10k *ar,
         */
 
        /* pull decapped header and copy SA & DA */
-       if ((ar->hw_params.hw_4addr_pad == ATH10K_HW_4ADDR_PAD_BEFORE) &&
-           ieee80211_has_a4(((struct ieee80211_hdr *)first_hdr)->frame_control)) {
-               /* The QCA99X0 4 address mode pad 2 bytes at the
-                * beginning of MSDU
-                */
-               hdr = (struct ieee80211_hdr *)(msdu->data + 2);
-               /* The skb length need be extended 2 as the 2 bytes at the tail
-                * be excluded due to the padding
-                */
-               skb_put(msdu, 2);
-       } else {
-               hdr = (struct ieee80211_hdr *)(msdu->data);
-       }
+       rxd = (void *)msdu->data - sizeof(*rxd);
+
+       l3_pad_bytes = ath10k_rx_desc_get_l3_pad_bytes(&ar->hw_params, rxd);
+       skb_put(msdu, l3_pad_bytes);
+
+       hdr = (struct ieee80211_hdr *)(msdu->data + l3_pad_bytes);
 
        hdr_len = ath10k_htt_rx_nwifi_hdrlen(ar, hdr);
        ether_addr_copy(da, ieee80211_get_DA(hdr));
@@ -1146,6 +1141,8 @@ static void ath10k_htt_rx_h_undecap_eth(struct ath10k *ar,
        void *rfc1042;
        u8 da[ETH_ALEN];
        u8 sa[ETH_ALEN];
+       int l3_pad_bytes;
+       struct htt_rx_desc *rxd;
 
        /* Delivered decapped frame:
         * [eth header] <-- replaced with 802.11 hdr & rfc1042/llc
@@ -1156,6 +1153,11 @@ static void ath10k_htt_rx_h_undecap_eth(struct ath10k *ar,
        if (WARN_ON_ONCE(!rfc1042))
                return;
 
+       rxd = (void *)msdu->data - sizeof(*rxd);
+       l3_pad_bytes = ath10k_rx_desc_get_l3_pad_bytes(&ar->hw_params, rxd);
+       skb_put(msdu, l3_pad_bytes);
+       skb_pull(msdu, l3_pad_bytes);
+
        /* pull decapped header and copy SA & DA */
        eth = (struct ethhdr *)msdu->data;
        ether_addr_copy(da, eth->h_dest);
@@ -1186,6 +1188,8 @@ static void ath10k_htt_rx_h_undecap_snap(struct ath10k *ar,
 {
        struct ieee80211_hdr *hdr;
        size_t hdr_len;
+       int l3_pad_bytes;
+       struct htt_rx_desc *rxd;
 
        /* Delivered decapped frame:
         * [amsdu header] <-- replaced with 802.11 hdr
@@ -1193,7 +1197,11 @@ static void ath10k_htt_rx_h_undecap_snap(struct ath10k *ar,
         * [payload]
         */
 
-       skb_pull(msdu, sizeof(struct amsdu_subframe_hdr));
+       rxd = (void *)msdu->data - sizeof(*rxd);
+       l3_pad_bytes = ath10k_rx_desc_get_l3_pad_bytes(&ar->hw_params, rxd);
+
+       skb_put(msdu, l3_pad_bytes);
+       skb_pull(msdu, sizeof(struct amsdu_subframe_hdr) + l3_pad_bytes);
 
        hdr = (struct ieee80211_hdr *)first_hdr;
        hdr_len = ieee80211_hdrlen(hdr->frame_control);
index 1b5ea3147f3ae8306d439a8dd1d7fc692826e878..204f88273572c59f7349d374e99eeb899f6726c0 100644 (file)
@@ -428,6 +428,15 @@ struct ath10k_hw_ops {
 extern const struct ath10k_hw_ops qca988x_ops;
 extern const struct ath10k_hw_ops qca99x0_ops;
 
+static inline int
+ath10k_rx_desc_get_l3_pad_bytes(struct ath10k_hw_params *hw,
+                               struct htt_rx_desc *rxd)
+{
+       if (hw->hw_ops->rx_desc_get_l3_pad_bytes)
+               return hw->hw_ops->rx_desc_get_l3_pad_bytes(rxd);
+       return 0;
+}
+
 /* Target specific defines for MAIN firmware */
 #define TARGET_NUM_VDEVS                       8
 #define TARGET_NUM_PEER_AST                    2