iwlwifi: mvm: use firmware station lookup, combine code
authorJohannes Berg <johannes.berg@intel.com>
Thu, 24 Sep 2015 16:29:00 +0000 (18:29 +0200)
committerEmmanuel Grumbach <emmanuel.grumbach@intel.com>
Tue, 1 Dec 2015 19:17:52 +0000 (21:17 +0200)
In most cases, the firmware will already match the station that
we received a given frame from and tell us the station ID in the
RX status, so we can look up the station from that. This lets us
skip the (more expensive) hash table lookup in mac80211.

Also change the fallback case (no station info from the firmware)
to not attempt to look up a multicast source address.

While at it, also combine all the code using the station into a
single if block.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h
drivers/net/wireless/intel/iwlwifi/mvm/rx.c

index 9b7e49d..d790322 100644 (file)
@@ -229,7 +229,8 @@ enum iwl_mvm_rx_status {
        RX_MPDU_RES_STATUS_CSUM_DONE                    = BIT(16),
        RX_MPDU_RES_STATUS_CSUM_OK                      = BIT(17),
        RX_MPDU_RES_STATUS_HASH_INDEX_MSK               = (0x3F0000),
-       RX_MPDU_RES_STATUS_STA_ID_MSK                   = (0x1f000000),
+       RX_MDPU_RES_STATUS_STA_ID_SHIFT                 = 24,
+       RX_MPDU_RES_STATUS_STA_ID_MSK                   = 0x1f << RX_MDPU_RES_STATUS_STA_ID_SHIFT,
        RX_MPDU_RES_STATUS_RRF_KILL                     = BIT(29),
        RX_MPDU_RES_STATUS_FILTERING_MSK                = (0xc00000),
        RX_MPDU_RES_STATUS2_FILTERING_MSK               = (0xc0000000),
index d1d50ff..a0e957a 100644 (file)
@@ -61,6 +61,7 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *****************************************************************************/
+#include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 #include "iwl-trans.h"
 #include "mvm.h"
@@ -262,7 +263,7 @@ void iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct napi_struct *napi,
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
        struct iwl_rx_phy_info *phy_info;
        struct iwl_rx_mpdu_res_start *rx_res;
-       struct ieee80211_sta *sta;
+       struct ieee80211_sta *sta = NULL;
        struct sk_buff *skb;
        u32 len;
        u32 ampdu_status;
@@ -333,22 +334,33 @@ void iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct napi_struct *napi,
                              (unsigned long long)rx_status->mactime);
 
        rcu_read_lock();
-       /*
-        * We have tx blocked stations (with CS bit). If we heard frames from
-        * a blocked station on a new channel we can TX to it again.
-        */
-       if (unlikely(mvm->csa_tx_block_bcn_timeout)) {
-               sta = ieee80211_find_sta(
-                       rcu_dereference(mvm->csa_tx_blocked_vif), hdr->addr2);
-               if (sta)
-                       iwl_mvm_sta_modify_disable_tx_ap(mvm, sta, false);
+       if (rx_pkt_status & RX_MPDU_RES_STATUS_SRC_STA_FOUND) {
+               u32 id = rx_pkt_status & RX_MPDU_RES_STATUS_STA_ID_MSK;
+
+               id >>= RX_MDPU_RES_STATUS_STA_ID_SHIFT;
+
+               if (!WARN_ON_ONCE(id >= IWL_MVM_STATION_COUNT)) {
+                       sta = rcu_dereference(mvm->fw_id_to_mac_id[id]);
+                       if (IS_ERR(sta))
+                               sta = NULL;
+               }
+       } else if (!is_multicast_ether_addr(hdr->addr2)) {
+               /* This is fine since we prevent two stations with the same
+                * address from being added.
+                */
+               sta = ieee80211_find_sta_by_ifaddr(mvm->hw, hdr->addr2, NULL);
        }
 
-       /* This is fine since we don't support multiple AP interfaces */
-       sta = ieee80211_find_sta_by_ifaddr(mvm->hw, hdr->addr2, NULL);
        if (sta) {
                struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
 
+               /* We have tx blocked stations (with CS bit). If we heard
+                * frames from a blocked station on a new channel we can
+                * TX to it again.
+                */
+               if (unlikely(mvm->csa_tx_block_bcn_timeout))
+                       iwl_mvm_sta_modify_disable_tx_ap(mvm, sta, false);
+
                rs_update_last_rssi(mvm, &mvmsta->lq_sta, rx_status);
 
                if (iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_RSSI) &&
@@ -369,11 +381,10 @@ void iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct napi_struct *napi,
                        if (trig_check && rx_status->signal < rssi)
                                iwl_mvm_fw_dbg_collect_trig(mvm, trig, NULL);
                }
-       }
-
-       if (sta && ieee80211_is_data(hdr->frame_control))
-               iwl_mvm_rx_csum(sta, skb, rx_pkt_status);
 
+               if (ieee80211_is_data(hdr->frame_control))
+                       iwl_mvm_rx_csum(sta, skb, rx_pkt_status);
+       }
        rcu_read_unlock();
 
        /* set the preamble flag if appropriate */