ath10k: use rx descriptor for ppdu status extraction
authorMichal Kazior <michal.kazior@tieto.com>
Tue, 18 Nov 2014 07:24:49 +0000 (09:24 +0200)
committerKalle Valo <kvalo@qca.qualcomm.com>
Thu, 20 Nov 2014 13:43:59 +0000 (15:43 +0200)
This makes it more in line with the new Rx path.
It also makes the code more reusable because Rx
descriptor is more accessible.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
drivers/net/wireless/ath/ath10k/htt_rx.c

index 332abc7..3d503b0 100644 (file)
@@ -629,23 +629,34 @@ static const u8 rx_legacy_rate_idx[] = {
 };
 
 static void ath10k_htt_rx_h_rates(struct ath10k *ar,
-                                 enum ieee80211_band band,
-                                 u8 info0, u32 info1, u32 info2,
-                                 struct ieee80211_rx_status *status)
+                                 struct ieee80211_rx_status *status,
+                                 struct htt_rx_desc *rxd)
 {
+       enum ieee80211_band band;
        u8 cck, rate, rate_idx, bw, sgi, mcs, nss;
        u8 preamble = 0;
+       u32 info1, info2, info3;
 
-       /* Check if valid fields */
-       if (!(info0 & HTT_RX_INDICATION_INFO0_START_VALID))
+       /* Band value can't be set as undefined but freq can be 0 - use that to
+        * determine whether band is provided.
+        *
+        * FIXME: Perhaps this can go away if CCK rate reporting is a little
+        * reworked?
+        */
+       if (!status->freq)
                return;
 
-       preamble = MS(info1, HTT_RX_INDICATION_INFO1_PREAMBLE_TYPE);
+       band = status->band;
+       info1 = __le32_to_cpu(rxd->ppdu_start.info1);
+       info2 = __le32_to_cpu(rxd->ppdu_start.info2);
+       info3 = __le32_to_cpu(rxd->ppdu_start.info3);
+
+       preamble = MS(info1, RX_PPDU_START_INFO1_PREAMBLE_TYPE);
 
        switch (preamble) {
        case HTT_RX_LEGACY:
-               cck = info0 & HTT_RX_INDICATION_INFO0_LEGACY_RATE_CCK;
-               rate = MS(info0, HTT_RX_INDICATION_INFO0_LEGACY_RATE);
+               cck = info1 & RX_PPDU_START_INFO1_L_SIG_RATE_SELECT;
+               rate = MS(info1, RX_PPDU_START_INFO1_L_SIG_RATE);
                rate_idx = 0;
 
                if (rate < 0x08 || rate > 0x0F)
@@ -672,11 +683,11 @@ static void ath10k_htt_rx_h_rates(struct ath10k *ar,
                break;
        case HTT_RX_HT:
        case HTT_RX_HT_WITH_TXBF:
-               /* HT-SIG - Table 20-11 in info1 and info2 */
-               mcs = info1 & 0x1F;
+               /* HT-SIG - Table 20-11 in info2 and info3 */
+               mcs = info2 & 0x1F;
                nss = mcs >> 3;
-               bw = (info1 >> 7) & 1;
-               sgi = (info2 >> 7) & 1;
+               bw = (info2 >> 7) & 1;
+               sgi = (info3 >> 7) & 1;
 
                status->rate_idx = mcs;
                status->flag |= RX_FLAG_HT;
@@ -687,12 +698,12 @@ static void ath10k_htt_rx_h_rates(struct ath10k *ar,
                break;
        case HTT_RX_VHT:
        case HTT_RX_VHT_WITH_TXBF:
-               /* VHT-SIG-A1 in info 1, VHT-SIG-A2 in info2
+               /* VHT-SIG-A1 in info2, VHT-SIG-A2 in info3
                   TODO check this */
-               mcs = (info2 >> 4) & 0x0F;
-               nss = ((info1 >> 10) & 0x07) + 1;
-               bw = info1 & 3;
-               sgi = info2 & 1;
+               mcs = (info3 >> 4) & 0x0F;
+               nss = ((info2 >> 10) & 0x07) + 1;
+               bw = info2 & 3;
+               sgi = info3 & 1;
 
                status->rate_idx = mcs;
                status->vht_nss = nss;
@@ -740,6 +751,72 @@ static bool ath10k_htt_rx_h_channel(struct ath10k *ar,
        return true;
 }
 
+static void ath10k_htt_rx_h_signal(struct ath10k *ar,
+                                  struct ieee80211_rx_status *status,
+                                  struct htt_rx_desc *rxd)
+{
+       /* FIXME: Get real NF */
+       status->signal = ATH10K_DEFAULT_NOISE_FLOOR +
+                        rxd->ppdu_start.rssi_comb;
+       status->flag &= ~RX_FLAG_NO_SIGNAL_VAL;
+}
+
+static void ath10k_htt_rx_h_mactime(struct ath10k *ar,
+                                   struct ieee80211_rx_status *status,
+                                   struct htt_rx_desc *rxd)
+{
+       /* FIXME: TSF is known only at the end of PPDU, in the last MPDU. This
+        * means all prior MSDUs in a PPDU are reported to mac80211 without the
+        * TSF. Is it worth holding frames until end of PPDU is known?
+        *
+        * FIXME: Can we get/compute 64bit TSF?
+        */
+       status->mactime = __le32_to_cpu(rxd->ppdu_end.tsf_timestamp);
+       status->flag |= RX_FLAG_MACTIME_END;
+}
+
+static void ath10k_htt_rx_h_ppdu(struct ath10k *ar,
+                                struct sk_buff_head *amsdu,
+                                struct ieee80211_rx_status *status)
+{
+       struct sk_buff *first;
+       struct htt_rx_desc *rxd;
+       bool is_first_ppdu;
+       bool is_last_ppdu;
+
+       if (skb_queue_empty(amsdu))
+               return;
+
+       first = skb_peek(amsdu);
+       rxd = (void *)first->data - sizeof(*rxd);
+
+       is_first_ppdu = !!(rxd->attention.flags &
+                          __cpu_to_le32(RX_ATTENTION_FLAGS_FIRST_MPDU));
+       is_last_ppdu = !!(rxd->attention.flags &
+                         __cpu_to_le32(RX_ATTENTION_FLAGS_LAST_MPDU));
+
+       if (is_first_ppdu) {
+               /* New PPDU starts so clear out the old per-PPDU status. */
+               status->freq = 0;
+               status->rate_idx = 0;
+               status->vht_nss = 0;
+               status->vht_flag &= ~RX_VHT_FLAG_80MHZ;
+               status->flag &= ~(RX_FLAG_HT |
+                                 RX_FLAG_VHT |
+                                 RX_FLAG_SHORT_GI |
+                                 RX_FLAG_40MHZ |
+                                 RX_FLAG_MACTIME_END);
+               status->flag |= RX_FLAG_NO_SIGNAL_VAL;
+
+               ath10k_htt_rx_h_signal(ar, status, rxd);
+               ath10k_htt_rx_h_channel(ar, status);
+               ath10k_htt_rx_h_rates(ar, status, rxd);
+       }
+
+       if (is_last_ppdu)
+               ath10k_htt_rx_h_mactime(ar, status, rxd);
+}
+
 static const char * const tid_to_ac[] = {
        "BE",
        "BK",
@@ -1358,7 +1435,6 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
        int num_mpdu_ranges;
        int fw_desc_len;
        u8 *fw_desc;
-       bool channel_set;
        int i, ret, mpdu_count = 0;
 
        lockdep_assert_held(&htt->rx_ring.lock);
@@ -1373,29 +1449,6 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
                             HTT_RX_INDICATION_INFO1_NUM_MPDU_RANGES);
        mpdu_ranges = htt_rx_ind_get_mpdu_ranges(rx);
 
-       /* Fill this once, while this is per-ppdu */
-       if (rx->ppdu.info0 & HTT_RX_INDICATION_INFO0_START_VALID) {
-               memset(rx_status, 0, sizeof(*rx_status));
-               rx_status->signal  = ATH10K_DEFAULT_NOISE_FLOOR +
-                                    rx->ppdu.combined_rssi;
-       }
-
-       if (rx->ppdu.info0 & HTT_RX_INDICATION_INFO0_END_VALID) {
-               /* TSF available only in 32-bit */
-               rx_status->mactime = __le32_to_cpu(rx->ppdu.tsf) & 0xffffffff;
-               rx_status->flag |= RX_FLAG_MACTIME_END;
-       }
-
-       channel_set = ath10k_htt_rx_h_channel(htt->ar, rx_status);
-
-       if (channel_set) {
-               ath10k_htt_rx_h_rates(htt->ar, rx_status->band,
-                                     rx->ppdu.info0,
-                                     __le32_to_cpu(rx->ppdu.info1),
-                                     __le32_to_cpu(rx->ppdu.info2),
-                                     rx_status);
-       }
-
        ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt rx ind: ",
                        rx, sizeof(*rx) +
                        (sizeof(struct htt_rx_indication_mpdu_range) *
@@ -1418,6 +1471,7 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
                        break;
                }
 
+               ath10k_htt_rx_h_ppdu(ar, &amsdu, rx_status);
                ath10k_htt_rx_h_unchain(ar, &amsdu, ret > 0);
                ath10k_htt_rx_h_filter(ar, &amsdu, rx_status);
                ath10k_htt_rx_h_mpdu(ar, &amsdu, rx_status);