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) 2012 - 2014 Intel Corporation. All rights reserved. 9 * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH 10 * Copyright(c) 2017 Intel Deutschland GmbH 11 * Copyright(c) 2018 - 2020 Intel Corporation 12 * 13 * This program is free software; you can redistribute it and/or modify 14 * it under the terms of version 2 of the GNU General Public License as 15 * published by the Free Software Foundation. 16 * 17 * This program is distributed in the hope that it will be useful, but 18 * WITHOUT ANY WARRANTY; without even the implied warranty of 19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 20 * General Public License for more details. 21 * 22 * The full GNU General Public License is included in this distribution 23 * in the file called COPYING. 24 * 25 * Contact Information: 26 * Intel Linux Wireless <linuxwifi@intel.com> 27 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 28 * 29 * BSD LICENSE 30 * 31 * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. 32 * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH 33 * Copyright(c) 2018 - 2020 Intel Corporation 34 * All rights reserved. 35 * 36 * Redistribution and use in source and binary forms, with or without 37 * modification, are permitted provided that the following conditions 38 * are met: 39 * 40 * * Redistributions of source code must retain the above copyright 41 * notice, this list of conditions and the following disclaimer. 42 * * Redistributions in binary form must reproduce the above copyright 43 * notice, this list of conditions and the following disclaimer in 44 * the documentation and/or other materials provided with the 45 * distribution. 46 * * Neither the name Intel Corporation nor the names of its 47 * contributors may be used to endorse or promote products derived 48 * from this software without specific prior written permission. 49 * 50 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 51 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 52 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 53 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 54 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 55 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 56 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 57 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 58 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 59 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 60 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 61 * 62 *****************************************************************************/ 63 64 #include <net/mac80211.h> 65 #include "fw-api.h" 66 #include "mvm.h" 67 68 /* Maps the driver specific channel width definition to the fw values */ 69 u8 iwl_mvm_get_channel_width(struct cfg80211_chan_def *chandef) 70 { 71 switch (chandef->width) { 72 case NL80211_CHAN_WIDTH_20_NOHT: 73 case NL80211_CHAN_WIDTH_20: 74 return PHY_VHT_CHANNEL_MODE20; 75 case NL80211_CHAN_WIDTH_40: 76 return PHY_VHT_CHANNEL_MODE40; 77 case NL80211_CHAN_WIDTH_80: 78 return PHY_VHT_CHANNEL_MODE80; 79 case NL80211_CHAN_WIDTH_160: 80 return PHY_VHT_CHANNEL_MODE160; 81 default: 82 WARN(1, "Invalid channel width=%u", chandef->width); 83 return PHY_VHT_CHANNEL_MODE20; 84 } 85 } 86 87 /* 88 * Maps the driver specific control channel position (relative to the center 89 * freq) definitions to the the fw values 90 */ 91 u8 iwl_mvm_get_ctrl_pos(struct cfg80211_chan_def *chandef) 92 { 93 switch (chandef->chan->center_freq - chandef->center_freq1) { 94 case -70: 95 return PHY_VHT_CTRL_POS_4_BELOW; 96 case -50: 97 return PHY_VHT_CTRL_POS_3_BELOW; 98 case -30: 99 return PHY_VHT_CTRL_POS_2_BELOW; 100 case -10: 101 return PHY_VHT_CTRL_POS_1_BELOW; 102 case 10: 103 return PHY_VHT_CTRL_POS_1_ABOVE; 104 case 30: 105 return PHY_VHT_CTRL_POS_2_ABOVE; 106 case 50: 107 return PHY_VHT_CTRL_POS_3_ABOVE; 108 case 70: 109 return PHY_VHT_CTRL_POS_4_ABOVE; 110 default: 111 WARN(1, "Invalid channel definition"); 112 /* fall through */ 113 case 0: 114 /* 115 * The FW is expected to check the control channel position only 116 * when in HT/VHT and the channel width is not 20MHz. Return 117 * this value as the default one. 118 */ 119 return PHY_VHT_CTRL_POS_1_BELOW; 120 } 121 } 122 123 /* 124 * Construct the generic fields of the PHY context command 125 */ 126 static void iwl_mvm_phy_ctxt_cmd_hdr(struct iwl_mvm_phy_ctxt *ctxt, 127 struct iwl_phy_context_cmd *cmd, 128 u32 action) 129 { 130 cmd->id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(ctxt->id, 131 ctxt->color)); 132 cmd->action = cpu_to_le32(action); 133 } 134 135 static void iwl_mvm_phy_ctxt_set_rxchain(struct iwl_mvm *mvm, 136 __le32 *rxchain_info, 137 u8 chains_static, 138 u8 chains_dynamic) 139 { 140 u8 active_cnt, idle_cnt; 141 142 /* Set rx the chains */ 143 idle_cnt = chains_static; 144 active_cnt = chains_dynamic; 145 146 /* In scenarios where we only ever use a single-stream rates, 147 * i.e. legacy 11b/g/a associations, single-stream APs or even 148 * static SMPS, enable both chains to get diversity, improving 149 * the case where we're far enough from the AP that attenuation 150 * between the two antennas is sufficiently different to impact 151 * performance. 152 */ 153 if (active_cnt == 1 && iwl_mvm_rx_diversity_allowed(mvm)) { 154 idle_cnt = 2; 155 active_cnt = 2; 156 } 157 158 *rxchain_info = cpu_to_le32(iwl_mvm_get_valid_rx_ant(mvm) << 159 PHY_RX_CHAIN_VALID_POS); 160 *rxchain_info |= cpu_to_le32(idle_cnt << PHY_RX_CHAIN_CNT_POS); 161 *rxchain_info |= cpu_to_le32(active_cnt << 162 PHY_RX_CHAIN_MIMO_CNT_POS); 163 #ifdef CONFIG_IWLWIFI_DEBUGFS 164 if (unlikely(mvm->dbgfs_rx_phyinfo)) 165 *rxchain_info = cpu_to_le32(mvm->dbgfs_rx_phyinfo); 166 #endif 167 } 168 169 /* 170 * Add the phy configuration to the PHY context command 171 */ 172 static void iwl_mvm_phy_ctxt_cmd_data_v1(struct iwl_mvm *mvm, 173 struct iwl_phy_context_cmd_v1 *cmd, 174 struct cfg80211_chan_def *chandef, 175 u8 chains_static, u8 chains_dynamic) 176 { 177 struct iwl_phy_context_cmd_tail *tail = 178 iwl_mvm_chan_info_cmd_tail(mvm, &cmd->ci); 179 180 /* Set the channel info data */ 181 iwl_mvm_set_chan_info_chandef(mvm, &cmd->ci, chandef); 182 183 iwl_mvm_phy_ctxt_set_rxchain(mvm, &tail->rxchain_info, 184 chains_static, chains_dynamic); 185 186 tail->txchain_info = cpu_to_le32(iwl_mvm_get_valid_tx_ant(mvm)); 187 } 188 189 /* 190 * Add the phy configuration to the PHY context command 191 */ 192 static void iwl_mvm_phy_ctxt_cmd_data(struct iwl_mvm *mvm, 193 struct iwl_phy_context_cmd *cmd, 194 struct cfg80211_chan_def *chandef, 195 u8 chains_static, u8 chains_dynamic) 196 { 197 cmd->lmac_id = cpu_to_le32(iwl_mvm_get_lmac_id(mvm->fw, 198 chandef->chan->band)); 199 200 /* Set the channel info data */ 201 iwl_mvm_set_chan_info_chandef(mvm, &cmd->ci, chandef); 202 203 iwl_mvm_phy_ctxt_set_rxchain(mvm, &cmd->rxchain_info, 204 chains_static, chains_dynamic); 205 } 206 207 /* 208 * Send a command to apply the current phy configuration. The command is send 209 * only if something in the configuration changed: in case that this is the 210 * first time that the phy configuration is applied or in case that the phy 211 * configuration changed from the previous apply. 212 */ 213 static int iwl_mvm_phy_ctxt_apply(struct iwl_mvm *mvm, 214 struct iwl_mvm_phy_ctxt *ctxt, 215 struct cfg80211_chan_def *chandef, 216 u8 chains_static, u8 chains_dynamic, 217 u32 action) 218 { 219 int ret; 220 int ver = iwl_fw_lookup_cmd_ver(mvm->fw, IWL_ALWAYS_LONG_GROUP, 221 PHY_CONTEXT_CMD, 1); 222 223 if (ver == 3) { 224 struct iwl_phy_context_cmd cmd = {}; 225 226 /* Set the command header fields */ 227 iwl_mvm_phy_ctxt_cmd_hdr(ctxt, &cmd, action); 228 229 /* Set the command data */ 230 iwl_mvm_phy_ctxt_cmd_data(mvm, &cmd, chandef, 231 chains_static, 232 chains_dynamic); 233 234 ret = iwl_mvm_send_cmd_pdu(mvm, PHY_CONTEXT_CMD, 235 0, sizeof(cmd), &cmd); 236 } else if (ver < 3) { 237 struct iwl_phy_context_cmd_v1 cmd = {}; 238 u16 len = sizeof(cmd) - iwl_mvm_chan_info_padding(mvm); 239 240 /* Set the command header fields */ 241 iwl_mvm_phy_ctxt_cmd_hdr(ctxt, 242 (struct iwl_phy_context_cmd *)&cmd, 243 action); 244 245 /* Set the command data */ 246 iwl_mvm_phy_ctxt_cmd_data_v1(mvm, &cmd, chandef, 247 chains_static, 248 chains_dynamic); 249 ret = iwl_mvm_send_cmd_pdu(mvm, PHY_CONTEXT_CMD, 250 0, len, &cmd); 251 } else { 252 IWL_ERR(mvm, "PHY ctxt cmd error ver %d not supported\n", ver); 253 return -EOPNOTSUPP; 254 } 255 256 257 if (ret) 258 IWL_ERR(mvm, "PHY ctxt cmd error. ret=%d\n", ret); 259 return ret; 260 } 261 262 /* 263 * Send a command to add a PHY context based on the current HW configuration. 264 */ 265 int iwl_mvm_phy_ctxt_add(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt, 266 struct cfg80211_chan_def *chandef, 267 u8 chains_static, u8 chains_dynamic) 268 { 269 WARN_ON(!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) && 270 ctxt->ref); 271 lockdep_assert_held(&mvm->mutex); 272 273 ctxt->channel = chandef->chan; 274 275 return iwl_mvm_phy_ctxt_apply(mvm, ctxt, chandef, 276 chains_static, chains_dynamic, 277 FW_CTXT_ACTION_ADD); 278 } 279 280 /* 281 * Update the number of references to the given PHY context. This is valid only 282 * in case the PHY context was already created, i.e., its reference count > 0. 283 */ 284 void iwl_mvm_phy_ctxt_ref(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt) 285 { 286 lockdep_assert_held(&mvm->mutex); 287 ctxt->ref++; 288 } 289 290 /* 291 * Send a command to modify the PHY context based on the current HW 292 * configuration. Note that the function does not check that the configuration 293 * changed. 294 */ 295 int iwl_mvm_phy_ctxt_changed(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt, 296 struct cfg80211_chan_def *chandef, 297 u8 chains_static, u8 chains_dynamic) 298 { 299 enum iwl_ctxt_action action = FW_CTXT_ACTION_MODIFY; 300 301 lockdep_assert_held(&mvm->mutex); 302 303 if (fw_has_capa(&mvm->fw->ucode_capa, 304 IWL_UCODE_TLV_CAPA_BINDING_CDB_SUPPORT) && 305 ctxt->channel->band != chandef->chan->band) { 306 int ret; 307 308 /* ... remove it here ...*/ 309 ret = iwl_mvm_phy_ctxt_apply(mvm, ctxt, chandef, 310 chains_static, chains_dynamic, 311 FW_CTXT_ACTION_REMOVE); 312 if (ret) 313 return ret; 314 315 /* ... and proceed to add it again */ 316 action = FW_CTXT_ACTION_ADD; 317 } 318 319 ctxt->channel = chandef->chan; 320 ctxt->width = chandef->width; 321 return iwl_mvm_phy_ctxt_apply(mvm, ctxt, chandef, 322 chains_static, chains_dynamic, 323 action); 324 } 325 326 void iwl_mvm_phy_ctxt_unref(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt) 327 { 328 lockdep_assert_held(&mvm->mutex); 329 330 if (WARN_ON_ONCE(!ctxt)) 331 return; 332 333 ctxt->ref--; 334 335 /* 336 * Move unused phy's to a default channel. When the phy is moved the, 337 * fw will cleanup immediate quiet bit if it was previously set, 338 * otherwise we might not be able to reuse this phy. 339 */ 340 if (ctxt->ref == 0) { 341 struct ieee80211_channel *chan; 342 struct cfg80211_chan_def chandef; 343 struct ieee80211_supported_band *sband = NULL; 344 enum nl80211_band band = NL80211_BAND_2GHZ; 345 346 while (!sband && band < NUM_NL80211_BANDS) 347 sband = mvm->hw->wiphy->bands[band++]; 348 349 if (WARN_ON(!sband)) 350 return; 351 352 chan = &sband->channels[0]; 353 354 cfg80211_chandef_create(&chandef, chan, NL80211_CHAN_NO_HT); 355 iwl_mvm_phy_ctxt_changed(mvm, ctxt, &chandef, 1, 1); 356 } 357 } 358 359 static void iwl_mvm_binding_iterator(void *_data, u8 *mac, 360 struct ieee80211_vif *vif) 361 { 362 unsigned long *data = _data; 363 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 364 365 if (!mvmvif->phy_ctxt) 366 return; 367 368 if (vif->type == NL80211_IFTYPE_STATION || 369 vif->type == NL80211_IFTYPE_AP) 370 __set_bit(mvmvif->phy_ctxt->id, data); 371 } 372 373 int iwl_mvm_phy_ctx_count(struct iwl_mvm *mvm) 374 { 375 unsigned long phy_ctxt_counter = 0; 376 377 ieee80211_iterate_active_interfaces_atomic(mvm->hw, 378 IEEE80211_IFACE_ITER_NORMAL, 379 iwl_mvm_binding_iterator, 380 &phy_ctxt_counter); 381 382 return hweight8(phy_ctxt_counter); 383 } 384