0001
0002
0003
0004
0005
0006 #include "rs.h"
0007 #include "fw-api.h"
0008 #include "sta.h"
0009 #include "iwl-op-mode.h"
0010 #include "mvm.h"
0011
0012 static u8 rs_fw_bw_from_sta_bw(struct ieee80211_sta *sta)
0013 {
0014 switch (sta->deflink.bandwidth) {
0015 case IEEE80211_STA_RX_BW_160:
0016 return IWL_TLC_MNG_CH_WIDTH_160MHZ;
0017 case IEEE80211_STA_RX_BW_80:
0018 return IWL_TLC_MNG_CH_WIDTH_80MHZ;
0019 case IEEE80211_STA_RX_BW_40:
0020 return IWL_TLC_MNG_CH_WIDTH_40MHZ;
0021 case IEEE80211_STA_RX_BW_20:
0022 default:
0023 return IWL_TLC_MNG_CH_WIDTH_20MHZ;
0024 }
0025 }
0026
0027 static u8 rs_fw_set_active_chains(u8 chains)
0028 {
0029 u8 fw_chains = 0;
0030
0031 if (chains & ANT_A)
0032 fw_chains |= IWL_TLC_MNG_CHAIN_A_MSK;
0033 if (chains & ANT_B)
0034 fw_chains |= IWL_TLC_MNG_CHAIN_B_MSK;
0035
0036 return fw_chains;
0037 }
0038
0039 static u8 rs_fw_sgi_cw_support(struct ieee80211_sta *sta)
0040 {
0041 struct ieee80211_sta_ht_cap *ht_cap = &sta->deflink.ht_cap;
0042 struct ieee80211_sta_vht_cap *vht_cap = &sta->deflink.vht_cap;
0043 struct ieee80211_sta_he_cap *he_cap = &sta->deflink.he_cap;
0044 u8 supp = 0;
0045
0046 if (he_cap->has_he)
0047 return 0;
0048
0049 if (ht_cap->cap & IEEE80211_HT_CAP_SGI_20)
0050 supp |= BIT(IWL_TLC_MNG_CH_WIDTH_20MHZ);
0051 if (ht_cap->cap & IEEE80211_HT_CAP_SGI_40)
0052 supp |= BIT(IWL_TLC_MNG_CH_WIDTH_40MHZ);
0053 if (vht_cap->cap & IEEE80211_VHT_CAP_SHORT_GI_80)
0054 supp |= BIT(IWL_TLC_MNG_CH_WIDTH_80MHZ);
0055 if (vht_cap->cap & IEEE80211_VHT_CAP_SHORT_GI_160)
0056 supp |= BIT(IWL_TLC_MNG_CH_WIDTH_160MHZ);
0057
0058 return supp;
0059 }
0060
0061 static u16 rs_fw_get_config_flags(struct iwl_mvm *mvm,
0062 struct ieee80211_sta *sta,
0063 struct ieee80211_supported_band *sband)
0064 {
0065 struct ieee80211_sta_ht_cap *ht_cap = &sta->deflink.ht_cap;
0066 struct ieee80211_sta_vht_cap *vht_cap = &sta->deflink.vht_cap;
0067 struct ieee80211_sta_he_cap *he_cap = &sta->deflink.he_cap;
0068 bool vht_ena = vht_cap->vht_supported;
0069 u16 flags = 0;
0070
0071
0072 if (mvm->cfg->ht_params->stbc &&
0073 (num_of_ant(iwl_mvm_get_valid_tx_ant(mvm)) > 1)) {
0074 if (he_cap->has_he && he_cap->he_cap_elem.phy_cap_info[2] &
0075 IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ)
0076 flags |= IWL_TLC_MNG_CFG_FLAGS_STBC_MSK;
0077 else if (vht_cap->cap & IEEE80211_VHT_CAP_RXSTBC_MASK)
0078 flags |= IWL_TLC_MNG_CFG_FLAGS_STBC_MSK;
0079 else if (ht_cap->cap & IEEE80211_HT_CAP_RX_STBC)
0080 flags |= IWL_TLC_MNG_CFG_FLAGS_STBC_MSK;
0081 }
0082
0083 if (mvm->cfg->ht_params->ldpc &&
0084 ((ht_cap->cap & IEEE80211_HT_CAP_LDPC_CODING) ||
0085 (vht_ena && (vht_cap->cap & IEEE80211_VHT_CAP_RXLDPC))))
0086 flags |= IWL_TLC_MNG_CFG_FLAGS_LDPC_MSK;
0087
0088
0089 if (he_cap->has_he && (he_cap->he_cap_elem.phy_cap_info[1] &
0090 IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD))
0091 flags |= IWL_TLC_MNG_CFG_FLAGS_LDPC_MSK;
0092
0093 if (sband->iftype_data && sband->iftype_data->he_cap.has_he &&
0094 !(sband->iftype_data->he_cap.he_cap_elem.phy_cap_info[1] &
0095 IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD))
0096 flags &= ~IWL_TLC_MNG_CFG_FLAGS_LDPC_MSK;
0097
0098 if (he_cap->has_he &&
0099 (he_cap->he_cap_elem.phy_cap_info[3] &
0100 IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_MASK &&
0101 sband->iftype_data &&
0102 sband->iftype_data->he_cap.he_cap_elem.phy_cap_info[3] &
0103 IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_MASK))
0104 flags |= IWL_TLC_MNG_CFG_FLAGS_HE_DCM_NSS_1_MSK;
0105
0106 return flags;
0107 }
0108
0109 static
0110 int rs_fw_vht_highest_rx_mcs_index(const struct ieee80211_sta_vht_cap *vht_cap,
0111 int nss)
0112 {
0113 u16 rx_mcs = le16_to_cpu(vht_cap->vht_mcs.rx_mcs_map) &
0114 (0x3 << (2 * (nss - 1)));
0115 rx_mcs >>= (2 * (nss - 1));
0116
0117 switch (rx_mcs) {
0118 case IEEE80211_VHT_MCS_SUPPORT_0_7:
0119 return IWL_TLC_MNG_HT_RATE_MCS7;
0120 case IEEE80211_VHT_MCS_SUPPORT_0_8:
0121 return IWL_TLC_MNG_HT_RATE_MCS8;
0122 case IEEE80211_VHT_MCS_SUPPORT_0_9:
0123 return IWL_TLC_MNG_HT_RATE_MCS9;
0124 default:
0125 WARN_ON_ONCE(1);
0126 break;
0127 }
0128
0129 return 0;
0130 }
0131
0132 static void
0133 rs_fw_vht_set_enabled_rates(const struct ieee80211_sta *sta,
0134 const struct ieee80211_sta_vht_cap *vht_cap,
0135 struct iwl_tlc_config_cmd_v4 *cmd)
0136 {
0137 u16 supp;
0138 int i, highest_mcs;
0139 u8 max_nss = sta->deflink.rx_nss;
0140 struct ieee80211_vht_cap ieee_vht_cap = {
0141 .vht_cap_info = cpu_to_le32(vht_cap->cap),
0142 .supp_mcs = vht_cap->vht_mcs,
0143 };
0144
0145
0146 if (sta->smps_mode == IEEE80211_SMPS_STATIC)
0147 max_nss = 1;
0148
0149 for (i = 0; i < max_nss && i < IWL_TLC_NSS_MAX; i++) {
0150 int nss = i + 1;
0151
0152 highest_mcs = rs_fw_vht_highest_rx_mcs_index(vht_cap, nss);
0153 if (!highest_mcs)
0154 continue;
0155
0156 supp = BIT(highest_mcs + 1) - 1;
0157 if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_20)
0158 supp &= ~BIT(IWL_TLC_MNG_HT_RATE_MCS9);
0159
0160 cmd->ht_rates[i][IWL_TLC_MCS_PER_BW_80] = cpu_to_le16(supp);
0161
0162
0163
0164
0165
0166 if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_160 &&
0167 ieee80211_get_vht_max_nss(&ieee_vht_cap,
0168 IEEE80211_VHT_CHANWIDTH_160MHZ,
0169 0, true, nss) >= nss)
0170 cmd->ht_rates[i][IWL_TLC_MCS_PER_BW_160] =
0171 cmd->ht_rates[i][IWL_TLC_MCS_PER_BW_80];
0172 }
0173 }
0174
0175 static u16 rs_fw_he_ieee80211_mcs_to_rs_mcs(u16 mcs)
0176 {
0177 switch (mcs) {
0178 case IEEE80211_HE_MCS_SUPPORT_0_7:
0179 return BIT(IWL_TLC_MNG_HT_RATE_MCS7 + 1) - 1;
0180 case IEEE80211_HE_MCS_SUPPORT_0_9:
0181 return BIT(IWL_TLC_MNG_HT_RATE_MCS9 + 1) - 1;
0182 case IEEE80211_HE_MCS_SUPPORT_0_11:
0183 return BIT(IWL_TLC_MNG_HT_RATE_MCS11 + 1) - 1;
0184 case IEEE80211_HE_MCS_NOT_SUPPORTED:
0185 return 0;
0186 }
0187
0188 WARN(1, "invalid HE MCS %d\n", mcs);
0189 return 0;
0190 }
0191
0192 static void
0193 rs_fw_he_set_enabled_rates(const struct ieee80211_sta *sta,
0194 struct ieee80211_supported_band *sband,
0195 struct iwl_tlc_config_cmd_v4 *cmd)
0196 {
0197 const struct ieee80211_sta_he_cap *he_cap = &sta->deflink.he_cap;
0198 u16 mcs_160 = le16_to_cpu(he_cap->he_mcs_nss_supp.rx_mcs_160);
0199 u16 mcs_80 = le16_to_cpu(he_cap->he_mcs_nss_supp.rx_mcs_80);
0200 u16 tx_mcs_80 =
0201 le16_to_cpu(sband->iftype_data->he_cap.he_mcs_nss_supp.tx_mcs_80);
0202 u16 tx_mcs_160 =
0203 le16_to_cpu(sband->iftype_data->he_cap.he_mcs_nss_supp.tx_mcs_160);
0204 int i;
0205 u8 nss = sta->deflink.rx_nss;
0206
0207
0208 if (sta->smps_mode == IEEE80211_SMPS_STATIC)
0209 nss = 1;
0210
0211 for (i = 0; i < nss && i < IWL_TLC_NSS_MAX; i++) {
0212 u16 _mcs_160 = (mcs_160 >> (2 * i)) & 0x3;
0213 u16 _mcs_80 = (mcs_80 >> (2 * i)) & 0x3;
0214 u16 _tx_mcs_160 = (tx_mcs_160 >> (2 * i)) & 0x3;
0215 u16 _tx_mcs_80 = (tx_mcs_80 >> (2 * i)) & 0x3;
0216
0217
0218 if (_mcs_80 == IEEE80211_HE_MCS_NOT_SUPPORTED ||
0219 _tx_mcs_80 == IEEE80211_HE_MCS_NOT_SUPPORTED) {
0220 _mcs_80 = IEEE80211_HE_MCS_NOT_SUPPORTED;
0221 _tx_mcs_80 = IEEE80211_HE_MCS_NOT_SUPPORTED;
0222 }
0223 if (_mcs_80 > _tx_mcs_80)
0224 _mcs_80 = _tx_mcs_80;
0225 cmd->ht_rates[i][IWL_TLC_MCS_PER_BW_80] =
0226 cpu_to_le16(rs_fw_he_ieee80211_mcs_to_rs_mcs(_mcs_80));
0227
0228
0229 if (_mcs_160 == IEEE80211_HE_MCS_NOT_SUPPORTED ||
0230 _tx_mcs_160 == IEEE80211_HE_MCS_NOT_SUPPORTED) {
0231 _mcs_160 = IEEE80211_HE_MCS_NOT_SUPPORTED;
0232 _tx_mcs_160 = IEEE80211_HE_MCS_NOT_SUPPORTED;
0233 }
0234 if (_mcs_160 > _tx_mcs_160)
0235 _mcs_160 = _tx_mcs_160;
0236 cmd->ht_rates[i][IWL_TLC_MCS_PER_BW_160] =
0237 cpu_to_le16(rs_fw_he_ieee80211_mcs_to_rs_mcs(_mcs_160));
0238 }
0239 }
0240
0241 static void rs_fw_set_supp_rates(struct ieee80211_sta *sta,
0242 struct ieee80211_supported_band *sband,
0243 struct iwl_tlc_config_cmd_v4 *cmd)
0244 {
0245 int i;
0246 u16 supp = 0;
0247 unsigned long tmp;
0248 const struct ieee80211_sta_ht_cap *ht_cap = &sta->deflink.ht_cap;
0249 const struct ieee80211_sta_vht_cap *vht_cap = &sta->deflink.vht_cap;
0250 const struct ieee80211_sta_he_cap *he_cap = &sta->deflink.he_cap;
0251
0252
0253 tmp = sta->deflink.supp_rates[sband->band];
0254 for_each_set_bit(i, &tmp, BITS_PER_LONG)
0255 supp |= BIT(sband->bitrates[i].hw_value);
0256
0257 cmd->non_ht_rates = cpu_to_le16(supp);
0258 cmd->mode = IWL_TLC_MNG_MODE_NON_HT;
0259
0260
0261 if (he_cap->has_he) {
0262 cmd->mode = IWL_TLC_MNG_MODE_HE;
0263 rs_fw_he_set_enabled_rates(sta, sband, cmd);
0264 } else if (vht_cap->vht_supported) {
0265 cmd->mode = IWL_TLC_MNG_MODE_VHT;
0266 rs_fw_vht_set_enabled_rates(sta, vht_cap, cmd);
0267 } else if (ht_cap->ht_supported) {
0268 cmd->mode = IWL_TLC_MNG_MODE_HT;
0269 cmd->ht_rates[IWL_TLC_NSS_1][IWL_TLC_MCS_PER_BW_80] =
0270 cpu_to_le16(ht_cap->mcs.rx_mask[0]);
0271
0272
0273 if (sta->smps_mode == IEEE80211_SMPS_STATIC)
0274 cmd->ht_rates[IWL_TLC_NSS_2][IWL_TLC_MCS_PER_BW_80] =
0275 0;
0276 else
0277 cmd->ht_rates[IWL_TLC_NSS_2][IWL_TLC_MCS_PER_BW_80] =
0278 cpu_to_le16(ht_cap->mcs.rx_mask[1]);
0279 }
0280 }
0281
0282 void iwl_mvm_tlc_update_notif(struct iwl_mvm *mvm,
0283 struct iwl_rx_cmd_buffer *rxb)
0284 {
0285 struct iwl_rx_packet *pkt = rxb_addr(rxb);
0286 struct iwl_tlc_update_notif *notif;
0287 struct ieee80211_sta *sta;
0288 struct iwl_mvm_sta *mvmsta;
0289 struct iwl_lq_sta_rs_fw *lq_sta;
0290 u32 flags;
0291
0292 rcu_read_lock();
0293
0294 notif = (void *)pkt->data;
0295 sta = rcu_dereference(mvm->fw_id_to_mac_id[notif->sta_id]);
0296 if (IS_ERR_OR_NULL(sta)) {
0297
0298
0299
0300 IWL_DEBUG_RATE(mvm,
0301 "Invalid mvm RCU pointer for sta id (%d) in TLC notification\n",
0302 notif->sta_id);
0303 goto out;
0304 }
0305
0306 mvmsta = iwl_mvm_sta_from_mac80211(sta);
0307
0308 if (!mvmsta) {
0309 IWL_ERR(mvm, "Invalid sta id (%d) in FW TLC notification\n",
0310 notif->sta_id);
0311 goto out;
0312 }
0313
0314 flags = le32_to_cpu(notif->flags);
0315
0316 lq_sta = &mvmsta->lq_sta.rs_fw;
0317
0318 if (flags & IWL_TLC_NOTIF_FLAG_RATE) {
0319 char pretty_rate[100];
0320
0321 if (iwl_fw_lookup_notif_ver(mvm->fw, DATA_PATH_GROUP,
0322 TLC_MNG_UPDATE_NOTIF, 0) < 3) {
0323 rs_pretty_print_rate_v1(pretty_rate,
0324 sizeof(pretty_rate),
0325 le32_to_cpu(notif->rate));
0326 IWL_DEBUG_RATE(mvm,
0327 "Got rate in old format. Rate: %s. Converting.\n",
0328 pretty_rate);
0329 lq_sta->last_rate_n_flags =
0330 iwl_new_rate_from_v1(le32_to_cpu(notif->rate));
0331 } else {
0332 lq_sta->last_rate_n_flags = le32_to_cpu(notif->rate);
0333 }
0334 rs_pretty_print_rate(pretty_rate, sizeof(pretty_rate),
0335 lq_sta->last_rate_n_flags);
0336 IWL_DEBUG_RATE(mvm, "new rate: %s\n", pretty_rate);
0337 }
0338
0339 if (flags & IWL_TLC_NOTIF_FLAG_AMSDU && !mvmsta->orig_amsdu_len) {
0340 u16 size = le32_to_cpu(notif->amsdu_size);
0341 int i;
0342
0343 if (sta->max_amsdu_len < size) {
0344
0345
0346
0347
0348
0349 WARN_ON(mvmsta->orig_amsdu_len < size);
0350 goto out;
0351 }
0352
0353 mvmsta->amsdu_enabled = le32_to_cpu(notif->amsdu_enabled);
0354 mvmsta->max_amsdu_len = size;
0355 sta->max_rc_amsdu_len = mvmsta->max_amsdu_len;
0356
0357 for (i = 0; i < IWL_MAX_TID_COUNT; i++) {
0358 if (mvmsta->amsdu_enabled & BIT(i))
0359 sta->max_tid_amsdu_len[i] =
0360 iwl_mvm_max_amsdu_size(mvm, sta, i);
0361 else
0362
0363
0364
0365
0366 sta->max_tid_amsdu_len[i] = 1;
0367 }
0368
0369 IWL_DEBUG_RATE(mvm,
0370 "AMSDU update. AMSDU size: %d, AMSDU selected size: %d, AMSDU TID bitmap 0x%X\n",
0371 le32_to_cpu(notif->amsdu_size), size,
0372 mvmsta->amsdu_enabled);
0373 }
0374 out:
0375 rcu_read_unlock();
0376 }
0377
0378 u16 rs_fw_get_max_amsdu_len(struct ieee80211_sta *sta)
0379 {
0380 struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
0381 const struct ieee80211_sta_vht_cap *vht_cap = &sta->deflink.vht_cap;
0382 const struct ieee80211_sta_ht_cap *ht_cap = &sta->deflink.ht_cap;
0383
0384 if (mvmsta->vif->bss_conf.chandef.chan->band == NL80211_BAND_6GHZ) {
0385 switch (le16_get_bits(sta->deflink.he_6ghz_capa.capa,
0386 IEEE80211_HE_6GHZ_CAP_MAX_MPDU_LEN)) {
0387 case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454:
0388 return IEEE80211_MAX_MPDU_LEN_VHT_11454;
0389 case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991:
0390 return IEEE80211_MAX_MPDU_LEN_VHT_7991;
0391 default:
0392 return IEEE80211_MAX_MPDU_LEN_VHT_3895;
0393 }
0394 } else
0395 if (vht_cap->vht_supported) {
0396 switch (vht_cap->cap & IEEE80211_VHT_CAP_MAX_MPDU_MASK) {
0397 case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454:
0398 return IEEE80211_MAX_MPDU_LEN_VHT_11454;
0399 case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991:
0400 return IEEE80211_MAX_MPDU_LEN_VHT_7991;
0401 default:
0402 return IEEE80211_MAX_MPDU_LEN_VHT_3895;
0403 }
0404 } else if (ht_cap->ht_supported) {
0405 if (ht_cap->cap & IEEE80211_HT_CAP_MAX_AMSDU)
0406
0407
0408
0409
0410
0411 return IEEE80211_MAX_MPDU_LEN_HT_BA;
0412 else
0413 return IEEE80211_MAX_MPDU_LEN_HT_3839;
0414 }
0415
0416
0417 return 0;
0418 }
0419
0420 void rs_fw_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
0421 enum nl80211_band band, bool update)
0422 {
0423 struct ieee80211_hw *hw = mvm->hw;
0424 struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
0425 struct iwl_lq_sta_rs_fw *lq_sta = &mvmsta->lq_sta.rs_fw;
0426 u32 cmd_id = WIDE_ID(DATA_PATH_GROUP, TLC_MNG_CONFIG_CMD);
0427 struct ieee80211_supported_band *sband = hw->wiphy->bands[band];
0428 u16 max_amsdu_len = rs_fw_get_max_amsdu_len(sta);
0429 struct iwl_tlc_config_cmd_v4 cfg_cmd = {
0430 .sta_id = mvmsta->sta_id,
0431 .max_ch_width = update ?
0432 rs_fw_bw_from_sta_bw(sta) : RATE_MCS_CHAN_WIDTH_20,
0433 .flags = cpu_to_le16(rs_fw_get_config_flags(mvm, sta, sband)),
0434 .chains = rs_fw_set_active_chains(iwl_mvm_get_valid_tx_ant(mvm)),
0435 .sgi_ch_width_supp = rs_fw_sgi_cw_support(sta),
0436 .max_mpdu_len = iwl_mvm_is_csum_supported(mvm) ?
0437 cpu_to_le16(max_amsdu_len) : 0,
0438 };
0439 int ret;
0440 int cmd_ver;
0441
0442 memset(lq_sta, 0, offsetof(typeof(*lq_sta), pers));
0443
0444 #ifdef CONFIG_IWLWIFI_DEBUGFS
0445 iwl_mvm_reset_frame_stats(mvm);
0446 #endif
0447 rs_fw_set_supp_rates(sta, sband, &cfg_cmd);
0448
0449
0450
0451
0452
0453 sta->max_amsdu_len = max_amsdu_len;
0454
0455 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw,
0456 WIDE_ID(DATA_PATH_GROUP,
0457 TLC_MNG_CONFIG_CMD),
0458 0);
0459 IWL_DEBUG_RATE(mvm, "TLC CONFIG CMD, sta_id=%d, max_ch_width=%d, mode=%d\n",
0460 cfg_cmd.sta_id, cfg_cmd.max_ch_width, cfg_cmd.mode);
0461 IWL_DEBUG_RATE(mvm, "TLC CONFIG CMD, chains=0x%X, ch_wid_supp=%d, flags=0x%X\n",
0462 cfg_cmd.chains, cfg_cmd.sgi_ch_width_supp, cfg_cmd.flags);
0463 IWL_DEBUG_RATE(mvm, "TLC CONFIG CMD, mpdu_len=%d, no_ht_rate=0x%X, tx_op=%d\n",
0464 cfg_cmd.max_mpdu_len, cfg_cmd.non_ht_rates, cfg_cmd.max_tx_op);
0465 IWL_DEBUG_RATE(mvm, "TLC CONFIG CMD, ht_rate[0][0]=0x%X, ht_rate[1][0]=0x%X\n",
0466 cfg_cmd.ht_rates[0][0], cfg_cmd.ht_rates[1][0]);
0467 IWL_DEBUG_RATE(mvm, "TLC CONFIG CMD, ht_rate[0][1]=0x%X, ht_rate[1][1]=0x%X\n",
0468 cfg_cmd.ht_rates[0][1], cfg_cmd.ht_rates[1][1]);
0469 IWL_DEBUG_RATE(mvm, "TLC CONFIG CMD, ht_rate[0][2]=0x%X, ht_rate[1][2]=0x%X\n",
0470 cfg_cmd.ht_rates[0][2], cfg_cmd.ht_rates[1][2]);
0471 if (cmd_ver == 4) {
0472 ret = iwl_mvm_send_cmd_pdu(mvm, cmd_id, CMD_ASYNC,
0473 sizeof(cfg_cmd), &cfg_cmd);
0474 } else if (cmd_ver < 4) {
0475 struct iwl_tlc_config_cmd_v3 cfg_cmd_v3 = {
0476 .sta_id = cfg_cmd.sta_id,
0477 .max_ch_width = cfg_cmd.max_ch_width,
0478 .mode = cfg_cmd.mode,
0479 .chains = cfg_cmd.chains,
0480 .amsdu = !!cfg_cmd.max_mpdu_len,
0481 .flags = cfg_cmd.flags,
0482 .non_ht_rates = cfg_cmd.non_ht_rates,
0483 .ht_rates[0][0] = cfg_cmd.ht_rates[0][0],
0484 .ht_rates[0][1] = cfg_cmd.ht_rates[0][1],
0485 .ht_rates[1][0] = cfg_cmd.ht_rates[1][0],
0486 .ht_rates[1][1] = cfg_cmd.ht_rates[1][1],
0487 .sgi_ch_width_supp = cfg_cmd.sgi_ch_width_supp,
0488 .max_mpdu_len = cfg_cmd.max_mpdu_len,
0489 };
0490
0491 u16 cmd_size = sizeof(cfg_cmd_v3);
0492
0493
0494 if (iwl_fw_lookup_cmd_ver(mvm->fw,
0495 WIDE_ID(DATA_PATH_GROUP,
0496 TLC_MNG_CONFIG_CMD), 0) < 3)
0497 cmd_size -= 4;
0498
0499 ret = iwl_mvm_send_cmd_pdu(mvm, cmd_id, CMD_ASYNC, cmd_size,
0500 &cfg_cmd_v3);
0501 } else {
0502 ret = -EINVAL;
0503 }
0504
0505 if (ret)
0506 IWL_ERR(mvm, "Failed to send rate scale config (%d)\n", ret);
0507 }
0508
0509 int rs_fw_tx_protection(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta,
0510 bool enable)
0511 {
0512
0513 IWL_DEBUG_RATE(mvm, "tx protection - not implemented yet.\n");
0514 return 0;
0515 }
0516
0517 void iwl_mvm_rs_add_sta(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta)
0518 {
0519 struct iwl_lq_sta_rs_fw *lq_sta = &mvmsta->lq_sta.rs_fw;
0520
0521 IWL_DEBUG_RATE(mvm, "create station rate scale window\n");
0522
0523 lq_sta->pers.drv = mvm;
0524 lq_sta->pers.sta_id = mvmsta->sta_id;
0525 lq_sta->pers.chains = 0;
0526 memset(lq_sta->pers.chain_signal, 0, sizeof(lq_sta->pers.chain_signal));
0527 lq_sta->pers.last_rssi = S8_MIN;
0528 lq_sta->last_rate_n_flags = 0;
0529
0530 #ifdef CONFIG_MAC80211_DEBUGFS
0531 lq_sta->pers.dbg_fixed_rate = 0;
0532 #endif
0533 }