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/rs-fw.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) 2017 Intel Deutschland GmbH
    4  * Copyright (C) 2018-2022 Intel Corporation
    5  */
    6 #include "rs.h"
    7 #include "fw-api.h"
    8 #include "sta.h"
    9 #include "iwl-op-mode.h"
   10 #include "mvm.h"
   11 
   12 static u8 rs_fw_bw_from_sta_bw(struct ieee80211_sta *sta)
   13 {
   14         switch (sta->deflink.bandwidth) {
   15         case IEEE80211_STA_RX_BW_160:
   16                 return IWL_TLC_MNG_CH_WIDTH_160MHZ;
   17         case IEEE80211_STA_RX_BW_80:
   18                 return IWL_TLC_MNG_CH_WIDTH_80MHZ;
   19         case IEEE80211_STA_RX_BW_40:
   20                 return IWL_TLC_MNG_CH_WIDTH_40MHZ;
   21         case IEEE80211_STA_RX_BW_20:
   22         default:
   23                 return IWL_TLC_MNG_CH_WIDTH_20MHZ;
   24         }
   25 }
   26 
   27 static u8 rs_fw_set_active_chains(u8 chains)
   28 {
   29         u8 fw_chains = 0;
   30 
   31         if (chains & ANT_A)
   32                 fw_chains |= IWL_TLC_MNG_CHAIN_A_MSK;
   33         if (chains & ANT_B)
   34                 fw_chains |= IWL_TLC_MNG_CHAIN_B_MSK;
   35 
   36         return fw_chains;
   37 }
   38 
   39 static u8 rs_fw_sgi_cw_support(struct ieee80211_sta *sta)
   40 {
   41         struct ieee80211_sta_ht_cap *ht_cap = &sta->deflink.ht_cap;
   42         struct ieee80211_sta_vht_cap *vht_cap = &sta->deflink.vht_cap;
   43         struct ieee80211_sta_he_cap *he_cap = &sta->deflink.he_cap;
   44         u8 supp = 0;
   45 
   46         if (he_cap->has_he)
   47                 return 0;
   48 
   49         if (ht_cap->cap & IEEE80211_HT_CAP_SGI_20)
   50                 supp |= BIT(IWL_TLC_MNG_CH_WIDTH_20MHZ);
   51         if (ht_cap->cap & IEEE80211_HT_CAP_SGI_40)
   52                 supp |= BIT(IWL_TLC_MNG_CH_WIDTH_40MHZ);
   53         if (vht_cap->cap & IEEE80211_VHT_CAP_SHORT_GI_80)
   54                 supp |= BIT(IWL_TLC_MNG_CH_WIDTH_80MHZ);
   55         if (vht_cap->cap & IEEE80211_VHT_CAP_SHORT_GI_160)
   56                 supp |= BIT(IWL_TLC_MNG_CH_WIDTH_160MHZ);
   57 
   58         return supp;
   59 }
   60 
   61 static u16 rs_fw_get_config_flags(struct iwl_mvm *mvm,
   62                                   struct ieee80211_sta *sta,
   63                                   struct ieee80211_supported_band *sband)
   64 {
   65         struct ieee80211_sta_ht_cap *ht_cap = &sta->deflink.ht_cap;
   66         struct ieee80211_sta_vht_cap *vht_cap = &sta->deflink.vht_cap;
   67         struct ieee80211_sta_he_cap *he_cap = &sta->deflink.he_cap;
   68         bool vht_ena = vht_cap->vht_supported;
   69         u16 flags = 0;
   70 
   71         /* get STBC flags */
   72         if (mvm->cfg->ht_params->stbc &&
   73             (num_of_ant(iwl_mvm_get_valid_tx_ant(mvm)) > 1)) {
   74                 if (he_cap->has_he && he_cap->he_cap_elem.phy_cap_info[2] &
   75                                       IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ)
   76                         flags |= IWL_TLC_MNG_CFG_FLAGS_STBC_MSK;
   77                 else if (vht_cap->cap & IEEE80211_VHT_CAP_RXSTBC_MASK)
   78                         flags |= IWL_TLC_MNG_CFG_FLAGS_STBC_MSK;
   79                 else if (ht_cap->cap & IEEE80211_HT_CAP_RX_STBC)
   80                         flags |= IWL_TLC_MNG_CFG_FLAGS_STBC_MSK;
   81         }
   82 
   83         if (mvm->cfg->ht_params->ldpc &&
   84             ((ht_cap->cap & IEEE80211_HT_CAP_LDPC_CODING) ||
   85              (vht_ena && (vht_cap->cap & IEEE80211_VHT_CAP_RXLDPC))))
   86                 flags |= IWL_TLC_MNG_CFG_FLAGS_LDPC_MSK;
   87 
   88         /* consider LDPC support in case of HE */
   89         if (he_cap->has_he && (he_cap->he_cap_elem.phy_cap_info[1] &
   90             IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD))
   91                 flags |= IWL_TLC_MNG_CFG_FLAGS_LDPC_MSK;
   92 
   93         if (sband->iftype_data && sband->iftype_data->he_cap.has_he &&
   94             !(sband->iftype_data->he_cap.he_cap_elem.phy_cap_info[1] &
   95              IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD))
   96                 flags &= ~IWL_TLC_MNG_CFG_FLAGS_LDPC_MSK;
   97 
   98         if (he_cap->has_he &&
   99             (he_cap->he_cap_elem.phy_cap_info[3] &
  100              IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_MASK &&
  101              sband->iftype_data &&
  102              sband->iftype_data->he_cap.he_cap_elem.phy_cap_info[3] &
  103              IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_MASK))
  104                 flags |= IWL_TLC_MNG_CFG_FLAGS_HE_DCM_NSS_1_MSK;
  105 
  106         return flags;
  107 }
  108 
  109 static
  110 int rs_fw_vht_highest_rx_mcs_index(const struct ieee80211_sta_vht_cap *vht_cap,
  111                                    int nss)
  112 {
  113         u16 rx_mcs = le16_to_cpu(vht_cap->vht_mcs.rx_mcs_map) &
  114                 (0x3 << (2 * (nss - 1)));
  115         rx_mcs >>= (2 * (nss - 1));
  116 
  117         switch (rx_mcs) {
  118         case IEEE80211_VHT_MCS_SUPPORT_0_7:
  119                 return IWL_TLC_MNG_HT_RATE_MCS7;
  120         case IEEE80211_VHT_MCS_SUPPORT_0_8:
  121                 return IWL_TLC_MNG_HT_RATE_MCS8;
  122         case IEEE80211_VHT_MCS_SUPPORT_0_9:
  123                 return IWL_TLC_MNG_HT_RATE_MCS9;
  124         default:
  125                 WARN_ON_ONCE(1);
  126                 break;
  127         }
  128 
  129         return 0;
  130 }
  131 
  132 static void
  133 rs_fw_vht_set_enabled_rates(const struct ieee80211_sta *sta,
  134                             const struct ieee80211_sta_vht_cap *vht_cap,
  135                             struct iwl_tlc_config_cmd_v4 *cmd)
  136 {
  137         u16 supp;
  138         int i, highest_mcs;
  139         u8 max_nss = sta->deflink.rx_nss;
  140         struct ieee80211_vht_cap ieee_vht_cap = {
  141                 .vht_cap_info = cpu_to_le32(vht_cap->cap),
  142                 .supp_mcs = vht_cap->vht_mcs,
  143         };
  144 
  145         /* the station support only a single receive chain */
  146         if (sta->smps_mode == IEEE80211_SMPS_STATIC)
  147                 max_nss = 1;
  148 
  149         for (i = 0; i < max_nss && i < IWL_TLC_NSS_MAX; i++) {
  150                 int nss = i + 1;
  151 
  152                 highest_mcs = rs_fw_vht_highest_rx_mcs_index(vht_cap, nss);
  153                 if (!highest_mcs)
  154                         continue;
  155 
  156                 supp = BIT(highest_mcs + 1) - 1;
  157                 if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_20)
  158                         supp &= ~BIT(IWL_TLC_MNG_HT_RATE_MCS9);
  159 
  160                 cmd->ht_rates[i][IWL_TLC_MCS_PER_BW_80] = cpu_to_le16(supp);
  161                 /*
  162                  * Check if VHT extended NSS indicates that the bandwidth/NSS
  163                  * configuration is supported - only for MCS 0 since we already
  164                  * decoded the MCS bits anyway ourselves.
  165                  */
  166                 if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_160 &&
  167                     ieee80211_get_vht_max_nss(&ieee_vht_cap,
  168                                               IEEE80211_VHT_CHANWIDTH_160MHZ,
  169                                               0, true, nss) >= nss)
  170                         cmd->ht_rates[i][IWL_TLC_MCS_PER_BW_160] =
  171                                 cmd->ht_rates[i][IWL_TLC_MCS_PER_BW_80];
  172         }
  173 }
  174 
  175 static u16 rs_fw_he_ieee80211_mcs_to_rs_mcs(u16 mcs)
  176 {
  177         switch (mcs) {
  178         case IEEE80211_HE_MCS_SUPPORT_0_7:
  179                 return BIT(IWL_TLC_MNG_HT_RATE_MCS7 + 1) - 1;
  180         case IEEE80211_HE_MCS_SUPPORT_0_9:
  181                 return BIT(IWL_TLC_MNG_HT_RATE_MCS9 + 1) - 1;
  182         case IEEE80211_HE_MCS_SUPPORT_0_11:
  183                 return BIT(IWL_TLC_MNG_HT_RATE_MCS11 + 1) - 1;
  184         case IEEE80211_HE_MCS_NOT_SUPPORTED:
  185                 return 0;
  186         }
  187 
  188         WARN(1, "invalid HE MCS %d\n", mcs);
  189         return 0;
  190 }
  191 
  192 static void
  193 rs_fw_he_set_enabled_rates(const struct ieee80211_sta *sta,
  194                            struct ieee80211_supported_band *sband,
  195                            struct iwl_tlc_config_cmd_v4 *cmd)
  196 {
  197         const struct ieee80211_sta_he_cap *he_cap = &sta->deflink.he_cap;
  198         u16 mcs_160 = le16_to_cpu(he_cap->he_mcs_nss_supp.rx_mcs_160);
  199         u16 mcs_80 = le16_to_cpu(he_cap->he_mcs_nss_supp.rx_mcs_80);
  200         u16 tx_mcs_80 =
  201                 le16_to_cpu(sband->iftype_data->he_cap.he_mcs_nss_supp.tx_mcs_80);
  202         u16 tx_mcs_160 =
  203                 le16_to_cpu(sband->iftype_data->he_cap.he_mcs_nss_supp.tx_mcs_160);
  204         int i;
  205         u8 nss = sta->deflink.rx_nss;
  206 
  207         /* the station support only a single receive chain */
  208         if (sta->smps_mode == IEEE80211_SMPS_STATIC)
  209                 nss = 1;
  210 
  211         for (i = 0; i < nss && i < IWL_TLC_NSS_MAX; i++) {
  212                 u16 _mcs_160 = (mcs_160 >> (2 * i)) & 0x3;
  213                 u16 _mcs_80 = (mcs_80 >> (2 * i)) & 0x3;
  214                 u16 _tx_mcs_160 = (tx_mcs_160 >> (2 * i)) & 0x3;
  215                 u16 _tx_mcs_80 = (tx_mcs_80 >> (2 * i)) & 0x3;
  216 
  217                 /* If one side doesn't support - mark both as not supporting */
  218                 if (_mcs_80 == IEEE80211_HE_MCS_NOT_SUPPORTED ||
  219                     _tx_mcs_80 == IEEE80211_HE_MCS_NOT_SUPPORTED) {
  220                         _mcs_80 = IEEE80211_HE_MCS_NOT_SUPPORTED;
  221                         _tx_mcs_80 = IEEE80211_HE_MCS_NOT_SUPPORTED;
  222                 }
  223                 if (_mcs_80 > _tx_mcs_80)
  224                         _mcs_80 = _tx_mcs_80;
  225                 cmd->ht_rates[i][IWL_TLC_MCS_PER_BW_80] =
  226                         cpu_to_le16(rs_fw_he_ieee80211_mcs_to_rs_mcs(_mcs_80));
  227 
  228                 /* If one side doesn't support - mark both as not supporting */
  229                 if (_mcs_160 == IEEE80211_HE_MCS_NOT_SUPPORTED ||
  230                     _tx_mcs_160 == IEEE80211_HE_MCS_NOT_SUPPORTED) {
  231                         _mcs_160 = IEEE80211_HE_MCS_NOT_SUPPORTED;
  232                         _tx_mcs_160 = IEEE80211_HE_MCS_NOT_SUPPORTED;
  233                 }
  234                 if (_mcs_160 > _tx_mcs_160)
  235                         _mcs_160 = _tx_mcs_160;
  236                 cmd->ht_rates[i][IWL_TLC_MCS_PER_BW_160] =
  237                         cpu_to_le16(rs_fw_he_ieee80211_mcs_to_rs_mcs(_mcs_160));
  238         }
  239 }
  240 
  241 static void rs_fw_set_supp_rates(struct ieee80211_sta *sta,
  242                                  struct ieee80211_supported_band *sband,
  243                                  struct iwl_tlc_config_cmd_v4 *cmd)
  244 {
  245         int i;
  246         u16 supp = 0;
  247         unsigned long tmp; /* must be unsigned long for for_each_set_bit */
  248         const struct ieee80211_sta_ht_cap *ht_cap = &sta->deflink.ht_cap;
  249         const struct ieee80211_sta_vht_cap *vht_cap = &sta->deflink.vht_cap;
  250         const struct ieee80211_sta_he_cap *he_cap = &sta->deflink.he_cap;
  251 
  252         /* non HT rates */
  253         tmp = sta->deflink.supp_rates[sband->band];
  254         for_each_set_bit(i, &tmp, BITS_PER_LONG)
  255                 supp |= BIT(sband->bitrates[i].hw_value);
  256 
  257         cmd->non_ht_rates = cpu_to_le16(supp);
  258         cmd->mode = IWL_TLC_MNG_MODE_NON_HT;
  259 
  260         /* HT/VHT rates */
  261         if (he_cap->has_he) {
  262                 cmd->mode = IWL_TLC_MNG_MODE_HE;
  263                 rs_fw_he_set_enabled_rates(sta, sband, cmd);
  264         } else if (vht_cap->vht_supported) {
  265                 cmd->mode = IWL_TLC_MNG_MODE_VHT;
  266                 rs_fw_vht_set_enabled_rates(sta, vht_cap, cmd);
  267         } else if (ht_cap->ht_supported) {
  268                 cmd->mode = IWL_TLC_MNG_MODE_HT;
  269                 cmd->ht_rates[IWL_TLC_NSS_1][IWL_TLC_MCS_PER_BW_80] =
  270                         cpu_to_le16(ht_cap->mcs.rx_mask[0]);
  271 
  272                 /* the station support only a single receive chain */
  273                 if (sta->smps_mode == IEEE80211_SMPS_STATIC)
  274                         cmd->ht_rates[IWL_TLC_NSS_2][IWL_TLC_MCS_PER_BW_80] =
  275                                 0;
  276                 else
  277                         cmd->ht_rates[IWL_TLC_NSS_2][IWL_TLC_MCS_PER_BW_80] =
  278                                 cpu_to_le16(ht_cap->mcs.rx_mask[1]);
  279         }
  280 }
  281 
  282 void iwl_mvm_tlc_update_notif(struct iwl_mvm *mvm,
  283                               struct iwl_rx_cmd_buffer *rxb)
  284 {
  285         struct iwl_rx_packet *pkt = rxb_addr(rxb);
  286         struct iwl_tlc_update_notif *notif;
  287         struct ieee80211_sta *sta;
  288         struct iwl_mvm_sta *mvmsta;
  289         struct iwl_lq_sta_rs_fw *lq_sta;
  290         u32 flags;
  291 
  292         rcu_read_lock();
  293 
  294         notif = (void *)pkt->data;
  295         sta = rcu_dereference(mvm->fw_id_to_mac_id[notif->sta_id]);
  296         if (IS_ERR_OR_NULL(sta)) {
  297                 /* can happen in remove station flow where mvm removed internally
  298                  * the station before removing from FW
  299                  */
  300                 IWL_DEBUG_RATE(mvm,
  301                                "Invalid mvm RCU pointer for sta id (%d) in TLC notification\n",
  302                                notif->sta_id);
  303                 goto out;
  304         }
  305 
  306         mvmsta = iwl_mvm_sta_from_mac80211(sta);
  307 
  308         if (!mvmsta) {
  309                 IWL_ERR(mvm, "Invalid sta id (%d) in FW TLC notification\n",
  310                         notif->sta_id);
  311                 goto out;
  312         }
  313 
  314         flags = le32_to_cpu(notif->flags);
  315 
  316         lq_sta = &mvmsta->lq_sta.rs_fw;
  317 
  318         if (flags & IWL_TLC_NOTIF_FLAG_RATE) {
  319                 char pretty_rate[100];
  320 
  321                 if (iwl_fw_lookup_notif_ver(mvm->fw, DATA_PATH_GROUP,
  322                                             TLC_MNG_UPDATE_NOTIF, 0) < 3) {
  323                         rs_pretty_print_rate_v1(pretty_rate,
  324                                                 sizeof(pretty_rate),
  325                                                 le32_to_cpu(notif->rate));
  326                         IWL_DEBUG_RATE(mvm,
  327                                        "Got rate in old format. Rate: %s. Converting.\n",
  328                                        pretty_rate);
  329                         lq_sta->last_rate_n_flags =
  330                                 iwl_new_rate_from_v1(le32_to_cpu(notif->rate));
  331                 } else {
  332                         lq_sta->last_rate_n_flags = le32_to_cpu(notif->rate);
  333                 }
  334                 rs_pretty_print_rate(pretty_rate, sizeof(pretty_rate),
  335                                      lq_sta->last_rate_n_flags);
  336                 IWL_DEBUG_RATE(mvm, "new rate: %s\n", pretty_rate);
  337         }
  338 
  339         if (flags & IWL_TLC_NOTIF_FLAG_AMSDU && !mvmsta->orig_amsdu_len) {
  340                 u16 size = le32_to_cpu(notif->amsdu_size);
  341                 int i;
  342 
  343                 if (sta->max_amsdu_len < size) {
  344                         /*
  345                          * In debug sta->max_amsdu_len < size
  346                          * so also check with orig_amsdu_len which holds the
  347                          * original data before debugfs changed the value
  348                          */
  349                         WARN_ON(mvmsta->orig_amsdu_len < size);
  350                         goto out;
  351                 }
  352 
  353                 mvmsta->amsdu_enabled = le32_to_cpu(notif->amsdu_enabled);
  354                 mvmsta->max_amsdu_len = size;
  355                 sta->max_rc_amsdu_len = mvmsta->max_amsdu_len;
  356 
  357                 for (i = 0; i < IWL_MAX_TID_COUNT; i++) {
  358                         if (mvmsta->amsdu_enabled & BIT(i))
  359                                 sta->max_tid_amsdu_len[i] =
  360                                         iwl_mvm_max_amsdu_size(mvm, sta, i);
  361                         else
  362                                 /*
  363                                  * Not so elegant, but this will effectively
  364                                  * prevent AMSDU on this TID
  365                                  */
  366                                 sta->max_tid_amsdu_len[i] = 1;
  367                 }
  368 
  369                 IWL_DEBUG_RATE(mvm,
  370                                "AMSDU update. AMSDU size: %d, AMSDU selected size: %d, AMSDU TID bitmap 0x%X\n",
  371                                le32_to_cpu(notif->amsdu_size), size,
  372                                mvmsta->amsdu_enabled);
  373         }
  374 out:
  375         rcu_read_unlock();
  376 }
  377 
  378 u16 rs_fw_get_max_amsdu_len(struct ieee80211_sta *sta)
  379 {
  380         struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
  381         const struct ieee80211_sta_vht_cap *vht_cap = &sta->deflink.vht_cap;
  382         const struct ieee80211_sta_ht_cap *ht_cap = &sta->deflink.ht_cap;
  383 
  384         if (mvmsta->vif->bss_conf.chandef.chan->band == NL80211_BAND_6GHZ) {
  385                 switch (le16_get_bits(sta->deflink.he_6ghz_capa.capa,
  386                                       IEEE80211_HE_6GHZ_CAP_MAX_MPDU_LEN)) {
  387                 case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454:
  388                         return IEEE80211_MAX_MPDU_LEN_VHT_11454;
  389                 case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991:
  390                         return IEEE80211_MAX_MPDU_LEN_VHT_7991;
  391                 default:
  392                         return IEEE80211_MAX_MPDU_LEN_VHT_3895;
  393                 }
  394         } else
  395         if (vht_cap->vht_supported) {
  396                 switch (vht_cap->cap & IEEE80211_VHT_CAP_MAX_MPDU_MASK) {
  397                 case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454:
  398                         return IEEE80211_MAX_MPDU_LEN_VHT_11454;
  399                 case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991:
  400                         return IEEE80211_MAX_MPDU_LEN_VHT_7991;
  401                 default:
  402                         return IEEE80211_MAX_MPDU_LEN_VHT_3895;
  403                 }
  404         } else if (ht_cap->ht_supported) {
  405                 if (ht_cap->cap & IEEE80211_HT_CAP_MAX_AMSDU)
  406                         /*
  407                          * agg is offloaded so we need to assume that agg
  408                          * are enabled and max mpdu in ampdu is 4095
  409                          * (spec 802.11-2016 9.3.2.1)
  410                          */
  411                         return IEEE80211_MAX_MPDU_LEN_HT_BA;
  412                 else
  413                         return IEEE80211_MAX_MPDU_LEN_HT_3839;
  414         }
  415 
  416         /* in legacy mode no amsdu is enabled so return zero */
  417         return 0;
  418 }
  419 
  420 void rs_fw_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
  421                      enum nl80211_band band, bool update)
  422 {
  423         struct ieee80211_hw *hw = mvm->hw;
  424         struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
  425         struct iwl_lq_sta_rs_fw *lq_sta = &mvmsta->lq_sta.rs_fw;
  426         u32 cmd_id = WIDE_ID(DATA_PATH_GROUP, TLC_MNG_CONFIG_CMD);
  427         struct ieee80211_supported_band *sband = hw->wiphy->bands[band];
  428         u16 max_amsdu_len = rs_fw_get_max_amsdu_len(sta);
  429         struct iwl_tlc_config_cmd_v4 cfg_cmd = {
  430                 .sta_id = mvmsta->sta_id,
  431                 .max_ch_width = update ?
  432                         rs_fw_bw_from_sta_bw(sta) : RATE_MCS_CHAN_WIDTH_20,
  433                 .flags = cpu_to_le16(rs_fw_get_config_flags(mvm, sta, sband)),
  434                 .chains = rs_fw_set_active_chains(iwl_mvm_get_valid_tx_ant(mvm)),
  435                 .sgi_ch_width_supp = rs_fw_sgi_cw_support(sta),
  436                 .max_mpdu_len = iwl_mvm_is_csum_supported(mvm) ?
  437                                 cpu_to_le16(max_amsdu_len) : 0,
  438         };
  439         int ret;
  440         int cmd_ver;
  441 
  442         memset(lq_sta, 0, offsetof(typeof(*lq_sta), pers));
  443 
  444 #ifdef CONFIG_IWLWIFI_DEBUGFS
  445         iwl_mvm_reset_frame_stats(mvm);
  446 #endif
  447         rs_fw_set_supp_rates(sta, sband, &cfg_cmd);
  448 
  449         /*
  450          * since TLC offload works with one mode we can assume
  451          * that only vht/ht is used and also set it as station max amsdu
  452          */
  453         sta->max_amsdu_len = max_amsdu_len;
  454 
  455         cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw,
  456                                         WIDE_ID(DATA_PATH_GROUP,
  457                                                 TLC_MNG_CONFIG_CMD),
  458                                         0);
  459         IWL_DEBUG_RATE(mvm, "TLC CONFIG CMD, sta_id=%d, max_ch_width=%d, mode=%d\n",
  460                        cfg_cmd.sta_id, cfg_cmd.max_ch_width, cfg_cmd.mode);
  461         IWL_DEBUG_RATE(mvm, "TLC CONFIG CMD, chains=0x%X, ch_wid_supp=%d, flags=0x%X\n",
  462                        cfg_cmd.chains, cfg_cmd.sgi_ch_width_supp, cfg_cmd.flags);
  463         IWL_DEBUG_RATE(mvm, "TLC CONFIG CMD, mpdu_len=%d, no_ht_rate=0x%X, tx_op=%d\n",
  464                        cfg_cmd.max_mpdu_len, cfg_cmd.non_ht_rates, cfg_cmd.max_tx_op);
  465         IWL_DEBUG_RATE(mvm, "TLC CONFIG CMD, ht_rate[0][0]=0x%X, ht_rate[1][0]=0x%X\n",
  466                        cfg_cmd.ht_rates[0][0], cfg_cmd.ht_rates[1][0]);
  467         IWL_DEBUG_RATE(mvm, "TLC CONFIG CMD, ht_rate[0][1]=0x%X, ht_rate[1][1]=0x%X\n",
  468                        cfg_cmd.ht_rates[0][1], cfg_cmd.ht_rates[1][1]);
  469         IWL_DEBUG_RATE(mvm, "TLC CONFIG CMD, ht_rate[0][2]=0x%X, ht_rate[1][2]=0x%X\n",
  470                        cfg_cmd.ht_rates[0][2], cfg_cmd.ht_rates[1][2]);
  471         if (cmd_ver == 4) {
  472                 ret = iwl_mvm_send_cmd_pdu(mvm, cmd_id, CMD_ASYNC,
  473                                            sizeof(cfg_cmd), &cfg_cmd);
  474         } else if (cmd_ver < 4) {
  475                 struct iwl_tlc_config_cmd_v3 cfg_cmd_v3 = {
  476                         .sta_id = cfg_cmd.sta_id,
  477                         .max_ch_width = cfg_cmd.max_ch_width,
  478                         .mode = cfg_cmd.mode,
  479                         .chains = cfg_cmd.chains,
  480                         .amsdu = !!cfg_cmd.max_mpdu_len,
  481                         .flags = cfg_cmd.flags,
  482                         .non_ht_rates = cfg_cmd.non_ht_rates,
  483                         .ht_rates[0][0] = cfg_cmd.ht_rates[0][0],
  484                         .ht_rates[0][1] = cfg_cmd.ht_rates[0][1],
  485                         .ht_rates[1][0] = cfg_cmd.ht_rates[1][0],
  486                         .ht_rates[1][1] = cfg_cmd.ht_rates[1][1],
  487                         .sgi_ch_width_supp = cfg_cmd.sgi_ch_width_supp,
  488                         .max_mpdu_len = cfg_cmd.max_mpdu_len,
  489                 };
  490 
  491                 u16 cmd_size = sizeof(cfg_cmd_v3);
  492 
  493                 /* In old versions of the API the struct is 4 bytes smaller */
  494                 if (iwl_fw_lookup_cmd_ver(mvm->fw,
  495                                           WIDE_ID(DATA_PATH_GROUP,
  496                                                   TLC_MNG_CONFIG_CMD), 0) < 3)
  497                         cmd_size -= 4;
  498 
  499                 ret = iwl_mvm_send_cmd_pdu(mvm, cmd_id, CMD_ASYNC, cmd_size,
  500                                            &cfg_cmd_v3);
  501         } else {
  502                 ret = -EINVAL;
  503         }
  504 
  505         if (ret)
  506                 IWL_ERR(mvm, "Failed to send rate scale config (%d)\n", ret);
  507 }
  508 
  509 int rs_fw_tx_protection(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta,
  510                         bool enable)
  511 {
  512         /* TODO: need to introduce a new FW cmd since LQ cmd is not relevant */
  513         IWL_DEBUG_RATE(mvm, "tx protection - not implemented yet.\n");
  514         return 0;
  515 }
  516 
  517 void iwl_mvm_rs_add_sta(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta)
  518 {
  519         struct iwl_lq_sta_rs_fw *lq_sta = &mvmsta->lq_sta.rs_fw;
  520 
  521         IWL_DEBUG_RATE(mvm, "create station rate scale window\n");
  522 
  523         lq_sta->pers.drv = mvm;
  524         lq_sta->pers.sta_id = mvmsta->sta_id;
  525         lq_sta->pers.chains = 0;
  526         memset(lq_sta->pers.chain_signal, 0, sizeof(lq_sta->pers.chain_signal));
  527         lq_sta->pers.last_rssi = S8_MIN;
  528         lq_sta->last_rate_n_flags = 0;
  529 
  530 #ifdef CONFIG_MAC80211_DEBUGFS
  531         lq_sta->pers.dbg_fixed_rate = 0;
  532 #endif
  533 }

Cache object: b42997d5dc3341e9a5badc706b4a0d7f


[ 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.