1 /****************************************************************************** 2 * 3 * This file is provided under a dual BSD/GPLv2 license. When using or 4 * redistributing this file, you may do so under either license. 5 * 6 * GPL LICENSE SUMMARY 7 * 8 * Copyright(c) 2017 Intel Deutschland GmbH 9 * 10 * This program is free software; you can redistribute it and/or modify 11 * it under the terms of version 2 of the GNU General Public License as 12 * published by the Free Software Foundation. 13 * 14 * This program is distributed in the hope that it will be useful, but 15 * WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 * General Public License for more details. 18 * 19 * The full GNU General Public License is included in this distribution 20 * in the file called COPYING. 21 * 22 * Contact Information: 23 * Intel Linux Wireless <linuxwifi@intel.com> 24 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 25 * 26 * BSD LICENSE 27 * 28 * Copyright(c) 2017 Intel Deutschland GmbH 29 * All rights reserved. 30 * 31 * Redistribution and use in source and binary forms, with or without 32 * modification, are permitted provided that the following conditions 33 * are met: 34 * 35 * * Redistributions of source code must retain the above copyright 36 * notice, this list of conditions and the following disclaimer. 37 * * Redistributions in binary form must reproduce the above copyright 38 * notice, this list of conditions and the following disclaimer in 39 * the documentation and/or other materials provided with the 40 * distribution. 41 * * Neither the name Intel Corporation nor the names of its 42 * contributors may be used to endorse or promote products derived 43 * from this software without specific prior written permission. 44 * 45 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 46 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 47 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 48 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 49 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 50 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 51 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 52 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 53 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 54 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 55 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 56 * 57 *****************************************************************************/ 58 #include "rs.h" 59 #include "fw-api.h" 60 #include "sta.h" 61 #include "iwl-op-mode.h" 62 #include "mvm.h" 63 64 static u8 rs_fw_bw_from_sta_bw(struct ieee80211_sta *sta) 65 { 66 switch (sta->bandwidth) { 67 case IEEE80211_STA_RX_BW_160: 68 return IWL_TLC_MNG_MAX_CH_WIDTH_160MHZ; 69 case IEEE80211_STA_RX_BW_80: 70 return IWL_TLC_MNG_MAX_CH_WIDTH_80MHZ; 71 case IEEE80211_STA_RX_BW_40: 72 return IWL_TLC_MNG_MAX_CH_WIDTH_40MHZ; 73 case IEEE80211_STA_RX_BW_20: 74 default: 75 return IWL_TLC_MNG_MAX_CH_WIDTH_20MHZ; 76 } 77 } 78 79 static u8 rs_fw_set_active_chains(u8 chains) 80 { 81 u8 fw_chains = 0; 82 83 if (chains & ANT_A) 84 fw_chains |= IWL_TLC_MNG_CHAIN_A_MSK; 85 if (chains & ANT_B) 86 fw_chains |= IWL_TLC_MNG_CHAIN_B_MSK; 87 if (chains & ANT_C) 88 fw_chains |= IWL_TLC_MNG_CHAIN_C_MSK; 89 90 return fw_chains; 91 } 92 93 static u8 rs_fw_sgi_cw_support(struct ieee80211_sta *sta) 94 { 95 struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap; 96 struct ieee80211_sta_vht_cap *vht_cap = &sta->vht_cap; 97 u8 supp = 0; 98 99 if (ht_cap->cap & IEEE80211_HT_CAP_SGI_20) 100 supp |= IWL_TLC_MNG_SGI_20MHZ_MSK; 101 if (ht_cap->cap & IEEE80211_HT_CAP_SGI_40) 102 supp |= IWL_TLC_MNG_SGI_40MHZ_MSK; 103 if (vht_cap->cap & IEEE80211_VHT_CAP_SHORT_GI_80) 104 supp |= IWL_TLC_MNG_SGI_80MHZ_MSK; 105 if (vht_cap->cap & IEEE80211_VHT_CAP_SHORT_GI_160) 106 supp |= IWL_TLC_MNG_SGI_160MHZ_MSK; 107 108 return supp; 109 } 110 111 static u16 rs_fw_set_config_flags(struct iwl_mvm *mvm, 112 struct ieee80211_sta *sta) 113 { 114 struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap; 115 struct ieee80211_sta_vht_cap *vht_cap = &sta->vht_cap; 116 bool vht_ena = vht_cap && vht_cap->vht_supported; 117 u16 flags = IWL_TLC_MNG_CFG_FLAGS_CCK_MSK | 118 IWL_TLC_MNG_CFG_FLAGS_DCM_MSK | 119 IWL_TLC_MNG_CFG_FLAGS_DD_MSK; 120 121 if (mvm->cfg->ht_params->stbc && 122 (num_of_ant(iwl_mvm_get_valid_tx_ant(mvm)) > 1) && 123 ((ht_cap && (ht_cap->cap & IEEE80211_HT_CAP_RX_STBC)) || 124 (vht_ena && (vht_cap->cap & IEEE80211_VHT_CAP_RXSTBC_MASK)))) 125 flags |= IWL_TLC_MNG_CFG_FLAGS_STBC_MSK; 126 127 if (mvm->cfg->ht_params->ldpc && 128 ((ht_cap && (ht_cap->cap & IEEE80211_HT_CAP_LDPC_CODING)) || 129 (vht_ena && (vht_cap->cap & IEEE80211_VHT_CAP_RXLDPC)))) 130 flags |= IWL_TLC_MNG_CFG_FLAGS_LDPC_MSK; 131 132 if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_BEAMFORMER) && 133 (num_of_ant(iwl_mvm_get_valid_tx_ant(mvm)) > 1) && 134 (vht_cap->cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE)) 135 flags |= IWL_TLC_MNG_CFG_FLAGS_BF_MSK; 136 137 return flags; 138 } 139 140 static 141 int rs_fw_vht_highest_rx_mcs_index(struct ieee80211_sta_vht_cap *vht_cap, 142 int nss) 143 { 144 u16 rx_mcs = le16_to_cpu(vht_cap->vht_mcs.rx_mcs_map) & 145 (0x3 << (2 * (nss - 1))); 146 rx_mcs >>= (2 * (nss - 1)); 147 148 switch (rx_mcs) { 149 case IEEE80211_VHT_MCS_SUPPORT_0_7: 150 return IWL_TLC_MNG_HT_RATE_MCS7; 151 case IEEE80211_VHT_MCS_SUPPORT_0_8: 152 return IWL_TLC_MNG_HT_RATE_MCS8; 153 case IEEE80211_VHT_MCS_SUPPORT_0_9: 154 return IWL_TLC_MNG_HT_RATE_MCS9; 155 default: 156 WARN_ON_ONCE(1); 157 break; 158 } 159 160 return 0; 161 } 162 163 static void rs_fw_vht_set_enabled_rates(struct ieee80211_sta *sta, 164 struct ieee80211_sta_vht_cap *vht_cap, 165 struct iwl_tlc_config_cmd *cmd) 166 { 167 u16 supp; 168 int i, highest_mcs; 169 170 for (i = 0; i < sta->rx_nss; i++) { 171 if (i == MAX_RS_ANT_NUM) 172 break; 173 174 highest_mcs = rs_fw_vht_highest_rx_mcs_index(vht_cap, i + 1); 175 if (!highest_mcs) 176 continue; 177 178 supp = BIT(highest_mcs + 1) - 1; 179 if (sta->bandwidth == IEEE80211_STA_RX_BW_20) 180 supp &= ~BIT(IWL_TLC_MNG_HT_RATE_MCS9); 181 182 cmd->ht_supp_rates[i] = cpu_to_le16(supp); 183 } 184 } 185 186 static void rs_fw_set_supp_rates(struct ieee80211_sta *sta, 187 struct ieee80211_supported_band *sband, 188 struct iwl_tlc_config_cmd *cmd) 189 { 190 int i; 191 unsigned long tmp; 192 unsigned long supp; /* must be unsigned long for for_each_set_bit */ 193 struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap; 194 struct ieee80211_sta_vht_cap *vht_cap = &sta->vht_cap; 195 196 /* non HT rates */ 197 supp = 0; 198 tmp = sta->supp_rates[sband->band]; 199 for_each_set_bit(i, &tmp, BITS_PER_LONG) 200 supp |= BIT(sband->bitrates[i].hw_value); 201 202 cmd->non_ht_supp_rates = cpu_to_le16(supp); 203 cmd->mode = IWL_TLC_MNG_MODE_NON_HT; 204 205 /* HT/VHT rates */ 206 if (vht_cap && vht_cap->vht_supported) { 207 cmd->mode = IWL_TLC_MNG_MODE_VHT; 208 rs_fw_vht_set_enabled_rates(sta, vht_cap, cmd); 209 } else if (ht_cap && ht_cap->ht_supported) { 210 cmd->mode = IWL_TLC_MNG_MODE_HT; 211 cmd->ht_supp_rates[0] = cpu_to_le16(ht_cap->mcs.rx_mask[0]); 212 cmd->ht_supp_rates[1] = cpu_to_le16(ht_cap->mcs.rx_mask[1]); 213 } 214 } 215 216 static void rs_fw_tlc_mng_notif_req_config(struct iwl_mvm *mvm, u8 sta_id) 217 { 218 u32 cmd_id = iwl_cmd_id(TLC_MNG_NOTIF_REQ_CMD, DATA_PATH_GROUP, 0); 219 struct iwl_tlc_notif_req_config_cmd cfg_cmd = { 220 .sta_id = sta_id, 221 .flags = cpu_to_le16(IWL_TLC_NOTIF_INIT_RATE_MSK), 222 .interval = cpu_to_le16(IWL_TLC_NOTIF_REQ_INTERVAL), 223 }; 224 int ret; 225 226 ret = iwl_mvm_send_cmd_pdu(mvm, cmd_id, 0, sizeof(cfg_cmd), &cfg_cmd); 227 if (ret) 228 IWL_ERR(mvm, "Failed to send TLC notif request (%d)\n", ret); 229 } 230 231 void iwl_mvm_tlc_update_notif(struct iwl_mvm *mvm, struct iwl_rx_packet *pkt) 232 { 233 struct iwl_tlc_update_notif *notif; 234 struct iwl_mvm_sta *mvmsta; 235 struct iwl_lq_sta_rs_fw *lq_sta; 236 237 rcu_read_lock(); 238 239 notif = (void *)pkt->data; 240 mvmsta = iwl_mvm_sta_from_staid_rcu(mvm, notif->sta_id); 241 242 if (!mvmsta) { 243 IWL_ERR(mvm, "Invalid sta id (%d) in FW TLC notification\n", 244 notif->sta_id); 245 goto out; 246 } 247 248 lq_sta = &mvmsta->lq_sta.rs_fw; 249 250 if (le16_to_cpu(notif->flags) & IWL_TLC_NOTIF_INIT_RATE_MSK) { 251 lq_sta->last_rate_n_flags = 252 le32_to_cpu(notif->values[IWL_TLC_NOTIF_INIT_RATE_POS]); 253 IWL_DEBUG_RATE(mvm, "new rate_n_flags: 0x%X\n", 254 lq_sta->last_rate_n_flags); 255 } 256 out: 257 rcu_read_unlock(); 258 } 259 260 void rs_fw_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, 261 enum nl80211_band band) 262 { 263 struct ieee80211_hw *hw = mvm->hw; 264 struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); 265 struct iwl_lq_sta_rs_fw *lq_sta = &mvmsta->lq_sta.rs_fw; 266 u32 cmd_id = iwl_cmd_id(TLC_MNG_CONFIG_CMD, DATA_PATH_GROUP, 0); 267 struct ieee80211_supported_band *sband; 268 struct iwl_tlc_config_cmd cfg_cmd = { 269 .sta_id = mvmsta->sta_id, 270 .max_supp_ch_width = rs_fw_bw_from_sta_bw(sta), 271 .flags = cpu_to_le16(rs_fw_set_config_flags(mvm, sta)), 272 .chains = rs_fw_set_active_chains(iwl_mvm_get_valid_tx_ant(mvm)), 273 .max_supp_ss = sta->rx_nss, 274 .max_ampdu_cnt = cpu_to_le32(mvmsta->max_agg_bufsize), 275 .sgi_ch_width_supp = rs_fw_sgi_cw_support(sta), 276 }; 277 int ret; 278 279 memset(lq_sta, 0, offsetof(typeof(*lq_sta), pers)); 280 281 #ifdef CONFIG_IWLWIFI_DEBUGFS 282 iwl_mvm_reset_frame_stats(mvm); 283 #endif 284 sband = hw->wiphy->bands[band]; 285 rs_fw_set_supp_rates(sta, sband, &cfg_cmd); 286 287 ret = iwl_mvm_send_cmd_pdu(mvm, cmd_id, 0, sizeof(cfg_cmd), &cfg_cmd); 288 if (ret) 289 IWL_ERR(mvm, "Failed to send rate scale config (%d)\n", ret); 290 291 rs_fw_tlc_mng_notif_req_config(mvm, cfg_cmd.sta_id); 292 } 293 294 int rs_fw_tx_protection(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta, 295 bool enable) 296 { 297 /* TODO: need to introduce a new FW cmd since LQ cmd is not relevant */ 298 IWL_DEBUG_RATE(mvm, "tx protection - not implemented yet.\n"); 299 return 0; 300 } 301 302 void iwl_mvm_rs_add_sta(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta) 303 { 304 struct iwl_lq_sta_rs_fw *lq_sta = &mvmsta->lq_sta.rs_fw; 305 306 IWL_DEBUG_RATE(mvm, "create station rate scale window\n"); 307 308 lq_sta->pers.drv = mvm; 309 lq_sta->pers.sta_id = mvmsta->sta_id; 310 lq_sta->pers.chains = 0; 311 memset(lq_sta->pers.chain_signal, 0, sizeof(lq_sta->pers.chain_signal)); 312 lq_sta->pers.last_rssi = S8_MIN; 313 lq_sta->last_rate_n_flags = 0; 314 315 #ifdef CONFIG_MAC80211_DEBUGFS 316 lq_sta->pers.dbg_fixed_rate = 0; 317 #endif 318 } 319