18c2ecf20Sopenharmony_ci/****************************************************************************** 28c2ecf20Sopenharmony_ci * 38c2ecf20Sopenharmony_ci * This file is provided under a dual BSD/GPLv2 license. When using or 48c2ecf20Sopenharmony_ci * redistributing this file, you may do so under either license. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * GPL LICENSE SUMMARY 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. 98c2ecf20Sopenharmony_ci * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH 108c2ecf20Sopenharmony_ci * Copyright(c) 2017 Intel Deutschland GmbH 118c2ecf20Sopenharmony_ci * Copyright(c) 2018 - 2020 Intel Corporation 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or modify 148c2ecf20Sopenharmony_ci * it under the terms of version 2 of the GNU General Public License as 158c2ecf20Sopenharmony_ci * published by the Free Software Foundation. 168c2ecf20Sopenharmony_ci * 178c2ecf20Sopenharmony_ci * This program is distributed in the hope that it will be useful, but 188c2ecf20Sopenharmony_ci * WITHOUT ANY WARRANTY; without even the implied warranty of 198c2ecf20Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 208c2ecf20Sopenharmony_ci * General Public License for more details. 218c2ecf20Sopenharmony_ci * 228c2ecf20Sopenharmony_ci * The full GNU General Public License is included in this distribution 238c2ecf20Sopenharmony_ci * in the file called COPYING. 248c2ecf20Sopenharmony_ci * 258c2ecf20Sopenharmony_ci * Contact Information: 268c2ecf20Sopenharmony_ci * Intel Linux Wireless <linuxwifi@intel.com> 278c2ecf20Sopenharmony_ci * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 288c2ecf20Sopenharmony_ci * 298c2ecf20Sopenharmony_ci * BSD LICENSE 308c2ecf20Sopenharmony_ci * 318c2ecf20Sopenharmony_ci * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. 328c2ecf20Sopenharmony_ci * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH 338c2ecf20Sopenharmony_ci * Copyright(c) 2018 - 2020 Intel Corporation 348c2ecf20Sopenharmony_ci * All rights reserved. 358c2ecf20Sopenharmony_ci * 368c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or without 378c2ecf20Sopenharmony_ci * modification, are permitted provided that the following conditions 388c2ecf20Sopenharmony_ci * are met: 398c2ecf20Sopenharmony_ci * 408c2ecf20Sopenharmony_ci * * Redistributions of source code must retain the above copyright 418c2ecf20Sopenharmony_ci * notice, this list of conditions and the following disclaimer. 428c2ecf20Sopenharmony_ci * * Redistributions in binary form must reproduce the above copyright 438c2ecf20Sopenharmony_ci * notice, this list of conditions and the following disclaimer in 448c2ecf20Sopenharmony_ci * the documentation and/or other materials provided with the 458c2ecf20Sopenharmony_ci * distribution. 468c2ecf20Sopenharmony_ci * * Neither the name Intel Corporation nor the names of its 478c2ecf20Sopenharmony_ci * contributors may be used to endorse or promote products derived 488c2ecf20Sopenharmony_ci * from this software without specific prior written permission. 498c2ecf20Sopenharmony_ci * 508c2ecf20Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 518c2ecf20Sopenharmony_ci * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 528c2ecf20Sopenharmony_ci * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 538c2ecf20Sopenharmony_ci * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 548c2ecf20Sopenharmony_ci * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 558c2ecf20Sopenharmony_ci * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 568c2ecf20Sopenharmony_ci * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 578c2ecf20Sopenharmony_ci * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 588c2ecf20Sopenharmony_ci * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 598c2ecf20Sopenharmony_ci * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 608c2ecf20Sopenharmony_ci * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 618c2ecf20Sopenharmony_ci * 628c2ecf20Sopenharmony_ci *****************************************************************************/ 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci#include <net/mac80211.h> 658c2ecf20Sopenharmony_ci#include "fw-api.h" 668c2ecf20Sopenharmony_ci#include "mvm.h" 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci/* Maps the driver specific channel width definition to the fw values */ 698c2ecf20Sopenharmony_ciu8 iwl_mvm_get_channel_width(struct cfg80211_chan_def *chandef) 708c2ecf20Sopenharmony_ci{ 718c2ecf20Sopenharmony_ci switch (chandef->width) { 728c2ecf20Sopenharmony_ci case NL80211_CHAN_WIDTH_20_NOHT: 738c2ecf20Sopenharmony_ci case NL80211_CHAN_WIDTH_20: 748c2ecf20Sopenharmony_ci return PHY_VHT_CHANNEL_MODE20; 758c2ecf20Sopenharmony_ci case NL80211_CHAN_WIDTH_40: 768c2ecf20Sopenharmony_ci return PHY_VHT_CHANNEL_MODE40; 778c2ecf20Sopenharmony_ci case NL80211_CHAN_WIDTH_80: 788c2ecf20Sopenharmony_ci return PHY_VHT_CHANNEL_MODE80; 798c2ecf20Sopenharmony_ci case NL80211_CHAN_WIDTH_160: 808c2ecf20Sopenharmony_ci return PHY_VHT_CHANNEL_MODE160; 818c2ecf20Sopenharmony_ci default: 828c2ecf20Sopenharmony_ci WARN(1, "Invalid channel width=%u", chandef->width); 838c2ecf20Sopenharmony_ci return PHY_VHT_CHANNEL_MODE20; 848c2ecf20Sopenharmony_ci } 858c2ecf20Sopenharmony_ci} 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci/* 888c2ecf20Sopenharmony_ci * Maps the driver specific control channel position (relative to the center 898c2ecf20Sopenharmony_ci * freq) definitions to the the fw values 908c2ecf20Sopenharmony_ci */ 918c2ecf20Sopenharmony_ciu8 iwl_mvm_get_ctrl_pos(struct cfg80211_chan_def *chandef) 928c2ecf20Sopenharmony_ci{ 938c2ecf20Sopenharmony_ci switch (chandef->chan->center_freq - chandef->center_freq1) { 948c2ecf20Sopenharmony_ci case -70: 958c2ecf20Sopenharmony_ci return PHY_VHT_CTRL_POS_4_BELOW; 968c2ecf20Sopenharmony_ci case -50: 978c2ecf20Sopenharmony_ci return PHY_VHT_CTRL_POS_3_BELOW; 988c2ecf20Sopenharmony_ci case -30: 998c2ecf20Sopenharmony_ci return PHY_VHT_CTRL_POS_2_BELOW; 1008c2ecf20Sopenharmony_ci case -10: 1018c2ecf20Sopenharmony_ci return PHY_VHT_CTRL_POS_1_BELOW; 1028c2ecf20Sopenharmony_ci case 10: 1038c2ecf20Sopenharmony_ci return PHY_VHT_CTRL_POS_1_ABOVE; 1048c2ecf20Sopenharmony_ci case 30: 1058c2ecf20Sopenharmony_ci return PHY_VHT_CTRL_POS_2_ABOVE; 1068c2ecf20Sopenharmony_ci case 50: 1078c2ecf20Sopenharmony_ci return PHY_VHT_CTRL_POS_3_ABOVE; 1088c2ecf20Sopenharmony_ci case 70: 1098c2ecf20Sopenharmony_ci return PHY_VHT_CTRL_POS_4_ABOVE; 1108c2ecf20Sopenharmony_ci default: 1118c2ecf20Sopenharmony_ci WARN(1, "Invalid channel definition"); 1128c2ecf20Sopenharmony_ci /* fall through */ 1138c2ecf20Sopenharmony_ci case 0: 1148c2ecf20Sopenharmony_ci /* 1158c2ecf20Sopenharmony_ci * The FW is expected to check the control channel position only 1168c2ecf20Sopenharmony_ci * when in HT/VHT and the channel width is not 20MHz. Return 1178c2ecf20Sopenharmony_ci * this value as the default one. 1188c2ecf20Sopenharmony_ci */ 1198c2ecf20Sopenharmony_ci return PHY_VHT_CTRL_POS_1_BELOW; 1208c2ecf20Sopenharmony_ci } 1218c2ecf20Sopenharmony_ci} 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci/* 1248c2ecf20Sopenharmony_ci * Construct the generic fields of the PHY context command 1258c2ecf20Sopenharmony_ci */ 1268c2ecf20Sopenharmony_cistatic void iwl_mvm_phy_ctxt_cmd_hdr(struct iwl_mvm_phy_ctxt *ctxt, 1278c2ecf20Sopenharmony_ci struct iwl_phy_context_cmd *cmd, 1288c2ecf20Sopenharmony_ci u32 action) 1298c2ecf20Sopenharmony_ci{ 1308c2ecf20Sopenharmony_ci cmd->id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(ctxt->id, 1318c2ecf20Sopenharmony_ci ctxt->color)); 1328c2ecf20Sopenharmony_ci cmd->action = cpu_to_le32(action); 1338c2ecf20Sopenharmony_ci} 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_cistatic void iwl_mvm_phy_ctxt_set_rxchain(struct iwl_mvm *mvm, 1368c2ecf20Sopenharmony_ci __le32 *rxchain_info, 1378c2ecf20Sopenharmony_ci u8 chains_static, 1388c2ecf20Sopenharmony_ci u8 chains_dynamic) 1398c2ecf20Sopenharmony_ci{ 1408c2ecf20Sopenharmony_ci u8 active_cnt, idle_cnt; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci /* Set rx the chains */ 1438c2ecf20Sopenharmony_ci idle_cnt = chains_static; 1448c2ecf20Sopenharmony_ci active_cnt = chains_dynamic; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci /* In scenarios where we only ever use a single-stream rates, 1478c2ecf20Sopenharmony_ci * i.e. legacy 11b/g/a associations, single-stream APs or even 1488c2ecf20Sopenharmony_ci * static SMPS, enable both chains to get diversity, improving 1498c2ecf20Sopenharmony_ci * the case where we're far enough from the AP that attenuation 1508c2ecf20Sopenharmony_ci * between the two antennas is sufficiently different to impact 1518c2ecf20Sopenharmony_ci * performance. 1528c2ecf20Sopenharmony_ci */ 1538c2ecf20Sopenharmony_ci if (active_cnt == 1 && iwl_mvm_rx_diversity_allowed(mvm)) { 1548c2ecf20Sopenharmony_ci idle_cnt = 2; 1558c2ecf20Sopenharmony_ci active_cnt = 2; 1568c2ecf20Sopenharmony_ci } 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci *rxchain_info = cpu_to_le32(iwl_mvm_get_valid_rx_ant(mvm) << 1598c2ecf20Sopenharmony_ci PHY_RX_CHAIN_VALID_POS); 1608c2ecf20Sopenharmony_ci *rxchain_info |= cpu_to_le32(idle_cnt << PHY_RX_CHAIN_CNT_POS); 1618c2ecf20Sopenharmony_ci *rxchain_info |= cpu_to_le32(active_cnt << 1628c2ecf20Sopenharmony_ci PHY_RX_CHAIN_MIMO_CNT_POS); 1638c2ecf20Sopenharmony_ci#ifdef CONFIG_IWLWIFI_DEBUGFS 1648c2ecf20Sopenharmony_ci if (unlikely(mvm->dbgfs_rx_phyinfo)) 1658c2ecf20Sopenharmony_ci *rxchain_info = cpu_to_le32(mvm->dbgfs_rx_phyinfo); 1668c2ecf20Sopenharmony_ci#endif 1678c2ecf20Sopenharmony_ci} 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci/* 1708c2ecf20Sopenharmony_ci * Add the phy configuration to the PHY context command 1718c2ecf20Sopenharmony_ci */ 1728c2ecf20Sopenharmony_cistatic void iwl_mvm_phy_ctxt_cmd_data_v1(struct iwl_mvm *mvm, 1738c2ecf20Sopenharmony_ci struct iwl_phy_context_cmd_v1 *cmd, 1748c2ecf20Sopenharmony_ci struct cfg80211_chan_def *chandef, 1758c2ecf20Sopenharmony_ci u8 chains_static, u8 chains_dynamic) 1768c2ecf20Sopenharmony_ci{ 1778c2ecf20Sopenharmony_ci struct iwl_phy_context_cmd_tail *tail = 1788c2ecf20Sopenharmony_ci iwl_mvm_chan_info_cmd_tail(mvm, &cmd->ci); 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci /* Set the channel info data */ 1818c2ecf20Sopenharmony_ci iwl_mvm_set_chan_info_chandef(mvm, &cmd->ci, chandef); 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci iwl_mvm_phy_ctxt_set_rxchain(mvm, &tail->rxchain_info, 1848c2ecf20Sopenharmony_ci chains_static, chains_dynamic); 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci tail->txchain_info = cpu_to_le32(iwl_mvm_get_valid_tx_ant(mvm)); 1878c2ecf20Sopenharmony_ci} 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci/* 1908c2ecf20Sopenharmony_ci * Add the phy configuration to the PHY context command 1918c2ecf20Sopenharmony_ci */ 1928c2ecf20Sopenharmony_cistatic void iwl_mvm_phy_ctxt_cmd_data(struct iwl_mvm *mvm, 1938c2ecf20Sopenharmony_ci struct iwl_phy_context_cmd *cmd, 1948c2ecf20Sopenharmony_ci struct cfg80211_chan_def *chandef, 1958c2ecf20Sopenharmony_ci u8 chains_static, u8 chains_dynamic) 1968c2ecf20Sopenharmony_ci{ 1978c2ecf20Sopenharmony_ci cmd->lmac_id = cpu_to_le32(iwl_mvm_get_lmac_id(mvm->fw, 1988c2ecf20Sopenharmony_ci chandef->chan->band)); 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci /* Set the channel info data */ 2018c2ecf20Sopenharmony_ci iwl_mvm_set_chan_info_chandef(mvm, &cmd->ci, chandef); 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci iwl_mvm_phy_ctxt_set_rxchain(mvm, &cmd->rxchain_info, 2048c2ecf20Sopenharmony_ci chains_static, chains_dynamic); 2058c2ecf20Sopenharmony_ci} 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci/* 2088c2ecf20Sopenharmony_ci * Send a command to apply the current phy configuration. The command is send 2098c2ecf20Sopenharmony_ci * only if something in the configuration changed: in case that this is the 2108c2ecf20Sopenharmony_ci * first time that the phy configuration is applied or in case that the phy 2118c2ecf20Sopenharmony_ci * configuration changed from the previous apply. 2128c2ecf20Sopenharmony_ci */ 2138c2ecf20Sopenharmony_cistatic int iwl_mvm_phy_ctxt_apply(struct iwl_mvm *mvm, 2148c2ecf20Sopenharmony_ci struct iwl_mvm_phy_ctxt *ctxt, 2158c2ecf20Sopenharmony_ci struct cfg80211_chan_def *chandef, 2168c2ecf20Sopenharmony_ci u8 chains_static, u8 chains_dynamic, 2178c2ecf20Sopenharmony_ci u32 action) 2188c2ecf20Sopenharmony_ci{ 2198c2ecf20Sopenharmony_ci int ret; 2208c2ecf20Sopenharmony_ci int ver = iwl_fw_lookup_cmd_ver(mvm->fw, IWL_ALWAYS_LONG_GROUP, 2218c2ecf20Sopenharmony_ci PHY_CONTEXT_CMD, 1); 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci if (ver == 3) { 2248c2ecf20Sopenharmony_ci struct iwl_phy_context_cmd cmd = {}; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci /* Set the command header fields */ 2278c2ecf20Sopenharmony_ci iwl_mvm_phy_ctxt_cmd_hdr(ctxt, &cmd, action); 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci /* Set the command data */ 2308c2ecf20Sopenharmony_ci iwl_mvm_phy_ctxt_cmd_data(mvm, &cmd, chandef, 2318c2ecf20Sopenharmony_ci chains_static, 2328c2ecf20Sopenharmony_ci chains_dynamic); 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci ret = iwl_mvm_send_cmd_pdu(mvm, PHY_CONTEXT_CMD, 2358c2ecf20Sopenharmony_ci 0, sizeof(cmd), &cmd); 2368c2ecf20Sopenharmony_ci } else if (ver < 3) { 2378c2ecf20Sopenharmony_ci struct iwl_phy_context_cmd_v1 cmd = {}; 2388c2ecf20Sopenharmony_ci u16 len = sizeof(cmd) - iwl_mvm_chan_info_padding(mvm); 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci /* Set the command header fields */ 2418c2ecf20Sopenharmony_ci iwl_mvm_phy_ctxt_cmd_hdr(ctxt, 2428c2ecf20Sopenharmony_ci (struct iwl_phy_context_cmd *)&cmd, 2438c2ecf20Sopenharmony_ci action); 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci /* Set the command data */ 2468c2ecf20Sopenharmony_ci iwl_mvm_phy_ctxt_cmd_data_v1(mvm, &cmd, chandef, 2478c2ecf20Sopenharmony_ci chains_static, 2488c2ecf20Sopenharmony_ci chains_dynamic); 2498c2ecf20Sopenharmony_ci ret = iwl_mvm_send_cmd_pdu(mvm, PHY_CONTEXT_CMD, 2508c2ecf20Sopenharmony_ci 0, len, &cmd); 2518c2ecf20Sopenharmony_ci } else { 2528c2ecf20Sopenharmony_ci IWL_ERR(mvm, "PHY ctxt cmd error ver %d not supported\n", ver); 2538c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 2548c2ecf20Sopenharmony_ci } 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci if (ret) 2588c2ecf20Sopenharmony_ci IWL_ERR(mvm, "PHY ctxt cmd error. ret=%d\n", ret); 2598c2ecf20Sopenharmony_ci return ret; 2608c2ecf20Sopenharmony_ci} 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci/* 2638c2ecf20Sopenharmony_ci * Send a command to add a PHY context based on the current HW configuration. 2648c2ecf20Sopenharmony_ci */ 2658c2ecf20Sopenharmony_ciint iwl_mvm_phy_ctxt_add(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt, 2668c2ecf20Sopenharmony_ci struct cfg80211_chan_def *chandef, 2678c2ecf20Sopenharmony_ci u8 chains_static, u8 chains_dynamic) 2688c2ecf20Sopenharmony_ci{ 2698c2ecf20Sopenharmony_ci WARN_ON(!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) && 2708c2ecf20Sopenharmony_ci ctxt->ref); 2718c2ecf20Sopenharmony_ci lockdep_assert_held(&mvm->mutex); 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci ctxt->channel = chandef->chan; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci return iwl_mvm_phy_ctxt_apply(mvm, ctxt, chandef, 2768c2ecf20Sopenharmony_ci chains_static, chains_dynamic, 2778c2ecf20Sopenharmony_ci FW_CTXT_ACTION_ADD); 2788c2ecf20Sopenharmony_ci} 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci/* 2818c2ecf20Sopenharmony_ci * Update the number of references to the given PHY context. This is valid only 2828c2ecf20Sopenharmony_ci * in case the PHY context was already created, i.e., its reference count > 0. 2838c2ecf20Sopenharmony_ci */ 2848c2ecf20Sopenharmony_civoid iwl_mvm_phy_ctxt_ref(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt) 2858c2ecf20Sopenharmony_ci{ 2868c2ecf20Sopenharmony_ci lockdep_assert_held(&mvm->mutex); 2878c2ecf20Sopenharmony_ci ctxt->ref++; 2888c2ecf20Sopenharmony_ci} 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci/* 2918c2ecf20Sopenharmony_ci * Send a command to modify the PHY context based on the current HW 2928c2ecf20Sopenharmony_ci * configuration. Note that the function does not check that the configuration 2938c2ecf20Sopenharmony_ci * changed. 2948c2ecf20Sopenharmony_ci */ 2958c2ecf20Sopenharmony_ciint iwl_mvm_phy_ctxt_changed(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt, 2968c2ecf20Sopenharmony_ci struct cfg80211_chan_def *chandef, 2978c2ecf20Sopenharmony_ci u8 chains_static, u8 chains_dynamic) 2988c2ecf20Sopenharmony_ci{ 2998c2ecf20Sopenharmony_ci enum iwl_ctxt_action action = FW_CTXT_ACTION_MODIFY; 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci lockdep_assert_held(&mvm->mutex); 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci if (fw_has_capa(&mvm->fw->ucode_capa, 3048c2ecf20Sopenharmony_ci IWL_UCODE_TLV_CAPA_BINDING_CDB_SUPPORT) && 3058c2ecf20Sopenharmony_ci ctxt->channel->band != chandef->chan->band) { 3068c2ecf20Sopenharmony_ci int ret; 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci /* ... remove it here ...*/ 3098c2ecf20Sopenharmony_ci ret = iwl_mvm_phy_ctxt_apply(mvm, ctxt, chandef, 3108c2ecf20Sopenharmony_ci chains_static, chains_dynamic, 3118c2ecf20Sopenharmony_ci FW_CTXT_ACTION_REMOVE); 3128c2ecf20Sopenharmony_ci if (ret) 3138c2ecf20Sopenharmony_ci return ret; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci /* ... and proceed to add it again */ 3168c2ecf20Sopenharmony_ci action = FW_CTXT_ACTION_ADD; 3178c2ecf20Sopenharmony_ci } 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci ctxt->channel = chandef->chan; 3208c2ecf20Sopenharmony_ci ctxt->width = chandef->width; 3218c2ecf20Sopenharmony_ci return iwl_mvm_phy_ctxt_apply(mvm, ctxt, chandef, 3228c2ecf20Sopenharmony_ci chains_static, chains_dynamic, 3238c2ecf20Sopenharmony_ci action); 3248c2ecf20Sopenharmony_ci} 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_civoid iwl_mvm_phy_ctxt_unref(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt) 3278c2ecf20Sopenharmony_ci{ 3288c2ecf20Sopenharmony_ci lockdep_assert_held(&mvm->mutex); 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(!ctxt)) 3318c2ecf20Sopenharmony_ci return; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci ctxt->ref--; 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci /* 3368c2ecf20Sopenharmony_ci * Move unused phy's to a default channel. When the phy is moved the, 3378c2ecf20Sopenharmony_ci * fw will cleanup immediate quiet bit if it was previously set, 3388c2ecf20Sopenharmony_ci * otherwise we might not be able to reuse this phy. 3398c2ecf20Sopenharmony_ci */ 3408c2ecf20Sopenharmony_ci if (ctxt->ref == 0) { 3418c2ecf20Sopenharmony_ci struct ieee80211_channel *chan; 3428c2ecf20Sopenharmony_ci struct cfg80211_chan_def chandef; 3438c2ecf20Sopenharmony_ci struct ieee80211_supported_band *sband = NULL; 3448c2ecf20Sopenharmony_ci enum nl80211_band band = NL80211_BAND_2GHZ; 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci while (!sband && band < NUM_NL80211_BANDS) 3478c2ecf20Sopenharmony_ci sband = mvm->hw->wiphy->bands[band++]; 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci if (WARN_ON(!sband)) 3508c2ecf20Sopenharmony_ci return; 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci chan = &sband->channels[0]; 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci cfg80211_chandef_create(&chandef, chan, NL80211_CHAN_NO_HT); 3558c2ecf20Sopenharmony_ci iwl_mvm_phy_ctxt_changed(mvm, ctxt, &chandef, 1, 1); 3568c2ecf20Sopenharmony_ci } 3578c2ecf20Sopenharmony_ci} 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_cistatic void iwl_mvm_binding_iterator(void *_data, u8 *mac, 3608c2ecf20Sopenharmony_ci struct ieee80211_vif *vif) 3618c2ecf20Sopenharmony_ci{ 3628c2ecf20Sopenharmony_ci unsigned long *data = _data; 3638c2ecf20Sopenharmony_ci struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci if (!mvmvif->phy_ctxt) 3668c2ecf20Sopenharmony_ci return; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci if (vif->type == NL80211_IFTYPE_STATION || 3698c2ecf20Sopenharmony_ci vif->type == NL80211_IFTYPE_AP) 3708c2ecf20Sopenharmony_ci __set_bit(mvmvif->phy_ctxt->id, data); 3718c2ecf20Sopenharmony_ci} 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ciint iwl_mvm_phy_ctx_count(struct iwl_mvm *mvm) 3748c2ecf20Sopenharmony_ci{ 3758c2ecf20Sopenharmony_ci unsigned long phy_ctxt_counter = 0; 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci ieee80211_iterate_active_interfaces_atomic(mvm->hw, 3788c2ecf20Sopenharmony_ci IEEE80211_IFACE_ITER_NORMAL, 3798c2ecf20Sopenharmony_ci iwl_mvm_binding_iterator, 3808c2ecf20Sopenharmony_ci &phy_ctxt_counter); 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci return hweight8(phy_ctxt_counter); 3838c2ecf20Sopenharmony_ci} 384