iwlwifi: mvm: add duplicate packet detection per rx queue
authorSara Sharon <sara.sharon@intel.com>
Mon, 7 Dec 2015 10:50:58 +0000 (12:50 +0200)
committerEmmanuel Grumbach <emmanuel.grumbach@intel.com>
Sat, 27 Feb 2016 20:00:09 +0000 (22:00 +0200)
Next hardware will direct TCP/UDP streams to different cores.
Packets belonging to the same stream will be directed to the same
core.
The result is that duplicates will be always directed to the same
rx queue were the first packet was received.
This enabled parallelizing the duplicate packet detection across
the different cores, without sharing data between the rx queues.

Signed-off-by: Sara Sharon <sara.sharon@intel.com>
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c
drivers/net/wireless/intel/iwlwifi/mvm/sta.c
drivers/net/wireless/intel/iwlwifi/mvm/sta.h

index a9180b06fb52ec3f9cbf8f1267a4c448a3afaeb3..d89194223af34681d71d3dfe2becfb0ab0bf33ad 100644 (file)
@@ -285,6 +285,66 @@ static void iwl_mvm_rx_csum(struct ieee80211_sta *sta,
                skb->ip_summed = CHECKSUM_UNNECESSARY;
 }
 
+/*
+ * returns true if a packet outside BA session is a duplicate and
+ * should be dropped
+ */
+static bool iwl_mvm_is_nonagg_dup(struct ieee80211_sta *sta, int queue,
+                                 struct ieee80211_rx_status *rx_status,
+                                 struct ieee80211_hdr *hdr,
+                                 struct iwl_rx_mpdu_desc *desc)
+{
+       struct iwl_mvm_sta *mvm_sta;
+       struct iwl_mvm_rxq_dup_data *dup_data;
+       u8 baid, tid, sub_frame_idx;
+
+       if (WARN_ON(IS_ERR_OR_NULL(sta)))
+               return false;
+
+       baid = (le32_to_cpu(desc->reorder_data) &
+               IWL_RX_MPDU_REORDER_BAID_MASK) >>
+               IWL_RX_MPDU_REORDER_BAID_SHIFT;
+
+       if (baid != IWL_RX_REORDER_DATA_INVALID_BAID)
+               return false;
+
+       mvm_sta = iwl_mvm_sta_from_mac80211(sta);
+       dup_data = &mvm_sta->dup_data[queue];
+
+       /*
+        * Drop duplicate 802.11 retransmissions
+        * (IEEE 802.11-2012: 9.3.2.10 "Duplicate detection and recovery")
+        */
+       if (ieee80211_is_ctl(hdr->frame_control) ||
+           ieee80211_is_qos_nullfunc(hdr->frame_control) ||
+           is_multicast_ether_addr(hdr->addr1)) {
+               rx_status->flag |= RX_FLAG_DUP_VALIDATED;
+               return false;
+       }
+
+       if (ieee80211_is_data_qos(hdr->frame_control))
+               /* frame has qos control */
+               tid = *ieee80211_get_qos_ctl(hdr) &
+                       IEEE80211_QOS_CTL_TID_MASK;
+       else
+               tid = IWL_MAX_TID_COUNT;
+
+       /* If this wasn't a part of an A-MSDU the sub-frame index will be 0 */
+       sub_frame_idx = desc->amsdu_info & IWL_RX_MPDU_AMSDU_SUBFRAME_IDX_MASK;
+
+       if (unlikely(ieee80211_has_retry(hdr->frame_control) &&
+                    dup_data->last_seq[tid] == hdr->seq_ctrl &&
+                    dup_data->last_sub_frame[tid] >= sub_frame_idx))
+               return true;
+
+       dup_data->last_seq[tid] = hdr->seq_ctrl;
+       dup_data->last_sub_frame[tid] = sub_frame_idx;
+
+       rx_status->flag |= RX_FLAG_DUP_VALIDATED;
+
+       return false;
+}
+
 void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
                        struct iwl_rx_cmd_buffer *rxb, int queue)
 {
@@ -389,6 +449,12 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
 
                if (ieee80211_is_data(hdr->frame_control))
                        iwl_mvm_rx_csum(sta, skb, desc);
+
+               if (iwl_mvm_is_nonagg_dup(sta, queue, rx_status, hdr, desc)) {
+                       kfree_skb(skb);
+                       rcu_read_unlock();
+                       return;
+               }
        }
 
        /*
index b2123ce3e3a8f388a54c0ec6d00751c88f046d05..4717b185f5b036090e7a204fb01927f4c77517a6 100644 (file)
@@ -280,6 +280,7 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm,
 {
        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
        struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);
+       struct iwl_mvm_rxq_dup_data *dup_data;
        int i, ret, sta_id;
 
        lockdep_assert_held(&mvm->mutex);
@@ -327,6 +328,16 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm,
        }
        mvm_sta->agg_tids = 0;
 
+       if (iwl_mvm_has_new_rx_api(mvm) &&
+           !test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) {
+               dup_data = kcalloc(mvm->trans->num_rx_queues,
+                                  sizeof(*dup_data),
+                                  GFP_KERNEL);
+               if (!dup_data)
+                       return -ENOMEM;
+               mvm_sta->dup_data = dup_data;
+       }
+
        ret = iwl_mvm_sta_send_to_fw(mvm, sta, false);
        if (ret)
                goto err;
@@ -508,6 +519,9 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm,
 
        lockdep_assert_held(&mvm->mutex);
 
+       if (iwl_mvm_has_new_rx_api(mvm))
+               kfree(mvm_sta->dup_data);
+
        if (vif->type == NL80211_IFTYPE_STATION &&
            mvmvif->ap_sta_id == mvm_sta->sta_id) {
                ret = iwl_mvm_drain_sta(mvm, mvm_sta, true);
index f95f603ad56cb6c4bf7016174ba27e011a403b75..db701cad87c186d57558c2cff509aa28c8b6196d 100644 (file)
@@ -295,6 +295,16 @@ struct iwl_mvm_key_pn {
        } ____cacheline_aligned_in_smp q[];
 };
 
+/**
+ * struct iwl_mvm_rxq_dup_data - per station per rx queue data
+ * @last_seq: last sequence per tid for duplicate packet detection
+ * @last_sub_frame: last subframe packet
+ */
+struct iwl_mvm_rxq_dup_data {
+       __le16 last_seq[IWL_MAX_TID_COUNT + 1];
+       u8 last_sub_frame[IWL_MAX_TID_COUNT + 1];
+} ____cacheline_aligned_in_smp;
+
 /**
  * struct iwl_mvm_sta - representation of a station in the driver
  * @sta_id: the index of the station in the fw (will be replaced by id_n_color)
@@ -321,6 +331,7 @@ struct iwl_mvm_key_pn {
  *     we are sending frames from an AMPDU queue and there was a hole in
  *     the BA window. To be used for UAPSD only.
  * @ptk_pn: per-queue PTK PN data structures
+ * @dup_data: per queue duplicate packet detection data
  *
  * When mac80211 creates a station it reserves some space (hw->sta_data_size)
  * in the structure for use by driver. This structure is placed in that
@@ -340,8 +351,8 @@ struct iwl_mvm_sta {
        struct iwl_mvm_tid_data tid_data[IWL_MAX_TID_COUNT];
        struct iwl_lq_sta lq_sta;
        struct ieee80211_vif *vif;
-
        struct iwl_mvm_key_pn __rcu *ptk_pn[4];
+       struct iwl_mvm_rxq_dup_data *dup_data;
 
        /* Temporary, until the new TLC will control the Tx protection */
        s8 tx_protection;