The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/contrib/dev/iwlwifi/mvm/rx.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
    2 /*
    3  * Copyright (C) 2012-2014, 2018-2021 Intel Corporation
    4  * Copyright (C) 2013-2015 Intel Mobile Communications GmbH
    5  * Copyright (C) 2016-2017 Intel Deutschland GmbH
    6  */
    7 #include <asm/unaligned.h>
    8 #include <linux/etherdevice.h>
    9 #include <linux/skbuff.h>
   10 #include "iwl-trans.h"
   11 #include "mvm.h"
   12 #include "fw-api.h"
   13 
   14 /*
   15  * iwl_mvm_rx_rx_phy_cmd - REPLY_RX_PHY_CMD handler
   16  *
   17  * Copies the phy information in mvm->last_phy_info, it will be used when the
   18  * actual data will come from the fw in the next packet.
   19  */
   20 void iwl_mvm_rx_rx_phy_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb)
   21 {
   22         struct iwl_rx_packet *pkt = rxb_addr(rxb);
   23         unsigned int pkt_len = iwl_rx_packet_payload_len(pkt);
   24 
   25         if (unlikely(pkt_len < sizeof(mvm->last_phy_info)))
   26                 return;
   27 
   28         memcpy(&mvm->last_phy_info, pkt->data, sizeof(mvm->last_phy_info));
   29         mvm->ampdu_ref++;
   30 
   31 #ifdef CONFIG_IWLWIFI_DEBUGFS
   32         if (mvm->last_phy_info.phy_flags & cpu_to_le16(RX_RES_PHY_FLAGS_AGG)) {
   33                 spin_lock(&mvm->drv_stats_lock);
   34                 mvm->drv_rx_stats.ampdu_count++;
   35                 spin_unlock(&mvm->drv_stats_lock);
   36         }
   37 #endif
   38 }
   39 
   40 /*
   41  * iwl_mvm_pass_packet_to_mac80211 - builds the packet for mac80211
   42  *
   43  * Adds the rxb to a new skb and give it to mac80211
   44  */
   45 static void iwl_mvm_pass_packet_to_mac80211(struct iwl_mvm *mvm,
   46                                             struct ieee80211_sta *sta,
   47                                             struct napi_struct *napi,
   48                                             struct sk_buff *skb,
   49                                             struct ieee80211_hdr *hdr, u16 len,
   50                                             u8 crypt_len,
   51                                             struct iwl_rx_cmd_buffer *rxb)
   52 {
   53         unsigned int hdrlen = ieee80211_hdrlen(hdr->frame_control);
   54         unsigned int fraglen;
   55 
   56         /*
   57          * The 'hdrlen' (plus the 8 bytes for the SNAP and the crypt_len,
   58          * but those are all multiples of 4 long) all goes away, but we
   59          * want the *end* of it, which is going to be the start of the IP
   60          * header, to be aligned when it gets pulled in.
   61          * The beginning of the skb->data is aligned on at least a 4-byte
   62          * boundary after allocation. Everything here is aligned at least
   63          * on a 2-byte boundary so we can just take hdrlen & 3 and pad by
   64          * the result.
   65          */
   66         skb_reserve(skb, hdrlen & 3);
   67 
   68         /* If frame is small enough to fit in skb->head, pull it completely.
   69          * If not, only pull ieee80211_hdr (including crypto if present, and
   70          * an additional 8 bytes for SNAP/ethertype, see below) so that
   71          * splice() or TCP coalesce are more efficient.
   72          *
   73          * Since, in addition, ieee80211_data_to_8023() always pull in at
   74          * least 8 bytes (possibly more for mesh) we can do the same here
   75          * to save the cost of doing it later. That still doesn't pull in
   76          * the actual IP header since the typical case has a SNAP header.
   77          * If the latter changes (there are efforts in the standards group
   78          * to do so) we should revisit this and ieee80211_data_to_8023().
   79          */
   80         hdrlen = (len <= skb_tailroom(skb)) ? len : hdrlen + crypt_len + 8;
   81 
   82         skb_put_data(skb, hdr, hdrlen);
   83         fraglen = len - hdrlen;
   84 
   85         if (fraglen) {
   86                 int offset = (u8 *)hdr + hdrlen -
   87                              (u8 *)rxb_addr(rxb) + rxb_offset(rxb);
   88 
   89                 skb_add_rx_frag(skb, 0, rxb_steal_page(rxb), offset,
   90                                 fraglen, rxb->truesize);
   91         }
   92 
   93         ieee80211_rx_napi(mvm->hw, sta, skb, napi);
   94 }
   95 
   96 /*
   97  * iwl_mvm_get_signal_strength - use new rx PHY INFO API
   98  * values are reported by the fw as positive values - need to negate
   99  * to obtain their dBM.  Account for missing antennas by replacing 0
  100  * values by -256dBm: practically 0 power and a non-feasible 8 bit value.
  101  */
  102 static void iwl_mvm_get_signal_strength(struct iwl_mvm *mvm,
  103                                         struct iwl_rx_phy_info *phy_info,
  104                                         struct ieee80211_rx_status *rx_status)
  105 {
  106         int energy_a, energy_b, max_energy;
  107         u32 val;
  108 
  109         val =
  110             le32_to_cpu(phy_info->non_cfg_phy[IWL_RX_INFO_ENERGY_ANT_ABC_IDX]);
  111         energy_a = (val & IWL_RX_INFO_ENERGY_ANT_A_MSK) >>
  112                                                 IWL_RX_INFO_ENERGY_ANT_A_POS;
  113         energy_a = energy_a ? -energy_a : S8_MIN;
  114         energy_b = (val & IWL_RX_INFO_ENERGY_ANT_B_MSK) >>
  115                                                 IWL_RX_INFO_ENERGY_ANT_B_POS;
  116         energy_b = energy_b ? -energy_b : S8_MIN;
  117         max_energy = max(energy_a, energy_b);
  118 
  119         IWL_DEBUG_STATS(mvm, "energy In A %d B %d  , and max %d\n",
  120                         energy_a, energy_b, max_energy);
  121 
  122         rx_status->signal = max_energy;
  123         rx_status->chains = (le16_to_cpu(phy_info->phy_flags) &
  124                                 RX_RES_PHY_FLAGS_ANTENNA)
  125                                         >> RX_RES_PHY_FLAGS_ANTENNA_POS;
  126         rx_status->chain_signal[0] = energy_a;
  127         rx_status->chain_signal[1] = energy_b;
  128 }
  129 
  130 /*
  131  * iwl_mvm_set_mac80211_rx_flag - translate fw status to mac80211 format
  132  * @mvm: the mvm object
  133  * @hdr: 80211 header
  134  * @stats: status in mac80211's format
  135  * @rx_pkt_status: status coming from fw
  136  *
  137  * returns non 0 value if the packet should be dropped
  138  */
  139 static u32 iwl_mvm_set_mac80211_rx_flag(struct iwl_mvm *mvm,
  140                                         struct ieee80211_hdr *hdr,
  141                                         struct ieee80211_rx_status *stats,
  142                                         u32 rx_pkt_status,
  143                                         u8 *crypt_len)
  144 {
  145         if (!ieee80211_has_protected(hdr->frame_control) ||
  146             (rx_pkt_status & RX_MPDU_RES_STATUS_SEC_ENC_MSK) ==
  147                              RX_MPDU_RES_STATUS_SEC_NO_ENC)
  148                 return 0;
  149 
  150         /* packet was encrypted with unknown alg */
  151         if ((rx_pkt_status & RX_MPDU_RES_STATUS_SEC_ENC_MSK) ==
  152                                         RX_MPDU_RES_STATUS_SEC_ENC_ERR)
  153                 return 0;
  154 
  155         switch (rx_pkt_status & RX_MPDU_RES_STATUS_SEC_ENC_MSK) {
  156         case RX_MPDU_RES_STATUS_SEC_CCM_ENC:
  157                 /* alg is CCM: check MIC only */
  158                 if (!(rx_pkt_status & RX_MPDU_RES_STATUS_MIC_OK))
  159                         return -1;
  160 
  161                 stats->flag |= RX_FLAG_DECRYPTED;
  162                 *crypt_len = IEEE80211_CCMP_HDR_LEN;
  163                 return 0;
  164 
  165         case RX_MPDU_RES_STATUS_SEC_TKIP_ENC:
  166                 /* Don't drop the frame and decrypt it in SW */
  167                 if (!fw_has_api(&mvm->fw->ucode_capa,
  168                                 IWL_UCODE_TLV_API_DEPRECATE_TTAK) &&
  169                     !(rx_pkt_status & RX_MPDU_RES_STATUS_TTAK_OK))
  170                         return 0;
  171                 *crypt_len = IEEE80211_TKIP_IV_LEN;
  172                 fallthrough;
  173 
  174         case RX_MPDU_RES_STATUS_SEC_WEP_ENC:
  175                 if (!(rx_pkt_status & RX_MPDU_RES_STATUS_ICV_OK))
  176                         return -1;
  177 
  178                 stats->flag |= RX_FLAG_DECRYPTED;
  179                 if ((rx_pkt_status & RX_MPDU_RES_STATUS_SEC_ENC_MSK) ==
  180                                 RX_MPDU_RES_STATUS_SEC_WEP_ENC)
  181                         *crypt_len = IEEE80211_WEP_IV_LEN;
  182                 return 0;
  183 
  184         case RX_MPDU_RES_STATUS_SEC_EXT_ENC:
  185                 if (!(rx_pkt_status & RX_MPDU_RES_STATUS_MIC_OK))
  186                         return -1;
  187                 stats->flag |= RX_FLAG_DECRYPTED;
  188                 return 0;
  189 
  190         default:
  191                 /* Expected in monitor (not having the keys) */
  192 #if defined(__linux__)
  193                 if (!mvm->monitor_on)
  194                         IWL_ERR(mvm, "Unhandled alg: 0x%x\n", rx_pkt_status);
  195 #elif defined(__FreeBSD__)
  196                 if (!mvm->monitor_on && net_ratelimit())
  197                         IWL_ERR(mvm, "%s: Unhandled alg: 0x%x\n",
  198                             __func__, rx_pkt_status);
  199 #endif
  200         }
  201 
  202         return 0;
  203 }
  204 
  205 static void iwl_mvm_rx_handle_tcm(struct iwl_mvm *mvm,
  206                                   struct ieee80211_sta *sta,
  207                                   struct ieee80211_hdr *hdr, u32 len,
  208                                   struct iwl_rx_phy_info *phy_info,
  209                                   u32 rate_n_flags)
  210 {
  211         struct iwl_mvm_sta *mvmsta;
  212         struct iwl_mvm_tcm_mac *mdata;
  213         int mac;
  214         int ac = IEEE80211_AC_BE; /* treat non-QoS as BE */
  215         struct iwl_mvm_vif *mvmvif;
  216         /* expected throughput in 100Kbps, single stream, 20 MHz */
  217         static const u8 thresh_tpt[] = {
  218                 9, 18, 30, 42, 60, 78, 90, 96, 120, 135,
  219         };
  220         u16 thr;
  221 
  222         if (ieee80211_is_data_qos(hdr->frame_control))
  223                 ac = tid_to_mac80211_ac[ieee80211_get_tid(hdr)];
  224 
  225         mvmsta = iwl_mvm_sta_from_mac80211(sta);
  226         mac = mvmsta->mac_id_n_color & FW_CTXT_ID_MSK;
  227 
  228         if (time_after(jiffies, mvm->tcm.ts + MVM_TCM_PERIOD))
  229                 schedule_delayed_work(&mvm->tcm.work, 0);
  230         mdata = &mvm->tcm.data[mac];
  231         mdata->rx.pkts[ac]++;
  232 
  233         /* count the airtime only once for each ampdu */
  234         if (mdata->rx.last_ampdu_ref != mvm->ampdu_ref) {
  235                 mdata->rx.last_ampdu_ref = mvm->ampdu_ref;
  236                 mdata->rx.airtime += le16_to_cpu(phy_info->frame_time);
  237         }
  238 
  239         if (!(rate_n_flags & (RATE_MCS_HT_MSK_V1 | RATE_MCS_VHT_MSK_V1)))
  240                 return;
  241 
  242         mvmvif = iwl_mvm_vif_from_mac80211(mvmsta->vif);
  243 
  244         if (mdata->opened_rx_ba_sessions ||
  245             mdata->uapsd_nonagg_detect.detected ||
  246             (!mvmvif->queue_params[IEEE80211_AC_VO].uapsd &&
  247              !mvmvif->queue_params[IEEE80211_AC_VI].uapsd &&
  248              !mvmvif->queue_params[IEEE80211_AC_BE].uapsd &&
  249              !mvmvif->queue_params[IEEE80211_AC_BK].uapsd) ||
  250             mvmsta->sta_id != mvmvif->ap_sta_id)
  251                 return;
  252 
  253         if (rate_n_flags & RATE_MCS_HT_MSK_V1) {
  254                 thr = thresh_tpt[rate_n_flags & RATE_HT_MCS_RATE_CODE_MSK_V1];
  255                 thr *= 1 + ((rate_n_flags & RATE_HT_MCS_NSS_MSK_V1) >>
  256                                         RATE_HT_MCS_NSS_POS_V1);
  257         } else {
  258                 if (WARN_ON((rate_n_flags & RATE_VHT_MCS_RATE_CODE_MSK) >=
  259                                 ARRAY_SIZE(thresh_tpt)))
  260                         return;
  261                 thr = thresh_tpt[rate_n_flags & RATE_VHT_MCS_RATE_CODE_MSK];
  262                 thr *= 1 + ((rate_n_flags & RATE_VHT_MCS_NSS_MSK) >>
  263                                         RATE_VHT_MCS_NSS_POS);
  264         }
  265 
  266         thr <<= ((rate_n_flags & RATE_MCS_CHAN_WIDTH_MSK_V1) >>
  267                                 RATE_MCS_CHAN_WIDTH_POS);
  268 
  269         mdata->uapsd_nonagg_detect.rx_bytes += len;
  270         ewma_rate_add(&mdata->uapsd_nonagg_detect.rate, thr);
  271 }
  272 
  273 static void iwl_mvm_rx_csum(struct ieee80211_sta *sta,
  274                             struct sk_buff *skb,
  275                             u32 status)
  276 {
  277         struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
  278         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(mvmsta->vif);
  279 
  280         if (mvmvif->features & NETIF_F_RXCSUM &&
  281             status & RX_MPDU_RES_STATUS_CSUM_DONE &&
  282             status & RX_MPDU_RES_STATUS_CSUM_OK)
  283                 skb->ip_summed = CHECKSUM_UNNECESSARY;
  284 }
  285 
  286 /*
  287  * iwl_mvm_rx_rx_mpdu - REPLY_RX_MPDU_CMD handler
  288  *
  289  * Handles the actual data of the Rx packet from the fw
  290  */
  291 void iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct napi_struct *napi,
  292                         struct iwl_rx_cmd_buffer *rxb)
  293 {
  294         struct ieee80211_hdr *hdr;
  295         struct ieee80211_rx_status *rx_status;
  296         struct iwl_rx_packet *pkt = rxb_addr(rxb);
  297         struct iwl_rx_phy_info *phy_info;
  298         struct iwl_rx_mpdu_res_start *rx_res;
  299         struct ieee80211_sta *sta = NULL;
  300         struct sk_buff *skb;
  301         u32 len, pkt_len = iwl_rx_packet_payload_len(pkt);
  302         u32 rate_n_flags;
  303         u32 rx_pkt_status;
  304         u8 crypt_len = 0;
  305 
  306         if (unlikely(pkt_len < sizeof(*rx_res))) {
  307                 IWL_DEBUG_DROP(mvm, "Bad REPLY_RX_MPDU_CMD size\n");
  308                 return;
  309         }
  310 
  311         phy_info = &mvm->last_phy_info;
  312         rx_res = (struct iwl_rx_mpdu_res_start *)pkt->data;
  313         hdr = (struct ieee80211_hdr *)(pkt->data + sizeof(*rx_res));
  314         len = le16_to_cpu(rx_res->byte_count);
  315 
  316         if (unlikely(len + sizeof(*rx_res) + sizeof(__le32) > pkt_len)) {
  317                 IWL_DEBUG_DROP(mvm, "FW lied about packet len\n");
  318                 return;
  319         }
  320 
  321         rx_pkt_status = get_unaligned_le32((__le32 *)
  322                 (pkt->data + sizeof(*rx_res) + len));
  323 
  324         /* Dont use dev_alloc_skb(), we'll have enough headroom once
  325          * ieee80211_hdr pulled.
  326          */
  327         skb = alloc_skb(128, GFP_ATOMIC);
  328         if (!skb) {
  329                 IWL_ERR(mvm, "alloc_skb failed\n");
  330                 return;
  331         }
  332 
  333         rx_status = IEEE80211_SKB_RXCB(skb);
  334 
  335         /*
  336          * drop the packet if it has failed being decrypted by HW
  337          */
  338         if (iwl_mvm_set_mac80211_rx_flag(mvm, hdr, rx_status, rx_pkt_status,
  339                                          &crypt_len)) {
  340                 IWL_DEBUG_DROP(mvm, "Bad decryption results 0x%08x\n",
  341                                rx_pkt_status);
  342                 kfree_skb(skb);
  343                 return;
  344         }
  345 
  346         /*
  347          * Keep packets with CRC errors (and with overrun) for monitor mode
  348          * (otherwise the firmware discards them) but mark them as bad.
  349          */
  350         if (!(rx_pkt_status & RX_MPDU_RES_STATUS_CRC_OK) ||
  351             !(rx_pkt_status & RX_MPDU_RES_STATUS_OVERRUN_OK)) {
  352                 IWL_DEBUG_RX(mvm, "Bad CRC or FIFO: 0x%08X.\n", rx_pkt_status);
  353                 rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
  354         }
  355 
  356         /* This will be used in several places later */
  357         rate_n_flags = le32_to_cpu(phy_info->rate_n_flags);
  358 
  359         /* rx_status carries information about the packet to mac80211 */
  360         rx_status->mactime = le64_to_cpu(phy_info->timestamp);
  361         rx_status->device_timestamp = le32_to_cpu(phy_info->system_timestamp);
  362         rx_status->band =
  363                 (phy_info->phy_flags & cpu_to_le16(RX_RES_PHY_FLAGS_BAND_24)) ?
  364                                 NL80211_BAND_2GHZ : NL80211_BAND_5GHZ;
  365         rx_status->freq =
  366                 ieee80211_channel_to_frequency(le16_to_cpu(phy_info->channel),
  367                                                rx_status->band);
  368 
  369         /* TSF as indicated by the firmware  is at INA time */
  370         rx_status->flag |= RX_FLAG_MACTIME_PLCP_START;
  371 
  372         iwl_mvm_get_signal_strength(mvm, phy_info, rx_status);
  373 
  374         IWL_DEBUG_STATS_LIMIT(mvm, "Rssi %d, TSF %llu\n", rx_status->signal,
  375                               (unsigned long long)rx_status->mactime);
  376 
  377         rcu_read_lock();
  378         if (rx_pkt_status & RX_MPDU_RES_STATUS_SRC_STA_FOUND) {
  379                 u32 id = rx_pkt_status & RX_MPDU_RES_STATUS_STA_ID_MSK;
  380 
  381                 id >>= RX_MDPU_RES_STATUS_STA_ID_SHIFT;
  382 
  383                 if (!WARN_ON_ONCE(id >= mvm->fw->ucode_capa.num_stations)) {
  384                         sta = rcu_dereference(mvm->fw_id_to_mac_id[id]);
  385                         if (IS_ERR(sta))
  386                                 sta = NULL;
  387                 }
  388         } else if (!is_multicast_ether_addr(hdr->addr2)) {
  389                 /* This is fine since we prevent two stations with the same
  390                  * address from being added.
  391                  */
  392                 sta = ieee80211_find_sta_by_ifaddr(mvm->hw, hdr->addr2, NULL);
  393         }
  394 
  395         if (sta) {
  396                 struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
  397                 struct ieee80211_vif *tx_blocked_vif =
  398                         rcu_dereference(mvm->csa_tx_blocked_vif);
  399                 struct iwl_fw_dbg_trigger_tlv *trig;
  400                 struct ieee80211_vif *vif = mvmsta->vif;
  401 
  402                 /* We have tx blocked stations (with CS bit). If we heard
  403                  * frames from a blocked station on a new channel we can
  404                  * TX to it again.
  405                  */
  406                 if (unlikely(tx_blocked_vif) && vif == tx_blocked_vif) {
  407                         struct iwl_mvm_vif *mvmvif =
  408                                 iwl_mvm_vif_from_mac80211(tx_blocked_vif);
  409 
  410                         if (mvmvif->csa_target_freq == rx_status->freq)
  411                                 iwl_mvm_sta_modify_disable_tx_ap(mvm, sta,
  412                                                                  false);
  413                 }
  414 
  415                 rs_update_last_rssi(mvm, mvmsta, rx_status);
  416 
  417                 trig = iwl_fw_dbg_trigger_on(&mvm->fwrt,
  418                                              ieee80211_vif_to_wdev(vif),
  419                                              FW_DBG_TRIGGER_RSSI);
  420 
  421                 if (trig && ieee80211_is_beacon(hdr->frame_control)) {
  422                         struct iwl_fw_dbg_trigger_low_rssi *rssi_trig;
  423                         s32 rssi;
  424 
  425                         rssi_trig = (void *)trig->data;
  426                         rssi = le32_to_cpu(rssi_trig->rssi);
  427 
  428                         if (rx_status->signal < rssi)
  429                                 iwl_fw_dbg_collect_trig(&mvm->fwrt, trig,
  430                                                         NULL);
  431                 }
  432 
  433                 if (!mvm->tcm.paused && len >= sizeof(*hdr) &&
  434                     !is_multicast_ether_addr(hdr->addr1) &&
  435                     ieee80211_is_data(hdr->frame_control))
  436                         iwl_mvm_rx_handle_tcm(mvm, sta, hdr, len, phy_info,
  437                                               rate_n_flags);
  438 
  439                 if (ieee80211_is_data(hdr->frame_control))
  440                         iwl_mvm_rx_csum(sta, skb, rx_pkt_status);
  441         }
  442         rcu_read_unlock();
  443 
  444         /* set the preamble flag if appropriate */
  445         if (phy_info->phy_flags & cpu_to_le16(RX_RES_PHY_FLAGS_SHORT_PREAMBLE))
  446                 rx_status->enc_flags |= RX_ENC_FLAG_SHORTPRE;
  447 
  448         if (phy_info->phy_flags & cpu_to_le16(RX_RES_PHY_FLAGS_AGG)) {
  449                 /*
  450                  * We know which subframes of an A-MPDU belong
  451                  * together since we get a single PHY response
  452                  * from the firmware for all of them
  453                  */
  454                 rx_status->flag |= RX_FLAG_AMPDU_DETAILS;
  455                 rx_status->ampdu_reference = mvm->ampdu_ref;
  456         }
  457 
  458         /* Set up the HT phy flags */
  459         switch (rate_n_flags & RATE_MCS_CHAN_WIDTH_MSK_V1) {
  460         case RATE_MCS_CHAN_WIDTH_20:
  461                 break;
  462         case RATE_MCS_CHAN_WIDTH_40:
  463                 rx_status->bw = RATE_INFO_BW_40;
  464                 break;
  465         case RATE_MCS_CHAN_WIDTH_80:
  466                 rx_status->bw = RATE_INFO_BW_80;
  467                 break;
  468         case RATE_MCS_CHAN_WIDTH_160:
  469                 rx_status->bw = RATE_INFO_BW_160;
  470                 break;
  471         }
  472         if (!(rate_n_flags & RATE_MCS_CCK_MSK_V1) &&
  473             rate_n_flags & RATE_MCS_SGI_MSK_V1)
  474                 rx_status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
  475         if (rate_n_flags & RATE_HT_MCS_GF_MSK)
  476                 rx_status->enc_flags |= RX_ENC_FLAG_HT_GF;
  477         if (rate_n_flags & RATE_MCS_LDPC_MSK_V1)
  478                 rx_status->enc_flags |= RX_ENC_FLAG_LDPC;
  479         if (rate_n_flags & RATE_MCS_HT_MSK_V1) {
  480                 u8 stbc = (rate_n_flags & RATE_MCS_STBC_MSK) >>
  481                                 RATE_MCS_STBC_POS;
  482                 rx_status->encoding = RX_ENC_HT;
  483                 rx_status->rate_idx = rate_n_flags & RATE_HT_MCS_INDEX_MSK_V1;
  484                 rx_status->enc_flags |= stbc << RX_ENC_FLAG_STBC_SHIFT;
  485         } else if (rate_n_flags & RATE_MCS_VHT_MSK_V1) {
  486                 u8 stbc = (rate_n_flags & RATE_MCS_STBC_MSK) >>
  487                                 RATE_MCS_STBC_POS;
  488                 rx_status->nss =
  489                         ((rate_n_flags & RATE_VHT_MCS_NSS_MSK) >>
  490                                                 RATE_VHT_MCS_NSS_POS) + 1;
  491                 rx_status->rate_idx = rate_n_flags & RATE_VHT_MCS_RATE_CODE_MSK;
  492                 rx_status->encoding = RX_ENC_VHT;
  493                 rx_status->enc_flags |= stbc << RX_ENC_FLAG_STBC_SHIFT;
  494                 if (rate_n_flags & RATE_MCS_BF_MSK)
  495                         rx_status->enc_flags |= RX_ENC_FLAG_BF;
  496         } else {
  497                 int rate = iwl_mvm_legacy_rate_to_mac80211_idx(rate_n_flags,
  498                                                                rx_status->band);
  499 
  500                 if (WARN(rate < 0 || rate > 0xFF,
  501                          "Invalid rate flags 0x%x, band %d,\n",
  502                          rate_n_flags, rx_status->band)) {
  503                         kfree_skb(skb);
  504                         return;
  505                 }
  506                 rx_status->rate_idx = rate;
  507         }
  508 
  509 #ifdef CONFIG_IWLWIFI_DEBUGFS
  510         iwl_mvm_update_frame_stats(mvm, rate_n_flags,
  511                                    rx_status->flag & RX_FLAG_AMPDU_DETAILS);
  512 #endif
  513 
  514         if (unlikely((ieee80211_is_beacon(hdr->frame_control) ||
  515                       ieee80211_is_probe_resp(hdr->frame_control)) &&
  516                      mvm->sched_scan_pass_all == SCHED_SCAN_PASS_ALL_ENABLED))
  517                 mvm->sched_scan_pass_all = SCHED_SCAN_PASS_ALL_FOUND;
  518 
  519         if (unlikely(ieee80211_is_beacon(hdr->frame_control) ||
  520                      ieee80211_is_probe_resp(hdr->frame_control)))
  521                 rx_status->boottime_ns = ktime_get_boottime_ns();
  522 
  523         iwl_mvm_pass_packet_to_mac80211(mvm, sta, napi, skb, hdr, len,
  524                                         crypt_len, rxb);
  525 }
  526 
  527 struct iwl_mvm_stat_data {
  528         struct iwl_mvm *mvm;
  529         __le32 flags;
  530         __le32 mac_id;
  531         u8 beacon_filter_average_energy;
  532         __le32 *beacon_counter;
  533         u8 *beacon_average_energy;
  534 };
  535 
  536 struct iwl_mvm_stat_data_all_macs {
  537         struct iwl_mvm *mvm;
  538         __le32 flags;
  539         struct iwl_statistics_ntfy_per_mac *per_mac_stats;
  540 };
  541 
  542 static void iwl_mvm_update_vif_sig(struct ieee80211_vif *vif, int sig)
  543 {
  544         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
  545         struct iwl_mvm *mvm = mvmvif->mvm;
  546         int thold = vif->bss_conf.cqm_rssi_thold;
  547         int hyst = vif->bss_conf.cqm_rssi_hyst;
  548         int last_event;
  549 
  550         if (sig == 0) {
  551                 IWL_DEBUG_RX(mvm, "RSSI is 0 - skip signal based decision\n");
  552                 return;
  553         }
  554 
  555         mvmvif->bf_data.ave_beacon_signal = sig;
  556 
  557         /* BT Coex */
  558         if (mvmvif->bf_data.bt_coex_min_thold !=
  559             mvmvif->bf_data.bt_coex_max_thold) {
  560                 last_event = mvmvif->bf_data.last_bt_coex_event;
  561                 if (sig > mvmvif->bf_data.bt_coex_max_thold &&
  562                     (last_event <= mvmvif->bf_data.bt_coex_min_thold ||
  563                      last_event == 0)) {
  564                         mvmvif->bf_data.last_bt_coex_event = sig;
  565                         IWL_DEBUG_RX(mvm, "cqm_iterator bt coex high %d\n",
  566                                      sig);
  567                         iwl_mvm_bt_rssi_event(mvm, vif, RSSI_EVENT_HIGH);
  568                 } else if (sig < mvmvif->bf_data.bt_coex_min_thold &&
  569                            (last_event >= mvmvif->bf_data.bt_coex_max_thold ||
  570                             last_event == 0)) {
  571                         mvmvif->bf_data.last_bt_coex_event = sig;
  572                         IWL_DEBUG_RX(mvm, "cqm_iterator bt coex low %d\n",
  573                                      sig);
  574                         iwl_mvm_bt_rssi_event(mvm, vif, RSSI_EVENT_LOW);
  575                 }
  576         }
  577 
  578         if (!(vif->driver_flags & IEEE80211_VIF_SUPPORTS_CQM_RSSI))
  579                 return;
  580 
  581         /* CQM Notification */
  582         last_event = mvmvif->bf_data.last_cqm_event;
  583         if (thold && sig < thold && (last_event == 0 ||
  584                                      sig < last_event - hyst)) {
  585                 mvmvif->bf_data.last_cqm_event = sig;
  586                 IWL_DEBUG_RX(mvm, "cqm_iterator cqm low %d\n",
  587                              sig);
  588                 ieee80211_cqm_rssi_notify(
  589                         vif,
  590                         NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW,
  591                         sig,
  592                         GFP_KERNEL);
  593         } else if (sig > thold &&
  594                    (last_event == 0 || sig > last_event + hyst)) {
  595                 mvmvif->bf_data.last_cqm_event = sig;
  596                 IWL_DEBUG_RX(mvm, "cqm_iterator cqm high %d\n",
  597                              sig);
  598                 ieee80211_cqm_rssi_notify(
  599                         vif,
  600                         NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH,
  601                         sig,
  602                         GFP_KERNEL);
  603         }
  604 }
  605 
  606 static void iwl_mvm_stat_iterator(void *_data, u8 *mac,
  607                                   struct ieee80211_vif *vif)
  608 {
  609         struct iwl_mvm_stat_data *data = _data;
  610         int sig = -data->beacon_filter_average_energy;
  611         u16 id = le32_to_cpu(data->mac_id);
  612         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
  613         u16 vif_id = mvmvif->id;
  614 
  615         /* This doesn't need the MAC ID check since it's not taking the
  616          * data copied into the "data" struct, but rather the data from
  617          * the notification directly.
  618          */
  619         mvmvif->beacon_stats.num_beacons =
  620                 le32_to_cpu(data->beacon_counter[vif_id]);
  621         mvmvif->beacon_stats.avg_signal =
  622                 -data->beacon_average_energy[vif_id];
  623 
  624         if (mvmvif->id != id)
  625                 return;
  626 
  627         if (vif->type != NL80211_IFTYPE_STATION)
  628                 return;
  629 
  630         /* make sure that beacon statistics don't go backwards with TCM
  631          * request to clear statistics
  632          */
  633         if (le32_to_cpu(data->flags) & IWL_STATISTICS_REPLY_FLG_CLEAR)
  634                 mvmvif->beacon_stats.accu_num_beacons +=
  635                         mvmvif->beacon_stats.num_beacons;
  636 
  637         iwl_mvm_update_vif_sig(vif, sig);
  638 }
  639 
  640 static void iwl_mvm_stat_iterator_all_macs(void *_data, u8 *mac,
  641                                            struct ieee80211_vif *vif)
  642 {
  643         struct iwl_mvm_stat_data_all_macs *data = _data;
  644         struct iwl_statistics_ntfy_per_mac *mac_stats;
  645         int sig;
  646         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
  647         u16 vif_id = mvmvif->id;
  648 
  649         if (WARN_ONCE(vif_id >= MAC_INDEX_AUX, "invalid vif id: %d", vif_id))
  650                 return;
  651 
  652         if (vif->type != NL80211_IFTYPE_STATION)
  653                 return;
  654 
  655         mac_stats = &data->per_mac_stats[vif_id];
  656 
  657         mvmvif->beacon_stats.num_beacons =
  658                 le32_to_cpu(mac_stats->beacon_counter);
  659         mvmvif->beacon_stats.avg_signal =
  660                 -le32_to_cpu(mac_stats->beacon_average_energy);
  661 
  662         /* make sure that beacon statistics don't go backwards with TCM
  663          * request to clear statistics
  664          */
  665         if (le32_to_cpu(data->flags) & IWL_STATISTICS_REPLY_FLG_CLEAR)
  666                 mvmvif->beacon_stats.accu_num_beacons +=
  667                         mvmvif->beacon_stats.num_beacons;
  668 
  669         sig = -le32_to_cpu(mac_stats->beacon_filter_average_energy);
  670         iwl_mvm_update_vif_sig(vif, sig);
  671 }
  672 
  673 static inline void
  674 iwl_mvm_rx_stats_check_trigger(struct iwl_mvm *mvm, struct iwl_rx_packet *pkt)
  675 {
  676         struct iwl_fw_dbg_trigger_tlv *trig;
  677         struct iwl_fw_dbg_trigger_stats *trig_stats;
  678         u32 trig_offset, trig_thold;
  679 
  680         trig = iwl_fw_dbg_trigger_on(&mvm->fwrt, NULL, FW_DBG_TRIGGER_STATS);
  681         if (!trig)
  682                 return;
  683 
  684         trig_stats = (void *)trig->data;
  685 
  686         trig_offset = le32_to_cpu(trig_stats->stop_offset);
  687         trig_thold = le32_to_cpu(trig_stats->stop_threshold);
  688 
  689         if (WARN_ON_ONCE(trig_offset >= iwl_rx_packet_payload_len(pkt)))
  690                 return;
  691 
  692         if (le32_to_cpup((__le32 *) (pkt->data + trig_offset)) < trig_thold)
  693                 return;
  694 
  695         iwl_fw_dbg_collect_trig(&mvm->fwrt, trig, NULL);
  696 }
  697 
  698 static void iwl_mvm_stats_energy_iter(void *_data,
  699                                       struct ieee80211_sta *sta)
  700 {
  701         struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
  702         u8 *energy = _data;
  703         u32 sta_id = mvmsta->sta_id;
  704 
  705         if (WARN_ONCE(sta_id >= IWL_MVM_STATION_COUNT_MAX, "sta_id %d >= %d",
  706                       sta_id, IWL_MVM_STATION_COUNT_MAX))
  707                 return;
  708 
  709         if (energy[sta_id])
  710                 mvmsta->avg_energy = energy[sta_id];
  711 
  712 }
  713 
  714 static void
  715 iwl_mvm_update_tcm_from_stats(struct iwl_mvm *mvm, __le32 *air_time_le,
  716                               __le32 *rx_bytes_le)
  717 {
  718         int i;
  719 
  720         spin_lock(&mvm->tcm.lock);
  721         for (i = 0; i < NUM_MAC_INDEX_DRIVER; i++) {
  722                 struct iwl_mvm_tcm_mac *mdata = &mvm->tcm.data[i];
  723                 u32 rx_bytes = le32_to_cpu(rx_bytes_le[i]);
  724                 u32 airtime = le32_to_cpu(air_time_le[i]);
  725 
  726                 mdata->rx.airtime += airtime;
  727                 mdata->uapsd_nonagg_detect.rx_bytes += rx_bytes;
  728                 if (airtime) {
  729                         /* re-init every time to store rate from FW */
  730                         ewma_rate_init(&mdata->uapsd_nonagg_detect.rate);
  731                         ewma_rate_add(&mdata->uapsd_nonagg_detect.rate,
  732                                       rx_bytes * 8 / airtime);
  733                 }
  734         }
  735         spin_unlock(&mvm->tcm.lock);
  736 }
  737 
  738 static void
  739 iwl_mvm_stats_ver_15(struct iwl_mvm *mvm,
  740                      struct iwl_statistics_operational_ntfy *stats)
  741 {
  742         struct iwl_mvm_stat_data_all_macs data = {
  743                 .mvm = mvm,
  744                 .flags = stats->flags,
  745                 .per_mac_stats = stats->per_mac_stats,
  746         };
  747 
  748         ieee80211_iterate_active_interfaces(mvm->hw,
  749                                             IEEE80211_IFACE_ITER_NORMAL,
  750                                             iwl_mvm_stat_iterator_all_macs,
  751                                             &data);
  752 }
  753 
  754 static void
  755 iwl_mvm_stats_ver_14(struct iwl_mvm *mvm,
  756                      struct iwl_statistics_operational_ntfy_ver_14 *stats)
  757 {
  758         struct iwl_mvm_stat_data data = {
  759                 .mvm = mvm,
  760         };
  761 
  762         u8 beacon_average_energy[MAC_INDEX_AUX];
  763         __le32 flags;
  764         int i;
  765 
  766         flags = stats->flags;
  767 
  768         data.mac_id = stats->mac_id;
  769         data.beacon_filter_average_energy =
  770                 le32_to_cpu(stats->beacon_filter_average_energy);
  771         data.flags = flags;
  772         data.beacon_counter = stats->beacon_counter;
  773 
  774         for (i = 0; i < ARRAY_SIZE(beacon_average_energy); i++)
  775                 beacon_average_energy[i] =
  776                         le32_to_cpu(stats->beacon_average_energy[i]);
  777 
  778         data.beacon_average_energy = beacon_average_energy;
  779 
  780         ieee80211_iterate_active_interfaces(mvm->hw,
  781                                             IEEE80211_IFACE_ITER_NORMAL,
  782                                             iwl_mvm_stat_iterator,
  783                                             &data);
  784 }
  785 
  786 static bool iwl_mvm_verify_stats_len(struct iwl_mvm *mvm,
  787                                      struct iwl_rx_packet *pkt,
  788                                      u32 expected_size)
  789 {
  790         struct iwl_statistics_ntfy_hdr *hdr;
  791 
  792         if (WARN_ONCE(iwl_rx_packet_payload_len(pkt) < expected_size,
  793                       "received invalid statistics size (%d)!, expected_size: %d\n",
  794                       iwl_rx_packet_payload_len(pkt), expected_size))
  795                 return false;
  796 
  797         hdr = (void *)&pkt->data;
  798 
  799         if (WARN_ONCE((hdr->type & IWL_STATISTICS_TYPE_MSK) != FW_STATISTICS_OPERATIONAL ||
  800                       hdr->version !=
  801                       iwl_fw_lookup_notif_ver(mvm->fw, LEGACY_GROUP, STATISTICS_NOTIFICATION, 0),
  802                       "received unsupported hdr type %d, version %d\n",
  803                       hdr->type, hdr->version))
  804                 return false;
  805 
  806         if (WARN_ONCE(le16_to_cpu(hdr->size) != expected_size,
  807                       "received invalid statistics size in header (%d)!, expected_size: %d\n",
  808                       le16_to_cpu(hdr->size), expected_size))
  809                 return false;
  810 
  811         return true;
  812 }
  813 
  814 static void
  815 iwl_mvm_handle_rx_statistics_tlv(struct iwl_mvm *mvm,
  816                                  struct iwl_rx_packet *pkt)
  817 {
  818         u8 average_energy[IWL_MVM_STATION_COUNT_MAX];
  819         __le32 air_time[MAC_INDEX_AUX];
  820         __le32 rx_bytes[MAC_INDEX_AUX];
  821         __le32 flags = 0;
  822         int i;
  823         u32 notif_ver = iwl_fw_lookup_notif_ver(mvm->fw, LEGACY_GROUP,
  824                                               STATISTICS_NOTIFICATION, 0);
  825 
  826         if (WARN_ONCE(notif_ver > 15,
  827                       "invalid statistics version id: %d\n", notif_ver))
  828                 return;
  829 
  830         if (notif_ver == 14) {
  831                 struct iwl_statistics_operational_ntfy_ver_14 *stats =
  832                         (void *)pkt->data;
  833 
  834                 if (!iwl_mvm_verify_stats_len(mvm, pkt, sizeof(*stats)))
  835                         return;
  836 
  837                 iwl_mvm_stats_ver_14(mvm, stats);
  838 
  839                 flags = stats->flags;
  840                 mvm->radio_stats.rx_time = le64_to_cpu(stats->rx_time);
  841                 mvm->radio_stats.tx_time = le64_to_cpu(stats->tx_time);
  842                 mvm->radio_stats.on_time_rf = le64_to_cpu(stats->on_time_rf);
  843                 mvm->radio_stats.on_time_scan =
  844                         le64_to_cpu(stats->on_time_scan);
  845 
  846                 for (i = 0; i < ARRAY_SIZE(average_energy); i++)
  847                         average_energy[i] = le32_to_cpu(stats->average_energy[i]);
  848 
  849                 for (i = 0; i < ARRAY_SIZE(air_time); i++) {
  850                         air_time[i] = stats->air_time[i];
  851                         rx_bytes[i] = stats->rx_bytes[i];
  852                 }
  853         }
  854 
  855         if (notif_ver == 15) {
  856                 struct iwl_statistics_operational_ntfy *stats =
  857                         (void *)pkt->data;
  858 
  859                 if (!iwl_mvm_verify_stats_len(mvm, pkt, sizeof(*stats)))
  860                         return;
  861 
  862                 iwl_mvm_stats_ver_15(mvm, stats);
  863 
  864                 flags = stats->flags;
  865                 mvm->radio_stats.rx_time = le64_to_cpu(stats->rx_time);
  866                 mvm->radio_stats.tx_time = le64_to_cpu(stats->tx_time);
  867                 mvm->radio_stats.on_time_rf = le64_to_cpu(stats->on_time_rf);
  868                 mvm->radio_stats.on_time_scan =
  869                         le64_to_cpu(stats->on_time_scan);
  870 
  871                 for (i = 0; i < ARRAY_SIZE(average_energy); i++)
  872                         average_energy[i] =
  873                                 le32_to_cpu(stats->per_sta_stats[i].average_energy);
  874 
  875                 for (i = 0; i < ARRAY_SIZE(air_time); i++) {
  876                         air_time[i] = stats->per_mac_stats[i].air_time;
  877                         rx_bytes[i] = stats->per_mac_stats[i].rx_bytes;
  878                 }
  879         }
  880 
  881         iwl_mvm_rx_stats_check_trigger(mvm, pkt);
  882 
  883         ieee80211_iterate_stations_atomic(mvm->hw, iwl_mvm_stats_energy_iter,
  884                                           average_energy);
  885         /*
  886          * Don't update in case the statistics are not cleared, since
  887          * we will end up counting twice the same airtime, once in TCM
  888          * request and once in statistics notification.
  889          */
  890         if (le32_to_cpu(flags) & IWL_STATISTICS_REPLY_FLG_CLEAR)
  891                 iwl_mvm_update_tcm_from_stats(mvm, air_time, rx_bytes);
  892 }
  893 
  894 void iwl_mvm_handle_rx_statistics(struct iwl_mvm *mvm,
  895                                   struct iwl_rx_packet *pkt)
  896 {
  897         struct iwl_mvm_stat_data data = {
  898                 .mvm = mvm,
  899         };
  900         __le32 *bytes, *air_time, flags;
  901         int expected_size;
  902         u8 *energy;
  903 
  904         /* From ver 14 and up we use TLV statistics format */
  905         if (iwl_fw_lookup_notif_ver(mvm->fw, LEGACY_GROUP,
  906                                     STATISTICS_NOTIFICATION, 0) >= 14)
  907                 return iwl_mvm_handle_rx_statistics_tlv(mvm, pkt);
  908 
  909         if (!iwl_mvm_has_new_rx_stats_api(mvm)) {
  910                 if (iwl_mvm_has_new_rx_api(mvm))
  911                         expected_size = sizeof(struct iwl_notif_statistics_v11);
  912                 else
  913                         expected_size = sizeof(struct iwl_notif_statistics_v10);
  914         } else {
  915                 expected_size = sizeof(struct iwl_notif_statistics);
  916         }
  917 
  918         if (WARN_ONCE(iwl_rx_packet_payload_len(pkt) != expected_size,
  919                       "received invalid statistics size (%d)!\n",
  920                       iwl_rx_packet_payload_len(pkt)))
  921                 return;
  922 
  923         if (!iwl_mvm_has_new_rx_stats_api(mvm)) {
  924                 struct iwl_notif_statistics_v11 *stats = (void *)&pkt->data;
  925 
  926                 data.mac_id = stats->rx.general.mac_id;
  927                 data.beacon_filter_average_energy =
  928                         stats->general.common.beacon_filter_average_energy;
  929 
  930                 mvm->rx_stats_v3 = stats->rx;
  931 
  932                 mvm->radio_stats.rx_time =
  933                         le64_to_cpu(stats->general.common.rx_time);
  934                 mvm->radio_stats.tx_time =
  935                         le64_to_cpu(stats->general.common.tx_time);
  936                 mvm->radio_stats.on_time_rf =
  937                         le64_to_cpu(stats->general.common.on_time_rf);
  938                 mvm->radio_stats.on_time_scan =
  939                         le64_to_cpu(stats->general.common.on_time_scan);
  940 
  941                 data.beacon_counter = stats->general.beacon_counter;
  942                 data.beacon_average_energy =
  943                         stats->general.beacon_average_energy;
  944                 flags = stats->flag;
  945         } else {
  946                 struct iwl_notif_statistics *stats = (void *)&pkt->data;
  947 
  948                 data.mac_id = stats->rx.general.mac_id;
  949                 data.beacon_filter_average_energy =
  950                         stats->general.common.beacon_filter_average_energy;
  951 
  952                 mvm->rx_stats = stats->rx;
  953 
  954                 mvm->radio_stats.rx_time =
  955                         le64_to_cpu(stats->general.common.rx_time);
  956                 mvm->radio_stats.tx_time =
  957                         le64_to_cpu(stats->general.common.tx_time);
  958                 mvm->radio_stats.on_time_rf =
  959                         le64_to_cpu(stats->general.common.on_time_rf);
  960                 mvm->radio_stats.on_time_scan =
  961                         le64_to_cpu(stats->general.common.on_time_scan);
  962 
  963                 data.beacon_counter = stats->general.beacon_counter;
  964                 data.beacon_average_energy =
  965                         stats->general.beacon_average_energy;
  966                 flags = stats->flag;
  967         }
  968         data.flags = flags;
  969 
  970         iwl_mvm_rx_stats_check_trigger(mvm, pkt);
  971 
  972         ieee80211_iterate_active_interfaces(mvm->hw,
  973                                             IEEE80211_IFACE_ITER_NORMAL,
  974                                             iwl_mvm_stat_iterator,
  975                                             &data);
  976 
  977         if (!iwl_mvm_has_new_rx_api(mvm))
  978                 return;
  979 
  980         if (!iwl_mvm_has_new_rx_stats_api(mvm)) {
  981                 struct iwl_notif_statistics_v11 *v11 = (void *)&pkt->data;
  982 
  983                 energy = (void *)&v11->load_stats.avg_energy;
  984                 bytes = (void *)&v11->load_stats.byte_count;
  985                 air_time = (void *)&v11->load_stats.air_time;
  986         } else {
  987                 struct iwl_notif_statistics *stats = (void *)&pkt->data;
  988 
  989                 energy = (void *)&stats->load_stats.avg_energy;
  990                 bytes = (void *)&stats->load_stats.byte_count;
  991                 air_time = (void *)&stats->load_stats.air_time;
  992         }
  993         ieee80211_iterate_stations_atomic(mvm->hw, iwl_mvm_stats_energy_iter,
  994                                           energy);
  995 
  996         /*
  997          * Don't update in case the statistics are not cleared, since
  998          * we will end up counting twice the same airtime, once in TCM
  999          * request and once in statistics notification.
 1000          */
 1001         if (le32_to_cpu(flags) & IWL_STATISTICS_REPLY_FLG_CLEAR)
 1002                 iwl_mvm_update_tcm_from_stats(mvm, air_time, bytes);
 1003 
 1004 }
 1005 
 1006 void iwl_mvm_rx_statistics(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb)
 1007 {
 1008         iwl_mvm_handle_rx_statistics(mvm, rxb_addr(rxb));
 1009 }
 1010 
 1011 void iwl_mvm_window_status_notif(struct iwl_mvm *mvm,
 1012                                  struct iwl_rx_cmd_buffer *rxb)
 1013 {
 1014         struct iwl_rx_packet *pkt = rxb_addr(rxb);
 1015         struct iwl_ba_window_status_notif *notif = (void *)pkt->data;
 1016         int i;
 1017 
 1018         BUILD_BUG_ON(ARRAY_SIZE(notif->ra_tid) != BA_WINDOW_STREAMS_MAX);
 1019         BUILD_BUG_ON(ARRAY_SIZE(notif->mpdu_rx_count) != BA_WINDOW_STREAMS_MAX);
 1020         BUILD_BUG_ON(ARRAY_SIZE(notif->bitmap) != BA_WINDOW_STREAMS_MAX);
 1021         BUILD_BUG_ON(ARRAY_SIZE(notif->start_seq_num) != BA_WINDOW_STREAMS_MAX);
 1022 
 1023         rcu_read_lock();
 1024         for (i = 0; i < BA_WINDOW_STREAMS_MAX; i++) {
 1025                 struct ieee80211_sta *sta;
 1026                 u8 sta_id, tid;
 1027                 u64 bitmap;
 1028                 u32 ssn;
 1029                 u16 ratid;
 1030                 u16 received_mpdu;
 1031 
 1032                 ratid = le16_to_cpu(notif->ra_tid[i]);
 1033                 /* check that this TID is valid */
 1034                 if (!(ratid & BA_WINDOW_STATUS_VALID_MSK))
 1035                         continue;
 1036 
 1037                 received_mpdu = le16_to_cpu(notif->mpdu_rx_count[i]);
 1038                 if (received_mpdu == 0)
 1039                         continue;
 1040 
 1041                 tid = ratid & BA_WINDOW_STATUS_TID_MSK;
 1042                 /* get the station */
 1043                 sta_id = (ratid & BA_WINDOW_STATUS_STA_ID_MSK)
 1044                          >> BA_WINDOW_STATUS_STA_ID_POS;
 1045                 sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]);
 1046                 if (IS_ERR_OR_NULL(sta))
 1047                         continue;
 1048                 bitmap = le64_to_cpu(notif->bitmap[i]);
 1049                 ssn = le32_to_cpu(notif->start_seq_num[i]);
 1050 
 1051                 /* update mac80211 with the bitmap for the reordering buffer */
 1052                 ieee80211_mark_rx_ba_filtered_frames(sta, tid, ssn, bitmap,
 1053                                                      received_mpdu);
 1054         }
 1055         rcu_read_unlock();
 1056 }

Cache object: 75db1256c3f5a802105d98b7a5149a6b


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.