Path: blob/main/sys/contrib/dev/iwlwifi/mvm/mac80211.c
48285 views
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause1/*2* Copyright (C) 2012-2014, 2018-2025 Intel Corporation3* Copyright (C) 2013-2015 Intel Mobile Communications GmbH4* Copyright (C) 2016-2017 Intel Deutschland GmbH5*/6#include <linux/kernel.h>7#include <linux/fips.h>8#include <linux/slab.h>9#include <linux/skbuff.h>10#include <linux/netdevice.h>11#include <linux/etherdevice.h>12#include <linux/ip.h>13#include <linux/if_arp.h>14#include <linux/time.h>15#if defined(__FreeBSD__)16#include <linux/math64.h>17#endif18#include <net/mac80211.h>19#include <net/ieee80211_radiotap.h>20#include <net/tcp.h>21#if defined(__FreeBSD__)22#include <linux/udp.h>23#endif2425#include "iwl-drv.h"26#include "iwl-op-mode.h"27#include "iwl-io.h"28#include "mvm.h"29#include "sta.h"30#include "time-event.h"31#include "iwl-nvm-utils.h"32#include "iwl-phy-db.h"33#ifdef CONFIG_NL80211_TESTMODE34#include "testmode.h"35#endif36#include "fw/error-dump.h"37#include "iwl-prph.h"38#include "iwl-nvm-parse.h"39#include "time-sync.h"4041#define IWL_MVM_LIMITS(ap) \42{ \43.max = 1, \44.types = BIT(NL80211_IFTYPE_STATION), \45}, \46{ \47.max = 1, \48.types = ap | \49BIT(NL80211_IFTYPE_P2P_CLIENT) | \50BIT(NL80211_IFTYPE_P2P_GO), \51}, \52{ \53.max = 1, \54.types = BIT(NL80211_IFTYPE_P2P_DEVICE), \55}5657static const struct ieee80211_iface_limit iwl_mvm_limits[] = {58IWL_MVM_LIMITS(0)59};6061static const struct ieee80211_iface_limit iwl_mvm_limits_ap[] = {62IWL_MVM_LIMITS(BIT(NL80211_IFTYPE_AP))63};6465static const struct ieee80211_iface_combination iwl_mvm_iface_combinations[] = {66{67.num_different_channels = 2,68.max_interfaces = 3,69.limits = iwl_mvm_limits,70.n_limits = ARRAY_SIZE(iwl_mvm_limits),71},72{73.num_different_channels = 1,74.max_interfaces = 3,75.limits = iwl_mvm_limits_ap,76.n_limits = ARRAY_SIZE(iwl_mvm_limits_ap),77},78};7980static const struct cfg80211_pmsr_capabilities iwl_mvm_pmsr_capa = {81.max_peers = IWL_TOF_MAX_APS,82.report_ap_tsf = 1,83.randomize_mac_addr = 1,8485.ftm = {86.supported = 1,87.asap = 1,88.non_asap = 1,89.request_lci = 1,90.request_civicloc = 1,91.trigger_based = 1,92.non_trigger_based = 1,93.max_bursts_exponent = -1, /* all supported */94.max_ftms_per_burst = 0, /* no limits */95.bandwidths = BIT(NL80211_CHAN_WIDTH_20_NOHT) |96BIT(NL80211_CHAN_WIDTH_20) |97BIT(NL80211_CHAN_WIDTH_40) |98BIT(NL80211_CHAN_WIDTH_80) |99BIT(NL80211_CHAN_WIDTH_160),100.preambles = BIT(NL80211_PREAMBLE_LEGACY) |101BIT(NL80211_PREAMBLE_HT) |102BIT(NL80211_PREAMBLE_VHT) |103BIT(NL80211_PREAMBLE_HE),104},105};106107static int __iwl_mvm_mac_set_key(struct ieee80211_hw *hw,108enum set_key_cmd cmd,109struct ieee80211_vif *vif,110struct ieee80211_sta *sta,111struct ieee80211_key_conf *key);112113static void iwl_mvm_reset_phy_ctxts(struct iwl_mvm *mvm)114{115int i;116117memset(mvm->phy_ctxts, 0, sizeof(mvm->phy_ctxts));118for (i = 0; i < NUM_PHY_CTX; i++) {119mvm->phy_ctxts[i].id = i;120mvm->phy_ctxts[i].ref = 0;121}122}123124struct ieee80211_regdomain *iwl_mvm_get_regdomain(struct wiphy *wiphy,125const char *alpha2,126enum iwl_mcc_source src_id,127bool *changed)128{129struct ieee80211_regdomain *regd = NULL;130struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);131struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);132struct iwl_mcc_update_resp_v8 *resp;133u8 resp_ver;134135IWL_DEBUG_LAR(mvm, "Getting regdomain data for %s from FW\n", alpha2);136137lockdep_assert_held(&mvm->mutex);138139resp = iwl_mvm_update_mcc(mvm, alpha2, src_id);140if (IS_ERR_OR_NULL(resp)) {141IWL_DEBUG_LAR(mvm, "Could not get update from FW %d\n",142PTR_ERR_OR_ZERO(resp));143resp = NULL;144goto out;145}146147if (changed) {148u32 status = le32_to_cpu(resp->status);149150*changed = (status == MCC_RESP_NEW_CHAN_PROFILE ||151status == MCC_RESP_ILLEGAL);152}153resp_ver = iwl_fw_lookup_notif_ver(mvm->fw, IWL_ALWAYS_LONG_GROUP,154MCC_UPDATE_CMD, 0);155IWL_DEBUG_LAR(mvm, "MCC update response version: %d\n", resp_ver);156157regd = iwl_parse_nvm_mcc_info(mvm->trans,158__le32_to_cpu(resp->n_channels),159resp->channels,160__le16_to_cpu(resp->mcc),161__le16_to_cpu(resp->geo_info),162le32_to_cpu(resp->cap), resp_ver);163/* Store the return source id */164src_id = resp->source_id;165if (IS_ERR_OR_NULL(regd)) {166IWL_DEBUG_LAR(mvm, "Could not get parse update from FW %d\n",167PTR_ERR_OR_ZERO(regd));168goto out;169}170171IWL_DEBUG_LAR(mvm, "setting alpha2 from FW to %s (0x%x, 0x%x) src=%d\n",172regd->alpha2, regd->alpha2[0], regd->alpha2[1], src_id);173mvm->lar_regdom_set = true;174mvm->mcc_src = src_id;175176iwl_mei_set_country_code(__le16_to_cpu(resp->mcc));177178out:179kfree(resp);180return regd;181}182183void iwl_mvm_update_changed_regdom(struct iwl_mvm *mvm)184{185bool changed;186struct ieee80211_regdomain *regd;187188if (!iwl_mvm_is_lar_supported(mvm))189return;190191regd = iwl_mvm_get_current_regdomain(mvm, &changed);192if (!IS_ERR_OR_NULL(regd)) {193/* only update the regulatory core if changed */194if (changed)195regulatory_set_wiphy_regd(mvm->hw->wiphy, regd);196197kfree(regd);198}199}200201struct ieee80211_regdomain *iwl_mvm_get_current_regdomain(struct iwl_mvm *mvm,202bool *changed)203{204return iwl_mvm_get_regdomain(mvm->hw->wiphy, "ZZ",205iwl_mvm_is_wifi_mcc_supported(mvm) ?206MCC_SOURCE_GET_CURRENT :207MCC_SOURCE_OLD_FW, changed);208}209210int iwl_mvm_init_fw_regd(struct iwl_mvm *mvm, bool force_regd_sync)211{212enum iwl_mcc_source used_src;213struct ieee80211_regdomain *regd;214int ret;215bool changed;216const struct ieee80211_regdomain *r =217wiphy_dereference(mvm->hw->wiphy, mvm->hw->wiphy->regd);218219if (!r)220return -ENOENT;221222/* save the last source in case we overwrite it below */223used_src = mvm->mcc_src;224if (iwl_mvm_is_wifi_mcc_supported(mvm)) {225/* Notify the firmware we support wifi location updates */226regd = iwl_mvm_get_current_regdomain(mvm, NULL);227if (!IS_ERR_OR_NULL(regd))228kfree(regd);229}230231/* Now set our last stored MCC and source */232regd = iwl_mvm_get_regdomain(mvm->hw->wiphy, r->alpha2, used_src,233&changed);234if (IS_ERR_OR_NULL(regd))235return -EIO;236237/* update cfg80211 if the regdomain was changed or the caller explicitly238* asked to update regdomain239*/240if (changed || force_regd_sync)241ret = regulatory_set_wiphy_regd_sync(mvm->hw->wiphy, regd);242else243ret = 0;244245kfree(regd);246return ret;247}248249/* Each capability added here should also be add to tm_if_types_ext_capa_sta */250static const u8 he_if_types_ext_capa_sta[] = {251[0] = WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING,252[2] = WLAN_EXT_CAPA3_MULTI_BSSID_SUPPORT,253[7] = WLAN_EXT_CAPA8_OPMODE_NOTIF |254WLAN_EXT_CAPA8_MAX_MSDU_IN_AMSDU_LSB,255[8] = WLAN_EXT_CAPA9_MAX_MSDU_IN_AMSDU_MSB,256};257258static const u8 tm_if_types_ext_capa_sta[] = {259[0] = WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING,260[2] = WLAN_EXT_CAPA3_MULTI_BSSID_SUPPORT |261WLAN_EXT_CAPA3_TIMING_MEASUREMENT_SUPPORT,262[7] = WLAN_EXT_CAPA8_OPMODE_NOTIF |263WLAN_EXT_CAPA8_MAX_MSDU_IN_AMSDU_LSB,264[8] = WLAN_EXT_CAPA9_MAX_MSDU_IN_AMSDU_MSB,265[9] = WLAN_EXT_CAPA10_TWT_REQUESTER_SUPPORT,266};267268/* Additional interface types for which extended capabilities are269* specified separately270*/271272#define IWL_MVM_EMLSR_CAPA (IEEE80211_EML_CAP_EMLSR_SUPP | \273IEEE80211_EML_CAP_EMLSR_PADDING_DELAY_32US << \274__bf_shf(IEEE80211_EML_CAP_EMLSR_PADDING_DELAY) | \275IEEE80211_EML_CAP_EMLSR_TRANSITION_DELAY_64US << \276__bf_shf(IEEE80211_EML_CAP_EMLSR_TRANSITION_DELAY))277#define IWL_MVM_MLD_CAPA_OPS (FIELD_PREP_CONST( \278IEEE80211_MLD_CAP_OP_TID_TO_LINK_MAP_NEG_SUPP, \279IEEE80211_MLD_CAP_OP_TID_TO_LINK_MAP_NEG_SUPP_SAME) | \280IEEE80211_MLD_CAP_OP_LINK_RECONF_SUPPORT)281282static const struct wiphy_iftype_ext_capab add_iftypes_ext_capa[] = {283{284.iftype = NL80211_IFTYPE_STATION,285.extended_capabilities = he_if_types_ext_capa_sta,286.extended_capabilities_mask = he_if_types_ext_capa_sta,287.extended_capabilities_len = sizeof(he_if_types_ext_capa_sta),288/* relevant only if EHT is supported */289.eml_capabilities = IWL_MVM_EMLSR_CAPA,290.mld_capa_and_ops = IWL_MVM_MLD_CAPA_OPS,291},292{293.iftype = NL80211_IFTYPE_STATION,294.extended_capabilities = tm_if_types_ext_capa_sta,295.extended_capabilities_mask = tm_if_types_ext_capa_sta,296.extended_capabilities_len = sizeof(tm_if_types_ext_capa_sta),297/* relevant only if EHT is supported */298.eml_capabilities = IWL_MVM_EMLSR_CAPA,299.mld_capa_and_ops = IWL_MVM_MLD_CAPA_OPS,300},301};302303int iwl_mvm_op_get_antenna(struct ieee80211_hw *hw, int radio_idx,304u32 *tx_ant, u32 *rx_ant)305{306struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);307*tx_ant = iwl_mvm_get_valid_tx_ant(mvm);308*rx_ant = iwl_mvm_get_valid_rx_ant(mvm);309return 0;310}311312int iwl_mvm_op_set_antenna(struct ieee80211_hw *hw, int radio_idx, u32 tx_ant,313u32 rx_ant)314{315struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);316317/* This has been tested on those devices only */318if (mvm->trans->mac_cfg->device_family != IWL_DEVICE_FAMILY_9000 &&319mvm->trans->mac_cfg->device_family != IWL_DEVICE_FAMILY_22000 &&320mvm->trans->mac_cfg->device_family != IWL_DEVICE_FAMILY_AX210)321return -EOPNOTSUPP;322323if (!mvm->nvm_data)324return -EBUSY;325326/* mac80211 ensures the device is not started,327* so the firmware cannot be running328*/329330mvm->set_tx_ant = tx_ant;331mvm->set_rx_ant = rx_ant;332333iwl_reinit_cab(mvm->trans, mvm->nvm_data, tx_ant, rx_ant, mvm->fw);334335return 0;336}337338int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)339{340struct ieee80211_hw *hw = mvm->hw;341int num_mac, ret, i;342static const u32 mvm_ciphers[] = {343WLAN_CIPHER_SUITE_WEP40,344WLAN_CIPHER_SUITE_WEP104,345WLAN_CIPHER_SUITE_TKIP,346WLAN_CIPHER_SUITE_CCMP,347};348#ifdef CONFIG_PM_SLEEP349bool unified = fw_has_capa(&mvm->fw->ucode_capa,350IWL_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG);351#endif352u32 sec_key_id = WIDE_ID(DATA_PATH_GROUP, SEC_KEY_CMD);353u8 sec_key_ver = iwl_fw_lookup_cmd_ver(mvm->fw, sec_key_id, 0);354355/* Tell mac80211 our characteristics */356ieee80211_hw_set(hw, SIGNAL_DBM);357ieee80211_hw_set(hw, SPECTRUM_MGMT);358ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS);359ieee80211_hw_set(hw, WANT_MONITOR_VIF);360ieee80211_hw_set(hw, SUPPORTS_PS);361ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS);362ieee80211_hw_set(hw, AMPDU_AGGREGATION);363ieee80211_hw_set(hw, CONNECTION_MONITOR);364ieee80211_hw_set(hw, CHANCTX_STA_CSA);365ieee80211_hw_set(hw, SUPPORT_FAST_XMIT);366ieee80211_hw_set(hw, SUPPORTS_CLONED_SKBS);367ieee80211_hw_set(hw, SUPPORTS_AMSDU_IN_AMPDU);368ieee80211_hw_set(hw, NEEDS_UNIQUE_STA_ADDR);369ieee80211_hw_set(hw, SUPPORTS_VHT_EXT_NSS_BW);370ieee80211_hw_set(hw, BUFF_MMPDU_TXQ);371ieee80211_hw_set(hw, STA_MMPDU_TXQ);372373/* Set this early since we need to have it for the check below */374if (mvm->mld_api_is_used && mvm->nvm_data->sku_cap_11be_enable &&375!iwlwifi_mod_params.disable_11ax &&376!iwlwifi_mod_params.disable_11be) {377hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_MLO;378/* we handle this already earlier, but need it for MLO */379ieee80211_hw_set(hw, HANDLES_QUIET_CSA);380}381382/* With MLD FW API, it tracks timing by itself,383* no need for any timing from the host384*/385if (!mvm->mld_api_is_used)386ieee80211_hw_set(hw, TIMING_BEACON_ONLY);387388/*389* On older devices, enabling TX A-MSDU occasionally leads to390* something getting messed up, the command read from the FIFO391* gets out of sync and isn't a TX command, so that we have an392* assert EDC.393*394* It's not clear where the bug is, but since we didn't used to395* support A-MSDU until moving the mac80211 iTXQs, just leave it396* for older devices. We also don't see this issue on any newer397* devices.398*/399if (mvm->trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_9000)400ieee80211_hw_set(hw, TX_AMSDU);401ieee80211_hw_set(hw, TX_FRAG_LIST);402403if (iwl_mvm_has_tlc_offload(mvm)) {404ieee80211_hw_set(hw, TX_AMPDU_SETUP_IN_HW);405ieee80211_hw_set(hw, HAS_RATE_CONTROL);406}407408/* We want to use the mac80211's reorder buffer for 9000 */409if (iwl_mvm_has_new_rx_api(mvm) &&410mvm->trans->mac_cfg->device_family > IWL_DEVICE_FAMILY_9000)411ieee80211_hw_set(hw, SUPPORTS_REORDERING_BUFFER);412413if (fw_has_capa(&mvm->fw->ucode_capa,414IWL_UCODE_TLV_CAPA_STA_PM_NOTIF)) {415ieee80211_hw_set(hw, AP_LINK_PS);416} else if (WARN_ON(iwl_mvm_has_new_tx_api(mvm))) {417/*418* we absolutely need this for the new TX API since that comes419* with many more queues than the current code can deal with420* for station powersave421*/422return -EINVAL;423}424425if (mvm->trans->info.num_rxqs > 1)426ieee80211_hw_set(hw, USES_RSS);427428if (mvm->trans->info.max_skb_frags)429hw->netdev_features = NETIF_F_HIGHDMA | NETIF_F_SG;430431hw->queues = IEEE80211_NUM_ACS;432hw->offchannel_tx_hw_queue = IWL_MVM_OFFCHANNEL_QUEUE;433hw->radiotap_mcs_details |= IEEE80211_RADIOTAP_MCS_HAVE_FEC |434IEEE80211_RADIOTAP_MCS_HAVE_STBC;435hw->radiotap_vht_details |= IEEE80211_RADIOTAP_VHT_KNOWN_STBC |436IEEE80211_RADIOTAP_VHT_KNOWN_BEAMFORMED;437438hw->radiotap_timestamp.units_pos =439IEEE80211_RADIOTAP_TIMESTAMP_UNIT_US |440IEEE80211_RADIOTAP_TIMESTAMP_SPOS_PLCP_SIG_ACQ;441/* this is the case for CCK frames, it's better (only 8) for OFDM */442hw->radiotap_timestamp.accuracy = 22;443444if (!iwl_mvm_has_tlc_offload(mvm))445hw->rate_control_algorithm = RS_NAME;446447hw->uapsd_queues = IWL_MVM_UAPSD_QUEUES;448hw->uapsd_max_sp_len = IWL_UAPSD_MAX_SP;449hw->max_tx_fragments = mvm->trans->info.max_skb_frags;450451BUILD_BUG_ON(ARRAY_SIZE(mvm->ciphers) < ARRAY_SIZE(mvm_ciphers) + 6);452memcpy(mvm->ciphers, mvm_ciphers, sizeof(mvm_ciphers));453hw->wiphy->n_cipher_suites = ARRAY_SIZE(mvm_ciphers);454hw->wiphy->cipher_suites = mvm->ciphers;455456if (iwl_mvm_has_new_rx_api(mvm)) {457mvm->ciphers[hw->wiphy->n_cipher_suites] =458WLAN_CIPHER_SUITE_GCMP;459hw->wiphy->n_cipher_suites++;460mvm->ciphers[hw->wiphy->n_cipher_suites] =461WLAN_CIPHER_SUITE_GCMP_256;462hw->wiphy->n_cipher_suites++;463}464465if (iwlwifi_mod_params.swcrypto)466IWL_ERR(mvm,467"iwlmvm doesn't allow to disable HW crypto, check swcrypto module parameter\n");468if (!iwlwifi_mod_params.bt_coex_active)469IWL_ERR(mvm,470"iwlmvm doesn't allow to disable BT Coex, check bt_coex_active module parameter\n");471472if (!fips_enabled)473ieee80211_hw_set(hw, MFP_CAPABLE);474475mvm->ciphers[hw->wiphy->n_cipher_suites] = WLAN_CIPHER_SUITE_AES_CMAC;476hw->wiphy->n_cipher_suites++;477if (iwl_mvm_has_new_rx_api(mvm)) {478mvm->ciphers[hw->wiphy->n_cipher_suites] =479WLAN_CIPHER_SUITE_BIP_GMAC_128;480hw->wiphy->n_cipher_suites++;481mvm->ciphers[hw->wiphy->n_cipher_suites] =482WLAN_CIPHER_SUITE_BIP_GMAC_256;483hw->wiphy->n_cipher_suites++;484}485486wiphy_ext_feature_set(hw->wiphy,487NL80211_EXT_FEATURE_BEACON_RATE_LEGACY);488wiphy_ext_feature_set(hw->wiphy,489NL80211_EXT_FEATURE_SCAN_MIN_PREQ_CONTENT);490491if (fw_has_capa(&mvm->fw->ucode_capa,492IWL_UCODE_TLV_CAPA_FTM_CALIBRATED)) {493wiphy_ext_feature_set(hw->wiphy,494NL80211_EXT_FEATURE_ENABLE_FTM_RESPONDER);495hw->wiphy->pmsr_capa = &iwl_mvm_pmsr_capa;496}497498/*499* beacon protection must be handled by firmware,500* so cannot be done with fips_enabled501*/502if (!fips_enabled && sec_key_ver &&503fw_has_capa(&mvm->fw->ucode_capa,504IWL_UCODE_TLV_CAPA_BIGTK_TX_SUPPORT))505wiphy_ext_feature_set(hw->wiphy,506NL80211_EXT_FEATURE_BEACON_PROTECTION);507else if (!fips_enabled &&508fw_has_capa(&mvm->fw->ucode_capa,509IWL_UCODE_TLV_CAPA_BIGTK_SUPPORT))510wiphy_ext_feature_set(hw->wiphy,511NL80211_EXT_FEATURE_BEACON_PROTECTION_CLIENT);512513if (fw_has_capa(&mvm->fw->ucode_capa,514IWL_UCODE_TLV_CAPA_TIME_SYNC_BOTH_FTM_TM))515hw->wiphy->hw_timestamp_max_peers = 1;516517if (fw_has_capa(&mvm->fw->ucode_capa,518IWL_UCODE_TLV_CAPA_SPP_AMSDU_SUPPORT))519wiphy_ext_feature_set(hw->wiphy,520NL80211_EXT_FEATURE_SPP_AMSDU_SUPPORT);521522ieee80211_hw_set(hw, SINGLE_SCAN_ON_ALL_BANDS);523hw->wiphy->features |=524NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR |525NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR |526NL80211_FEATURE_ND_RANDOM_MAC_ADDR;527528hw->sta_data_size = sizeof(struct iwl_mvm_sta);529hw->vif_data_size = sizeof(struct iwl_mvm_vif);530hw->chanctx_data_size = sizeof(u16);531hw->txq_data_size = sizeof(struct iwl_mvm_txq);532533hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |534BIT(NL80211_IFTYPE_P2P_CLIENT) |535BIT(NL80211_IFTYPE_AP) |536BIT(NL80211_IFTYPE_P2P_GO) |537BIT(NL80211_IFTYPE_P2P_DEVICE) |538BIT(NL80211_IFTYPE_ADHOC);539540hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;541wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_VHT_IBSS);542543/* The new Tx API does not allow to pass the key or keyid of a MPDU to544* the hw, preventing us to control which key(id) to use per MPDU.545* Till that's fixed we can't use Extended Key ID for the newer cards.546*/547if (!iwl_mvm_has_new_tx_api(mvm))548wiphy_ext_feature_set(hw->wiphy,549NL80211_EXT_FEATURE_EXT_KEY_ID);550hw->wiphy->features |= NL80211_FEATURE_HT_IBSS;551552hw->wiphy->regulatory_flags |= REGULATORY_ENABLE_RELAX_NO_IR;553if (iwl_mvm_is_lar_supported(mvm))554hw->wiphy->regulatory_flags |= REGULATORY_WIPHY_SELF_MANAGED;555else556hw->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG |557REGULATORY_DISABLE_BEACON_HINTS;558559if (mvm->trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_AX210)560wiphy_ext_feature_set(hw->wiphy,561NL80211_EXT_FEATURE_DFS_CONCURRENT);562563hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;564hw->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH;565hw->wiphy->flags |= WIPHY_FLAG_SPLIT_SCAN_6GHZ;566567hw->wiphy->iface_combinations = iwl_mvm_iface_combinations;568hw->wiphy->n_iface_combinations =569ARRAY_SIZE(iwl_mvm_iface_combinations);570571hw->wiphy->max_remain_on_channel_duration = 10000;572hw->max_listen_interval = IWL_MVM_CONN_LISTEN_INTERVAL;573574/* Extract MAC address */575memcpy(mvm->addresses[0].addr, mvm->nvm_data->hw_addr, ETH_ALEN);576hw->wiphy->addresses = mvm->addresses;577hw->wiphy->n_addresses = 1;578579/* Extract additional MAC addresses if available */580num_mac = (mvm->nvm_data->n_hw_addrs > 1) ?581min(IWL_MVM_MAX_ADDRESSES, mvm->nvm_data->n_hw_addrs) : 1;582583for (i = 1; i < num_mac; i++) {584memcpy(mvm->addresses[i].addr, mvm->addresses[i-1].addr,585ETH_ALEN);586mvm->addresses[i].addr[5]++;587hw->wiphy->n_addresses++;588}589590iwl_mvm_reset_phy_ctxts(mvm);591592hw->wiphy->max_scan_ie_len = iwl_mvm_max_scan_ie_len(mvm);593594hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX;595596BUILD_BUG_ON(IWL_MVM_SCAN_STOPPING_MASK & IWL_MVM_SCAN_MASK);597BUILD_BUG_ON(IWL_MAX_UMAC_SCANS > HWEIGHT32(IWL_MVM_SCAN_MASK) ||598IWL_MAX_LMAC_SCANS > HWEIGHT32(IWL_MVM_SCAN_MASK));599600if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_UMAC_SCAN))601mvm->max_scans = IWL_MAX_UMAC_SCANS;602else603mvm->max_scans = IWL_MAX_LMAC_SCANS;604605if (mvm->nvm_data->bands[NL80211_BAND_2GHZ].n_channels)606hw->wiphy->bands[NL80211_BAND_2GHZ] =607&mvm->nvm_data->bands[NL80211_BAND_2GHZ];608if (mvm->nvm_data->bands[NL80211_BAND_5GHZ].n_channels) {609hw->wiphy->bands[NL80211_BAND_5GHZ] =610&mvm->nvm_data->bands[NL80211_BAND_5GHZ];611612if (fw_has_capa(&mvm->fw->ucode_capa,613IWL_UCODE_TLV_CAPA_BEAMFORMER) &&614fw_has_api(&mvm->fw->ucode_capa,615IWL_UCODE_TLV_API_LQ_SS_PARAMS))616hw->wiphy->bands[NL80211_BAND_5GHZ]->vht_cap.cap |=617IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE;618}619if (fw_has_capa(&mvm->fw->ucode_capa,620IWL_UCODE_TLV_CAPA_PSC_CHAN_SUPPORT) &&621mvm->nvm_data->bands[NL80211_BAND_6GHZ].n_channels)622hw->wiphy->bands[NL80211_BAND_6GHZ] =623&mvm->nvm_data->bands[NL80211_BAND_6GHZ];624625hw->wiphy->hw_version = mvm->trans->info.hw_id;626627if (iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_CAM)628hw->wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT;629else630hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;631632hw->wiphy->max_sched_scan_reqs = 1;633hw->wiphy->max_sched_scan_ssids = PROBE_OPTION_MAX;634hw->wiphy->max_match_sets = iwl_umac_scan_get_max_profiles(mvm->fw);635/* we create the 802.11 header and zero length SSID IE. */636hw->wiphy->max_sched_scan_ie_len =637SCAN_OFFLOAD_PROBE_REQ_SIZE - 24 - 2;638hw->wiphy->max_sched_scan_plans = IWL_MAX_SCHED_SCAN_PLANS;639hw->wiphy->max_sched_scan_plan_interval = U16_MAX;640641/*642* the firmware uses u8 for num of iterations, but 0xff is saved for643* infinite loop, so the maximum number of iterations is actually 254.644*/645hw->wiphy->max_sched_scan_plan_iterations = 254;646647hw->wiphy->features |= NL80211_FEATURE_P2P_GO_CTWIN |648NL80211_FEATURE_LOW_PRIORITY_SCAN |649NL80211_FEATURE_P2P_GO_OPPPS |650NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE |651NL80211_FEATURE_SUPPORTS_WMM_ADMISSION;652653/* when firmware supports RLC/SMPS offload, do not set these654* driver features, since it's no longer supported by driver.655*/656if (!iwl_mvm_has_rlc_offload(mvm))657hw->wiphy->features |= NL80211_FEATURE_STATIC_SMPS |658NL80211_FEATURE_DYNAMIC_SMPS;659660if (fw_has_capa(&mvm->fw->ucode_capa,661IWL_UCODE_TLV_CAPA_TXPOWER_INSERTION_SUPPORT))662hw->wiphy->features |= NL80211_FEATURE_TX_POWER_INSERTION;663if (fw_has_capa(&mvm->fw->ucode_capa,664IWL_UCODE_TLV_CAPA_QUIET_PERIOD_SUPPORT))665hw->wiphy->features |= NL80211_FEATURE_QUIET;666667if (fw_has_capa(&mvm->fw->ucode_capa,668IWL_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT))669hw->wiphy->features |=670NL80211_FEATURE_DS_PARAM_SET_IE_IN_PROBES;671672if (fw_has_capa(&mvm->fw->ucode_capa,673IWL_UCODE_TLV_CAPA_WFA_TPC_REP_IE_SUPPORT))674hw->wiphy->features |= NL80211_FEATURE_WFA_TPC_IE_IN_PROBES;675676if (iwl_fw_lookup_cmd_ver(mvm->fw, WOWLAN_KEK_KCK_MATERIAL,677IWL_FW_CMD_VER_UNKNOWN) >= 3)678hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_EXT_KEK_KCK;679680if (fw_has_api(&mvm->fw->ucode_capa,681IWL_UCODE_TLV_API_SCAN_TSF_REPORT)) {682wiphy_ext_feature_set(hw->wiphy,683NL80211_EXT_FEATURE_SCAN_START_TIME);684wiphy_ext_feature_set(hw->wiphy,685NL80211_EXT_FEATURE_BSS_PARENT_TSF);686}687688if (iwl_mvm_is_oce_supported(mvm)) {689u8 scan_ver = iwl_fw_lookup_cmd_ver(mvm->fw, SCAN_REQ_UMAC, 0);690691wiphy_ext_feature_set(hw->wiphy,692NL80211_EXT_FEATURE_ACCEPT_BCAST_PROBE_RESP);693wiphy_ext_feature_set(hw->wiphy,694NL80211_EXT_FEATURE_FILS_MAX_CHANNEL_TIME);695wiphy_ext_feature_set(hw->wiphy,696NL80211_EXT_FEATURE_OCE_PROBE_REQ_HIGH_TX_RATE);697698/* Old firmware also supports probe deferral and suppression */699if (scan_ver < 15)700wiphy_ext_feature_set(hw->wiphy,701NL80211_EXT_FEATURE_OCE_PROBE_REQ_DEFERRAL_SUPPRESSION);702}703704hw->wiphy->iftype_ext_capab = NULL;705hw->wiphy->num_iftype_ext_capab = 0;706707if (mvm->nvm_data->sku_cap_11ax_enable &&708!iwlwifi_mod_params.disable_11ax) {709hw->wiphy->iftype_ext_capab = add_iftypes_ext_capa;710hw->wiphy->num_iftype_ext_capab =711ARRAY_SIZE(add_iftypes_ext_capa) - 1;712713ieee80211_hw_set(hw, SUPPORTS_MULTI_BSSID);714ieee80211_hw_set(hw, SUPPORTS_ONLY_HE_MULTI_BSSID);715}716717if (iwl_fw_lookup_cmd_ver(mvm->fw,718WIDE_ID(DATA_PATH_GROUP,719WNM_80211V_TIMING_MEASUREMENT_CONFIG_CMD),720IWL_FW_CMD_VER_UNKNOWN) >= 1) {721IWL_DEBUG_INFO(mvm->trans, "Timing measurement supported\n");722723if (!hw->wiphy->iftype_ext_capab) {724hw->wiphy->num_iftype_ext_capab = 1;725hw->wiphy->iftype_ext_capab = add_iftypes_ext_capa +726ARRAY_SIZE(add_iftypes_ext_capa) - 1;727} else {728hw->wiphy->iftype_ext_capab = add_iftypes_ext_capa + 1;729}730}731732if (iwl_fw_lookup_cmd_ver(mvm->fw, WIDE_ID(LOCATION_GROUP,733TOF_RANGE_REQ_CMD),734IWL_FW_CMD_VER_UNKNOWN) >= 11) {735wiphy_ext_feature_set(hw->wiphy,736NL80211_EXT_FEATURE_PROT_RANGE_NEGO_AND_MEASURE);737738if (fw_has_capa(&mvm->fw->ucode_capa,739IWL_UCODE_TLV_CAPA_SECURE_LTF_SUPPORT))740wiphy_ext_feature_set(hw->wiphy,741NL80211_EXT_FEATURE_SECURE_LTF);742}743744mvm->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD;745746#ifdef CONFIG_PM_SLEEP747if ((unified || mvm->fw->img[IWL_UCODE_WOWLAN].num_sec) &&748device_can_wakeup(mvm->trans->dev) && !fips_enabled) {749mvm->wowlan.flags |= WIPHY_WOWLAN_MAGIC_PKT |750WIPHY_WOWLAN_DISCONNECT |751WIPHY_WOWLAN_EAP_IDENTITY_REQ |752WIPHY_WOWLAN_RFKILL_RELEASE |753WIPHY_WOWLAN_NET_DETECT;754mvm->wowlan.flags |= WIPHY_WOWLAN_SUPPORTS_GTK_REKEY |755WIPHY_WOWLAN_GTK_REKEY_FAILURE |756WIPHY_WOWLAN_4WAY_HANDSHAKE;757758mvm->wowlan.n_patterns = IWL_WOWLAN_MAX_PATTERNS;759mvm->wowlan.pattern_min_len = IWL_WOWLAN_MIN_PATTERN_LEN;760mvm->wowlan.pattern_max_len = IWL_WOWLAN_MAX_PATTERN_LEN;761mvm->wowlan.max_nd_match_sets =762iwl_umac_scan_get_max_profiles(mvm->fw);763hw->wiphy->wowlan = &mvm->wowlan;764}765#endif766767ret = iwl_mvm_leds_init(mvm);768if (ret)769return ret;770771if (fw_has_capa(&mvm->fw->ucode_capa,772IWL_UCODE_TLV_CAPA_TDLS_SUPPORT)) {773IWL_DEBUG_TDLS(mvm, "TDLS supported\n");774hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS;775ieee80211_hw_set(hw, TDLS_WIDER_BW);776}777778if (fw_has_capa(&mvm->fw->ucode_capa,779IWL_UCODE_TLV_CAPA_TDLS_CHANNEL_SWITCH)) {780IWL_DEBUG_TDLS(mvm, "TDLS channel switch supported\n");781hw->wiphy->features |= NL80211_FEATURE_TDLS_CHANNEL_SWITCH;782}783784hw->netdev_features |= mvm->trans->mac_cfg->base->features;785if (!iwl_mvm_is_csum_supported(mvm))786hw->netdev_features &= ~IWL_CSUM_NETIF_FLAGS_MASK;787788if (mvm->cfg->vht_mu_mimo_supported)789wiphy_ext_feature_set(hw->wiphy,790NL80211_EXT_FEATURE_MU_MIMO_AIR_SNIFFER);791792if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_PROTECTED_TWT))793wiphy_ext_feature_set(hw->wiphy,794NL80211_EXT_FEATURE_PROTECTED_TWT);795796iwl_mvm_vendor_cmds_register(mvm);797798hw->wiphy->available_antennas_tx = iwl_mvm_get_valid_tx_ant(mvm);799hw->wiphy->available_antennas_rx = iwl_mvm_get_valid_rx_ant(mvm);800801ret = ieee80211_register_hw(mvm->hw);802if (ret) {803iwl_mvm_leds_exit(mvm);804}805806return ret;807}808809static void iwl_mvm_tx_skb(struct iwl_mvm *mvm, struct sk_buff *skb,810struct ieee80211_sta *sta)811{812if (likely(sta)) {813if (likely(iwl_mvm_tx_skb_sta(mvm, skb, sta) == 0))814return;815} else {816if (likely(iwl_mvm_tx_skb_non_sta(mvm, skb) == 0))817return;818}819820ieee80211_free_txskb(mvm->hw, skb);821}822823void iwl_mvm_mac_tx(struct ieee80211_hw *hw,824struct ieee80211_tx_control *control, struct sk_buff *skb)825{826struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);827struct ieee80211_sta *sta = control->sta;828struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);829struct ieee80211_hdr *hdr = (void *)skb->data;830bool offchannel = IEEE80211_SKB_CB(skb)->flags &831IEEE80211_TX_CTL_TX_OFFCHAN;832u32 link_id = u32_get_bits(info->control.flags,833IEEE80211_TX_CTRL_MLO_LINK);834struct ieee80211_sta *tmp_sta = sta;835836if (iwl_mvm_is_radio_killed(mvm)) {837IWL_DEBUG_DROP(mvm, "Dropping - RF/CT KILL\n");838goto drop;839}840841if (offchannel &&842!test_bit(IWL_MVM_STATUS_ROC_P2P_RUNNING, &mvm->status) &&843!test_bit(IWL_MVM_STATUS_ROC_AUX_RUNNING, &mvm->status))844goto drop;845846/*847* bufferable MMPDUs or MMPDUs on STA interfaces come via TXQs848* so we treat the others as broadcast849*/850if (ieee80211_is_mgmt(hdr->frame_control))851sta = NULL;852853/* this shouldn't even happen: just drop */854if (!sta && info->control.vif->type == NL80211_IFTYPE_STATION &&855!offchannel)856goto drop;857858if (tmp_sta && !sta && link_id != IEEE80211_LINK_UNSPECIFIED &&859!ieee80211_is_probe_resp(hdr->frame_control)) {860/* translate MLD addresses to LINK addresses */861struct ieee80211_link_sta *link_sta =862rcu_dereference(tmp_sta->link[link_id]);863struct ieee80211_bss_conf *link_conf =864rcu_dereference(info->control.vif->link_conf[link_id]);865struct ieee80211_mgmt *mgmt;866867if (WARN_ON(!link_sta || !link_conf))868goto drop;869870/* if sta is NULL, the frame is a management frame */871mgmt = (void *)hdr;872memcpy(mgmt->da, link_sta->addr, ETH_ALEN);873memcpy(mgmt->sa, link_conf->addr, ETH_ALEN);874memcpy(mgmt->bssid, link_conf->bssid, ETH_ALEN);875}876877iwl_mvm_tx_skb(mvm, skb, sta);878return;879drop:880ieee80211_free_txskb(hw, skb);881}882883void iwl_mvm_mac_itxq_xmit(struct ieee80211_hw *hw, struct ieee80211_txq *txq)884{885struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);886struct iwl_mvm_txq *mvmtxq = iwl_mvm_txq_from_mac80211(txq);887struct sk_buff *skb = NULL;888889/*890* No need for threads to be pending here, they can leave the first891* taker all the work.892*893* mvmtxq->tx_request logic:894*895* If 0, no one is currently TXing, set to 1 to indicate current thread896* will now start TX and other threads should quit.897*898* If 1, another thread is currently TXing, set to 2 to indicate to899* that thread that there was another request. Since that request may900* have raced with the check whether the queue is empty, the TXing901* thread should check the queue's status one more time before leaving.902* This check is done in order to not leave any TX hanging in the queue903* until the next TX invocation (which may not even happen).904*905* If 2, another thread is currently TXing, and it will already double906* check the queue, so do nothing.907*/908if (atomic_fetch_add_unless(&mvmtxq->tx_request, 1, 2))909return;910911rcu_read_lock();912do {913while (likely(!test_bit(IWL_MVM_TXQ_STATE_STOP_FULL,914&mvmtxq->state) &&915!test_bit(IWL_MVM_TXQ_STATE_STOP_REDIRECT,916&mvmtxq->state) &&917!test_bit(IWL_MVM_TXQ_STATE_STOP_AP_CSA,918&mvmtxq->state) &&919!test_bit(IWL_MVM_STATUS_IN_D3, &mvm->status))) {920skb = ieee80211_tx_dequeue(hw, txq);921922if (!skb) {923if (txq->sta)924IWL_DEBUG_TX(mvm,925"TXQ of sta %pM tid %d is now empty\n",926txq->sta->addr,927txq->tid);928break;929}930931iwl_mvm_tx_skb(mvm, skb, txq->sta);932}933} while (atomic_dec_return(&mvmtxq->tx_request));934rcu_read_unlock();935}936937void iwl_mvm_mac_wake_tx_queue(struct ieee80211_hw *hw,938struct ieee80211_txq *txq)939{940struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);941struct iwl_mvm_txq *mvmtxq = iwl_mvm_txq_from_mac80211(txq);942943if (likely(test_bit(IWL_MVM_TXQ_STATE_READY, &mvmtxq->state)) ||944!txq->sta) {945iwl_mvm_mac_itxq_xmit(hw, txq);946return;947}948949/* iwl_mvm_mac_itxq_xmit() will later be called by the worker950* to handle any packets we leave on the txq now951*/952953spin_lock_bh(&mvm->add_stream_lock);954/* The list is being deleted only after the queue is fully allocated. */955if (list_empty(&mvmtxq->list) &&956/* recheck under lock */957!test_bit(IWL_MVM_TXQ_STATE_READY, &mvmtxq->state)) {958list_add_tail(&mvmtxq->list, &mvm->add_stream_txqs);959schedule_work(&mvm->add_stream_wk);960}961spin_unlock_bh(&mvm->add_stream_lock);962}963964#define CHECK_BA_TRIGGER(_mvm, _trig, _tid_bm, _tid, _fmt...) \965do { \966if (!(le16_to_cpu(_tid_bm) & BIT(_tid))) \967break; \968iwl_fw_dbg_collect_trig(&(_mvm)->fwrt, _trig, _fmt); \969} while (0)970971static void972iwl_mvm_ampdu_check_trigger(struct iwl_mvm *mvm, struct ieee80211_vif *vif,973struct ieee80211_sta *sta, u16 tid, u16 rx_ba_ssn,974enum ieee80211_ampdu_mlme_action action)975{976struct iwl_fw_dbg_trigger_tlv *trig;977struct iwl_fw_dbg_trigger_ba *ba_trig;978979trig = iwl_fw_dbg_trigger_on(&mvm->fwrt, ieee80211_vif_to_wdev(vif),980FW_DBG_TRIGGER_BA);981if (!trig)982return;983984ba_trig = (void *)trig->data;985986switch (action) {987case IEEE80211_AMPDU_TX_OPERATIONAL: {988struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);989struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid];990991CHECK_BA_TRIGGER(mvm, trig, ba_trig->tx_ba_start, tid,992"TX AGG START: MAC %pM tid %d ssn %d\n",993sta->addr, tid, tid_data->ssn);994break;995}996case IEEE80211_AMPDU_TX_STOP_CONT:997CHECK_BA_TRIGGER(mvm, trig, ba_trig->tx_ba_stop, tid,998"TX AGG STOP: MAC %pM tid %d\n",999sta->addr, tid);1000break;1001case IEEE80211_AMPDU_RX_START:1002CHECK_BA_TRIGGER(mvm, trig, ba_trig->rx_ba_start, tid,1003"RX AGG START: MAC %pM tid %d ssn %d\n",1004sta->addr, tid, rx_ba_ssn);1005break;1006case IEEE80211_AMPDU_RX_STOP:1007CHECK_BA_TRIGGER(mvm, trig, ba_trig->rx_ba_stop, tid,1008"RX AGG STOP: MAC %pM tid %d\n",1009sta->addr, tid);1010break;1011default:1012break;1013}1014}10151016int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw,1017struct ieee80211_vif *vif,1018struct ieee80211_ampdu_params *params)1019{1020struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);1021int ret;1022struct ieee80211_sta *sta = params->sta;1023enum ieee80211_ampdu_mlme_action action = params->action;1024u16 tid = params->tid;1025u16 *ssn = ¶ms->ssn;1026u16 buf_size = params->buf_size;1027bool amsdu = params->amsdu;1028u16 timeout = params->timeout;10291030IWL_DEBUG_HT(mvm, "A-MPDU action on addr %pM tid %d: action %d\n",1031sta->addr, tid, action);10321033if (!(mvm->nvm_data->sku_cap_11n_enable))1034return -EACCES;10351036mutex_lock(&mvm->mutex);10371038switch (action) {1039case IEEE80211_AMPDU_RX_START:1040if (iwl_mvm_vif_from_mac80211(vif)->deflink.ap_sta_id ==1041iwl_mvm_sta_from_mac80211(sta)->deflink.sta_id) {1042struct iwl_mvm_vif *mvmvif;1043u16 macid = iwl_mvm_vif_from_mac80211(vif)->id;1044struct iwl_mvm_tcm_mac *mdata = &mvm->tcm.data[macid];10451046mdata->opened_rx_ba_sessions = true;1047mvmvif = iwl_mvm_vif_from_mac80211(vif);1048cancel_delayed_work(&mvmvif->uapsd_nonagg_detected_wk);1049}1050if (!iwl_enable_rx_ampdu()) {1051ret = -EINVAL;1052break;1053}1054ret = iwl_mvm_sta_rx_agg(mvm, sta, tid, *ssn, true, buf_size,1055timeout);1056break;1057case IEEE80211_AMPDU_RX_STOP:1058ret = iwl_mvm_sta_rx_agg(mvm, sta, tid, 0, false, buf_size,1059timeout);1060break;1061case IEEE80211_AMPDU_TX_START:1062if (!iwl_enable_tx_ampdu()) {1063ret = -EINVAL;1064break;1065}1066ret = iwl_mvm_sta_tx_agg_start(mvm, vif, sta, tid, ssn);1067break;1068case IEEE80211_AMPDU_TX_STOP_CONT:1069ret = iwl_mvm_sta_tx_agg_stop(mvm, vif, sta, tid);1070break;1071case IEEE80211_AMPDU_TX_STOP_FLUSH:1072case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:1073ret = iwl_mvm_sta_tx_agg_flush(mvm, vif, sta, tid);1074break;1075case IEEE80211_AMPDU_TX_OPERATIONAL:1076ret = iwl_mvm_sta_tx_agg_oper(mvm, vif, sta, tid,1077buf_size, amsdu);1078break;1079default:1080WARN_ON_ONCE(1);1081ret = -EINVAL;1082break;1083}10841085if (!ret) {1086u16 rx_ba_ssn = 0;10871088if (action == IEEE80211_AMPDU_RX_START)1089rx_ba_ssn = *ssn;10901091iwl_mvm_ampdu_check_trigger(mvm, vif, sta, tid,1092rx_ba_ssn, action);1093}1094mutex_unlock(&mvm->mutex);10951096return ret;1097}10981099static void iwl_mvm_cleanup_iterator(void *data, u8 *mac,1100struct ieee80211_vif *vif)1101{1102struct iwl_mvm *mvm = data;1103struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);1104struct iwl_probe_resp_data *probe_data;1105unsigned int link_id;11061107mvmvif->uploaded = false;11081109spin_lock_bh(&mvm->time_event_lock);1110iwl_mvm_te_clear_data(mvm, &mvmvif->time_event_data);1111spin_unlock_bh(&mvm->time_event_lock);11121113mvmvif->roc_activity = ROC_NUM_ACTIVITIES;11141115mvmvif->bf_enabled = false;1116mvmvif->ba_enabled = false;1117mvmvif->ap_sta = NULL;11181119mvmvif->esr_active = false;1120vif->driver_flags &= ~IEEE80211_VIF_EML_ACTIVE;11211122for_each_mvm_vif_valid_link(mvmvif, link_id) {1123mvmvif->link[link_id]->ap_sta_id = IWL_INVALID_STA;1124mvmvif->link[link_id]->fw_link_id = IWL_MVM_FW_LINK_ID_INVALID;1125mvmvif->link[link_id]->phy_ctxt = NULL;1126mvmvif->link[link_id]->active = 0;1127mvmvif->link[link_id]->igtk = NULL;1128memset(&mvmvif->link[link_id]->bf_data, 0,1129sizeof(mvmvif->link[link_id]->bf_data));1130}11311132probe_data = rcu_dereference_protected(mvmvif->deflink.probe_resp_data,1133lockdep_is_held(&mvm->mutex));1134if (probe_data)1135kfree_rcu(probe_data, rcu_head);1136RCU_INIT_POINTER(mvmvif->deflink.probe_resp_data, NULL);1137}11381139static void iwl_mvm_cleanup_sta_iterator(void *data, struct ieee80211_sta *sta)1140{1141struct iwl_mvm *mvm = data;1142struct iwl_mvm_sta *mvm_sta;1143struct ieee80211_vif *vif;1144int link_id;11451146mvm_sta = iwl_mvm_sta_from_mac80211(sta);1147vif = mvm_sta->vif;11481149if (!sta->valid_links)1150return;11511152for (link_id = 0; link_id < ARRAY_SIZE((sta)->link); link_id++) {1153struct iwl_mvm_link_sta *mvm_link_sta;11541155mvm_link_sta =1156rcu_dereference_check(mvm_sta->link[link_id],1157lockdep_is_held(&mvm->mutex));1158if (mvm_link_sta && !(vif->active_links & BIT(link_id))) {1159/*1160* We have a link STA but the link is inactive in1161* mac80211. This will happen if we failed to1162* deactivate the link but mac80211 roll back the1163* deactivation of the link.1164* Delete the stale data to avoid issues later on.1165*/1166iwl_mvm_mld_free_sta_link(mvm, mvm_sta, mvm_link_sta,1167link_id);1168}1169}1170}11711172static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm)1173{1174iwl_mvm_stop_device(mvm);11751176mvm->cur_aid = 0;11771178mvm->scan_status = 0;1179mvm->ps_disabled = false;1180mvm->rfkill_safe_init_done = false;11811182/* just in case one was running */1183iwl_mvm_cleanup_roc_te(mvm);1184ieee80211_remain_on_channel_expired(mvm->hw);11851186iwl_mvm_ftm_restart(mvm);11871188/*1189* cleanup all interfaces, even inactive ones, as some might have1190* gone down during the HW restart1191*/1192ieee80211_iterate_interfaces(mvm->hw, 0, iwl_mvm_cleanup_iterator, mvm);11931194/* cleanup stations as links may be gone after restart */1195ieee80211_iterate_stations_atomic(mvm->hw,1196iwl_mvm_cleanup_sta_iterator, mvm);11971198mvm->p2p_device_vif = NULL;11991200iwl_mvm_reset_phy_ctxts(mvm);1201memset(mvm->fw_key_table, 0, sizeof(mvm->fw_key_table));1202memset(&mvm->last_bt_notif, 0, sizeof(mvm->last_bt_notif));1203memset(&mvm->last_bt_ci_cmd, 0, sizeof(mvm->last_bt_ci_cmd));12041205ieee80211_wake_queues(mvm->hw);12061207mvm->rx_ba_sessions = 0;1208mvm->fwrt.dump.conf = FW_DBG_INVALID;1209mvm->monitor_on = false;1210#ifdef CONFIG_IWLWIFI_DEBUGFS1211mvm->beacon_inject_active = false;1212#endif12131214/* keep statistics ticking */1215iwl_mvm_accu_radio_stats(mvm);1216}12171218int __iwl_mvm_mac_start(struct iwl_mvm *mvm)1219{1220bool fast_resume = false;1221int ret;12221223lockdep_assert_held(&mvm->mutex);12241225ret = iwl_mvm_mei_get_ownership(mvm);1226if (ret)1227return ret;12281229if (mvm->mei_nvm_data) {1230/* We got the NIC, we can now free the MEI NVM data */1231kfree(mvm->mei_nvm_data);1232mvm->mei_nvm_data = NULL;12331234/*1235* We can't free the nvm_data we allocated based on the SAP1236* data because we registered to cfg80211 with the channels1237* allocated on mvm->nvm_data. Keep a pointer in temp_nvm_data1238* just in order to be able free it later.1239* NULLify nvm_data so that we will read the NVM from the1240* firmware this time.1241*/1242mvm->temp_nvm_data = mvm->nvm_data;1243mvm->nvm_data = NULL;1244}12451246#ifdef CONFIG_PM_SLEEP1247/* fast_resume will be cleared by iwl_mvm_fast_resume */1248fast_resume = mvm->fast_resume;12491250if (fast_resume) {1251iwl_mvm_mei_device_state(mvm, true);1252ret = iwl_mvm_fast_resume(mvm);1253if (ret) {1254iwl_mvm_stop_device(mvm);1255/* iwl_mvm_up() will be called further down */1256} else {1257/*1258* We clear IWL_MVM_STATUS_FIRMWARE_RUNNING upon1259* mac_down() so that debugfs will stop honoring1260* requests after we flush all the workers.1261* Set the IWL_MVM_STATUS_FIRMWARE_RUNNING bit again1262* now that we are back. This is a bit abusing the1263* flag since the firmware wasn't really ever stopped,1264* but this still serves the purpose.1265*/1266set_bit(IWL_MVM_STATUS_FIRMWARE_RUNNING, &mvm->status);1267}1268}1269#endif /* CONFIG_PM_SLEEP */12701271if (test_bit(IWL_MVM_STATUS_HW_RESTART_REQUESTED, &mvm->status)) {1272/*1273* Now convert the HW_RESTART_REQUESTED flag to IN_HW_RESTART1274* so later code will - from now on - see that we're doing it.1275*/1276set_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status);1277clear_bit(IWL_MVM_STATUS_HW_RESTART_REQUESTED, &mvm->status);1278/* Clean up some internal and mac80211 state on restart */1279iwl_mvm_restart_cleanup(mvm);1280}12811282/* we also want to load the firmware if fast_resume failed */1283if (!fast_resume || ret)1284ret = iwl_mvm_up(mvm);12851286iwl_dbg_tlv_time_point(&mvm->fwrt, IWL_FW_INI_TIME_POINT_POST_INIT,1287NULL);1288iwl_dbg_tlv_time_point(&mvm->fwrt, IWL_FW_INI_TIME_POINT_PERIODIC,1289NULL);12901291mvm->last_reset_or_resume_time_jiffies = jiffies;12921293if (ret && test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) {1294/* Something went wrong - we need to finish some cleanup1295* that normally iwl_mvm_mac_restart_complete() below1296* would do.1297*/1298clear_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status);1299}13001301return ret;1302}13031304int iwl_mvm_mac_start(struct ieee80211_hw *hw)1305{1306struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);1307int ret;1308int retry, max_retry = 0;13091310mutex_lock(&mvm->mutex);13111312/* we are starting the mac not in error flow, and restart is enabled */1313if (!test_bit(IWL_MVM_STATUS_HW_RESTART_REQUESTED, &mvm->status) &&1314iwlwifi_mod_params.fw_restart)1315max_retry = IWL_MAX_INIT_RETRY;13161317for (retry = 0; retry <= max_retry; retry++) {1318ret = __iwl_mvm_mac_start(mvm);1319if (ret != -ETIMEDOUT)1320break;13211322IWL_ERR(mvm, "mac start retry %d\n", retry);1323}13241325mutex_unlock(&mvm->mutex);13261327iwl_mvm_mei_set_sw_rfkill_state(mvm);13281329return ret;1330}13311332static void iwl_mvm_restart_complete(struct iwl_mvm *mvm)1333{1334int ret;13351336guard(mvm)(mvm);13371338clear_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status);13391340ret = iwl_mvm_update_quotas(mvm, true, NULL);1341if (ret)1342IWL_ERR(mvm, "Failed to update quotas after restart (%d)\n",1343ret);13441345iwl_mvm_send_recovery_cmd(mvm, ERROR_RECOVERY_END_OF_RECOVERY);13461347/*1348* If we have TDLS peers, remove them. We don't know the last seqno/PN1349* of packets the FW sent out, so we must reconnect.1350*/1351iwl_mvm_teardown_tdls_peers(mvm);13521353IWL_INFO(mvm, "restart completed\n");1354iwl_trans_finish_sw_reset(mvm->trans);13551356/* no need to lock, adding in parallel would schedule too */1357if (!list_empty(&mvm->add_stream_txqs))1358schedule_work(&mvm->add_stream_wk);1359}13601361void iwl_mvm_mac_reconfig_complete(struct ieee80211_hw *hw,1362enum ieee80211_reconfig_type reconfig_type)1363{1364struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);13651366switch (reconfig_type) {1367case IEEE80211_RECONFIG_TYPE_RESTART:1368iwl_mvm_restart_complete(mvm);1369break;1370case IEEE80211_RECONFIG_TYPE_SUSPEND:1371break;1372}1373}13741375void __iwl_mvm_mac_stop(struct iwl_mvm *mvm, bool suspend)1376{1377lockdep_assert_held(&mvm->mutex);13781379iwl_mvm_ftm_initiator_smooth_stop(mvm);13801381/* firmware counters are obviously reset now, but we shouldn't1382* partially track so also clear the fw_reset_accu counters.1383*/1384memset(&mvm->accu_radio_stats, 0, sizeof(mvm->accu_radio_stats));13851386/* async_handlers_wk is now blocked */13871388if (!iwl_mvm_has_new_station_api(mvm->fw))1389iwl_mvm_rm_aux_sta(mvm);13901391if (suspend &&1392mvm->trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_22000) {1393iwl_mvm_fast_suspend(mvm);1394/* From this point on, we won't touch the device */1395iwl_mvm_mei_device_state(mvm, false);1396} else {1397iwl_mvm_stop_device(mvm);1398}13991400iwl_mvm_async_handlers_purge(mvm);1401/* async_handlers_list is empty and will stay empty: HW is stopped */14021403/*1404* Clear IN_HW_RESTART and HW_RESTART_REQUESTED flag when stopping the1405* hw (as restart_complete() won't be called in this case) and mac802111406* won't execute the restart.1407* But make sure to cleanup interfaces that have gone down before/during1408* HW restart was requested.1409*/1410if (test_and_clear_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) ||1411test_and_clear_bit(IWL_MVM_STATUS_HW_RESTART_REQUESTED,1412&mvm->status))1413ieee80211_iterate_interfaces(mvm->hw, 0,1414iwl_mvm_cleanup_iterator, mvm);14151416/* We shouldn't have any UIDs still set. Loop over all the UIDs to1417* make sure there's nothing left there and warn if any is found.1418*/1419if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_UMAC_SCAN)) {1420int i;14211422for (i = 0; i < mvm->max_scans; i++) {1423if (WARN_ONCE(mvm->scan_uid_status[i],1424"UMAC scan UID %d status was not cleaned\n",1425i))1426mvm->scan_uid_status[i] = 0;1427}1428}1429}14301431void iwl_mvm_mac_stop(struct ieee80211_hw *hw, bool suspend)1432{1433struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);14341435/* Stop internal MLO scan, if running */1436mutex_lock(&mvm->mutex);1437iwl_mvm_scan_stop(mvm, IWL_MVM_SCAN_INT_MLO, false);1438mutex_unlock(&mvm->mutex);14391440wiphy_work_cancel(mvm->hw->wiphy, &mvm->trig_link_selection_wk);1441wiphy_work_flush(mvm->hw->wiphy, &mvm->async_handlers_wiphy_wk);1442flush_work(&mvm->async_handlers_wk);1443flush_work(&mvm->add_stream_wk);14441445/*1446* Lock and clear the firmware running bit here already, so that1447* new commands coming in elsewhere, e.g. from debugfs, will not1448* be able to proceed. This is important here because one of those1449* debugfs files causes the firmware dump to be triggered, and if we1450* don't stop debugfs accesses before canceling that it could be1451* retriggered after we flush it but before we've cleared the bit.1452*/1453clear_bit(IWL_MVM_STATUS_FIRMWARE_RUNNING, &mvm->status);14541455cancel_delayed_work_sync(&mvm->cs_tx_unblock_dwork);1456cancel_delayed_work_sync(&mvm->scan_timeout_dwork);14571458/*1459* The work item could be running or queued if the1460* ROC time event stops just as we get here.1461*/1462flush_work(&mvm->roc_done_wk);14631464iwl_mvm_mei_set_sw_rfkill_state(mvm);14651466mutex_lock(&mvm->mutex);1467__iwl_mvm_mac_stop(mvm, suspend);1468mutex_unlock(&mvm->mutex);14691470/*1471* The worker might have been waiting for the mutex, let it run and1472* discover that its list is now empty.1473*/1474cancel_work_sync(&mvm->async_handlers_wk);1475wiphy_work_cancel(hw->wiphy, &mvm->async_handlers_wiphy_wk);1476}14771478struct iwl_mvm_phy_ctxt *iwl_mvm_get_free_phy_ctxt(struct iwl_mvm *mvm)1479{1480u16 i;14811482lockdep_assert_held(&mvm->mutex);14831484for (i = 0; i < NUM_PHY_CTX; i++)1485if (!mvm->phy_ctxts[i].ref)1486return &mvm->phy_ctxts[i];14871488IWL_ERR(mvm, "No available PHY context\n");1489return NULL;1490}14911492int iwl_mvm_set_tx_power(struct iwl_mvm *mvm,1493struct ieee80211_bss_conf *link_conf,1494s16 tx_power)1495{1496u32 cmd_id = REDUCE_TX_POWER_CMD;1497struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(link_conf->vif);1498u32 mac_id = mvmvif->id;1499int len;1500struct iwl_dev_tx_power_cmd_v3_v8 cmd = {1501.common.set_mode = cpu_to_le32(IWL_TX_POWER_MODE_SET_LINK),1502.common.link_id = cpu_to_le32(mac_id),1503};1504struct iwl_dev_tx_power_cmd cmd_v9_v10;1505u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, cmd_id, 3);1506u16 u_tx_power = tx_power == IWL_DEFAULT_MAX_TX_POWER ?1507IWL_DEV_MAX_TX_POWER : 8 * tx_power;1508void *cmd_data = &cmd;15091510cmd.common.pwr_restriction = cpu_to_le16(u_tx_power);15111512if (cmd_ver > 8) {1513u32 link_id;15141515if (WARN_ON(!mvmvif->link[link_conf->link_id]))1516return -ENODEV;15171518link_id = mvmvif->link[link_conf->link_id]->fw_link_id;15191520/* Those fields sit on the same place for v9 and v10 */1521cmd_v9_v10.common.set_mode = cpu_to_le32(IWL_TX_POWER_MODE_SET_LINK);1522cmd_v9_v10.common.link_id = cpu_to_le32(link_id);1523cmd_v9_v10.common.pwr_restriction = cpu_to_le16(u_tx_power);1524cmd_data = &cmd_v9_v10;1525}15261527if (cmd_ver == 10)1528len = sizeof(cmd_v9_v10.v10);1529else if (cmd_ver == 9)1530len = sizeof(cmd_v9_v10.v9);1531else if (cmd_ver == 8)1532len = sizeof(cmd.v8);1533else if (fw_has_api(&mvm->fw->ucode_capa,1534IWL_UCODE_TLV_API_REDUCE_TX_POWER))1535len = sizeof(cmd.v5);1536else if (fw_has_capa(&mvm->fw->ucode_capa,1537IWL_UCODE_TLV_CAPA_TX_POWER_ACK))1538len = sizeof(cmd.v4);1539else1540len = sizeof(cmd.v3);15411542/* all structs have the same common part, add its length */1543len += sizeof(cmd.common);15441545if (cmd_ver < 9)1546len += sizeof(cmd.per_band);15471548return iwl_mvm_send_cmd_pdu(mvm, cmd_id, 0, len, cmd_data);15491550}15511552static void iwl_mvm_post_csa_tx(void *data, struct ieee80211_sta *sta)1553{1554struct ieee80211_hw *hw = data;1555int i;15561557for (i = 0; i < ARRAY_SIZE(sta->txq); i++) {1558struct iwl_mvm_txq *mvmtxq =1559iwl_mvm_txq_from_mac80211(sta->txq[i]);15601561clear_bit(IWL_MVM_TXQ_STATE_STOP_AP_CSA, &mvmtxq->state);1562iwl_mvm_mac_itxq_xmit(hw, sta->txq[i]);1563}1564}15651566int iwl_mvm_post_channel_switch(struct ieee80211_hw *hw,1567struct ieee80211_vif *vif,1568struct ieee80211_bss_conf *link_conf)1569{1570struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);1571struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);1572int ret;15731574mutex_lock(&mvm->mutex);15751576if (vif->type == NL80211_IFTYPE_STATION) {1577struct iwl_mvm_sta *mvmsta;1578unsigned int link_id = link_conf->link_id;1579u8 ap_sta_id = mvmvif->link[link_id]->ap_sta_id;15801581mvmvif->csa_bcn_pending = false;1582mvmvif->csa_blocks_tx = false;1583mvmsta = iwl_mvm_sta_from_staid_protected(mvm, ap_sta_id);15841585if (WARN_ON(!mvmsta)) {1586ret = -EIO;1587goto out_unlock;1588}15891590iwl_mvm_sta_modify_disable_tx(mvm, mvmsta, false);1591if (mvm->mld_api_is_used)1592iwl_mvm_mld_mac_ctxt_changed(mvm, vif, false);1593else1594iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL);15951596if (!fw_has_capa(&mvm->fw->ucode_capa,1597IWL_UCODE_TLV_CAPA_CHANNEL_SWITCH_CMD)) {1598ret = iwl_mvm_enable_beacon_filter(mvm, vif);1599if (ret)1600goto out_unlock;16011602iwl_mvm_stop_session_protection(mvm, vif);1603}1604} else if (vif->type == NL80211_IFTYPE_AP && mvmvif->csa_blocks_tx) {1605struct iwl_mvm_txq *mvmtxq =1606iwl_mvm_txq_from_mac80211(vif->txq);16071608clear_bit(IWL_MVM_TXQ_STATE_STOP_AP_CSA, &mvmtxq->state);16091610local_bh_disable();1611iwl_mvm_mac_itxq_xmit(hw, vif->txq);1612ieee80211_iterate_stations_atomic(hw, iwl_mvm_post_csa_tx, hw);1613local_bh_enable();16141615mvmvif->csa_blocks_tx = false;1616}16171618mvmvif->ps_disabled = false;16191620ret = iwl_mvm_power_update_ps(mvm);16211622out_unlock:1623if (mvmvif->csa_failed)1624ret = -EIO;1625mutex_unlock(&mvm->mutex);16261627return ret;1628}16291630void iwl_mvm_abort_channel_switch(struct ieee80211_hw *hw,1631struct ieee80211_vif *vif,1632struct ieee80211_bss_conf *link_conf)1633{1634struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);1635struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);1636struct iwl_chan_switch_te_cmd cmd = {1637.mac_id = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id,1638mvmvif->color)),1639.action = cpu_to_le32(FW_CTXT_ACTION_REMOVE),1640};16411642/*1643* In the new flow since FW is in charge of the timing,1644* if driver has canceled the channel switch he will receive the1645* CHANNEL_SWITCH_START_NOTIF notification from FW and then cancel it1646*/1647if (iwl_fw_lookup_notif_ver(mvm->fw, MAC_CONF_GROUP,1648CHANNEL_SWITCH_ERROR_NOTIF, 0))1649return;16501651IWL_DEBUG_MAC80211(mvm, "Abort CSA on mac %d\n", mvmvif->id);16521653mutex_lock(&mvm->mutex);1654if (!fw_has_capa(&mvm->fw->ucode_capa,1655IWL_UCODE_TLV_CAPA_CHANNEL_SWITCH_CMD))1656iwl_mvm_remove_csa_period(mvm, vif);1657else1658WARN_ON(iwl_mvm_send_cmd_pdu(mvm,1659WIDE_ID(MAC_CONF_GROUP,1660CHANNEL_SWITCH_TIME_EVENT_CMD),16610, sizeof(cmd), &cmd));1662mvmvif->csa_failed = true;1663mutex_unlock(&mvm->mutex);16641665/* If we're here, we can't support MLD */1666iwl_mvm_post_channel_switch(hw, vif, &vif->bss_conf);1667}16681669void iwl_mvm_channel_switch_disconnect_wk(struct work_struct *wk)1670{1671struct iwl_mvm_vif *mvmvif;1672struct ieee80211_vif *vif;16731674mvmvif = container_of(wk, struct iwl_mvm_vif, csa_work.work);1675vif = container_of((void *)mvmvif, struct ieee80211_vif, drv_priv);16761677/* Trigger disconnect (should clear the CSA state) */1678ieee80211_chswitch_done(vif, false, 0);1679}16801681static u81682iwl_mvm_chandef_get_primary_80(struct cfg80211_chan_def *chandef)1683{1684int data_start;1685int control_start;1686int bw;16871688if (chandef->width == NL80211_CHAN_WIDTH_320)1689bw = 320;1690else if (chandef->width == NL80211_CHAN_WIDTH_160)1691bw = 160;1692else1693return 0;16941695/* data is bw wide so the start is half the width */1696data_start = chandef->center_freq1 - bw / 2;1697/* control is 20Mhz width */1698control_start = chandef->chan->center_freq - 10;16991700return (control_start - data_start) / 80;1701}17021703static int iwl_mvm_alloc_bcast_mcast_sta(struct iwl_mvm *mvm,1704struct ieee80211_vif *vif)1705{1706struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);1707int ret;17081709lockdep_assert_held(&mvm->mutex);17101711ret = iwl_mvm_alloc_bcast_sta(mvm, vif);1712if (ret) {1713IWL_ERR(mvm, "Failed to allocate bcast sta\n");1714return ret;1715}17161717/* Only queue for this station is the mcast queue,1718* which shouldn't be in TFD mask anyway1719*/1720return iwl_mvm_allocate_int_sta(mvm, &mvmvif->deflink.mcast_sta, 0,1721vif->type,1722IWL_STA_MULTICAST);1723}17241725static void iwl_mvm_prevent_esr_done_wk(struct wiphy *wiphy,1726struct wiphy_work *wk)1727{1728struct iwl_mvm_vif *mvmvif =1729container_of(wk, struct iwl_mvm_vif, prevent_esr_done_wk.work);1730struct iwl_mvm *mvm = mvmvif->mvm;1731struct ieee80211_vif *vif =1732container_of((void *)mvmvif, struct ieee80211_vif, drv_priv);17331734guard(mvm)(mvm);1735iwl_mvm_unblock_esr(mvm, vif, IWL_MVM_ESR_BLOCKED_PREVENTION);1736}17371738static void iwl_mvm_mlo_int_scan_wk(struct wiphy *wiphy, struct wiphy_work *wk)1739{1740struct iwl_mvm_vif *mvmvif = container_of(wk, struct iwl_mvm_vif,1741mlo_int_scan_wk.work);1742struct ieee80211_vif *vif =1743container_of((void *)mvmvif, struct ieee80211_vif, drv_priv);17441745guard(mvm)(mvmvif->mvm);1746iwl_mvm_int_mlo_scan(mvmvif->mvm, vif);1747}17481749static void iwl_mvm_unblock_esr_tpt(struct wiphy *wiphy, struct wiphy_work *wk)1750{1751struct iwl_mvm_vif *mvmvif =1752container_of(wk, struct iwl_mvm_vif, unblock_esr_tpt_wk);1753struct iwl_mvm *mvm = mvmvif->mvm;1754struct ieee80211_vif *vif =1755container_of((void *)mvmvif, struct ieee80211_vif, drv_priv);17561757guard(mvm)(mvm);1758iwl_mvm_unblock_esr(mvm, vif, IWL_MVM_ESR_BLOCKED_TPT);1759}17601761static void iwl_mvm_unblock_esr_tmp_non_bss(struct wiphy *wiphy,1762struct wiphy_work *wk)1763{1764struct iwl_mvm_vif *mvmvif =1765container_of(wk, struct iwl_mvm_vif,1766unblock_esr_tmp_non_bss_wk.work);1767struct iwl_mvm *mvm = mvmvif->mvm;1768struct ieee80211_vif *vif =1769container_of((void *)mvmvif, struct ieee80211_vif, drv_priv);17701771mutex_lock(&mvm->mutex);1772iwl_mvm_unblock_esr(mvm, vif, IWL_MVM_ESR_BLOCKED_TMP_NON_BSS);1773mutex_unlock(&mvm->mutex);1774}17751776void iwl_mvm_mac_init_mvmvif(struct iwl_mvm *mvm, struct iwl_mvm_vif *mvmvif)1777{1778lockdep_assert_held(&mvm->mutex);17791780if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))1781return;17821783mvmvif->deflink.average_beacon_energy = 0;17841785INIT_DELAYED_WORK(&mvmvif->csa_work,1786iwl_mvm_channel_switch_disconnect_wk);17871788wiphy_delayed_work_init(&mvmvif->prevent_esr_done_wk,1789iwl_mvm_prevent_esr_done_wk);17901791wiphy_delayed_work_init(&mvmvif->mlo_int_scan_wk,1792iwl_mvm_mlo_int_scan_wk);17931794wiphy_work_init(&mvmvif->unblock_esr_tpt_wk,1795iwl_mvm_unblock_esr_tpt);17961797wiphy_delayed_work_init(&mvmvif->unblock_esr_tmp_non_bss_wk,1798iwl_mvm_unblock_esr_tmp_non_bss);1799}18001801static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,1802struct ieee80211_vif *vif)1803{1804struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);1805struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);1806int ret;1807int i;18081809mutex_lock(&mvm->mutex);18101811iwl_mvm_mac_init_mvmvif(mvm, mvmvif);18121813mvmvif->mvm = mvm;18141815/* the first link always points to the default one */1816mvmvif->deflink.fw_link_id = IWL_MVM_FW_LINK_ID_INVALID;1817mvmvif->deflink.active = 0;1818mvmvif->link[0] = &mvmvif->deflink;18191820vif->driver_flags = IEEE80211_VIF_REMOVE_AP_AFTER_DISASSOC;18211822iwl_mvm_set_link_fw_id(mvm, vif, &vif->bss_conf);18231824/*1825* Not much to do here. The stack will not allow interface1826* types or combinations that we didn't advertise, so we1827* don't really have to check the types.1828*/18291830/* make sure that beacon statistics don't go backwards with FW reset */1831if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))1832for_each_mvm_vif_valid_link(mvmvif, i)1833mvmvif->link[i]->beacon_stats.accu_num_beacons +=1834mvmvif->link[i]->beacon_stats.num_beacons;18351836/* Allocate resources for the MAC context, and add it to the fw */1837ret = iwl_mvm_mac_ctxt_init(mvm, vif);1838if (ret)1839goto out;18401841rcu_assign_pointer(mvm->vif_id_to_mac[mvmvif->id], vif);18421843/*1844* The AP binding flow can be done only after the beacon1845* template is configured (which happens only in the mac802111846* start_ap() flow), and adding the broadcast station can happen1847* only after the binding.1848* In addition, since modifying the MAC before adding a bcast1849* station is not allowed by the FW, delay the adding of MAC context to1850* the point where we can also add the bcast station.1851* In short: there's not much we can do at this point, other than1852* allocating resources :)1853*/1854if (vif->type == NL80211_IFTYPE_AP ||1855vif->type == NL80211_IFTYPE_ADHOC) {1856if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))1857iwl_mvm_vif_dbgfs_add_link(mvm, vif);1858ret = 0;1859goto out;1860}18611862mvmvif->features |= hw->netdev_features;18631864ret = iwl_mvm_mac_ctxt_add(mvm, vif);1865if (ret)1866goto out_unlock;18671868ret = iwl_mvm_power_update_mac(mvm);1869if (ret)1870goto out_remove_mac;18711872/* beacon filtering */1873ret = iwl_mvm_disable_beacon_filter(mvm, vif);1874if (ret)1875goto out_remove_mac;18761877if (!mvm->bf_allowed_vif &&1878vif->type == NL80211_IFTYPE_STATION && !vif->p2p) {1879mvm->bf_allowed_vif = mvmvif;1880vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER |1881IEEE80211_VIF_SUPPORTS_CQM_RSSI;1882}18831884if (vif->type == NL80211_IFTYPE_P2P_DEVICE)1885mvm->p2p_device_vif = vif;18861887iwl_mvm_tcm_add_vif(mvm, vif);18881889if (vif->type == NL80211_IFTYPE_MONITOR) {1890mvm->monitor_on = true;1891mvm->monitor_p80 =1892iwl_mvm_chandef_get_primary_80(&vif->bss_conf.chanreq.oper);1893}18941895if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))1896iwl_mvm_vif_dbgfs_add_link(mvm, vif);18971898if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) &&1899vif->type == NL80211_IFTYPE_STATION && !vif->p2p &&1900!mvm->csme_vif && mvm->mei_registered) {1901iwl_mei_set_nic_info(vif->addr, mvm->nvm_data->hw_addr);1902iwl_mei_set_netdev(ieee80211_vif_to_wdev(vif)->netdev);1903mvm->csme_vif = vif;1904}19051906out:1907if (!ret && (vif->type == NL80211_IFTYPE_AP ||1908vif->type == NL80211_IFTYPE_ADHOC))1909ret = iwl_mvm_alloc_bcast_mcast_sta(mvm, vif);19101911goto out_unlock;19121913out_remove_mac:1914mvmvif->deflink.phy_ctxt = NULL;1915iwl_mvm_mac_ctxt_remove(mvm, vif);1916out_unlock:1917mutex_unlock(&mvm->mutex);19181919return ret;1920}19211922void iwl_mvm_prepare_mac_removal(struct iwl_mvm *mvm,1923struct ieee80211_vif *vif)1924{1925struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);19261927if (vif->type == NL80211_IFTYPE_P2P_DEVICE) {1928/*1929* Flush the ROC worker which will flush the OFFCHANNEL queue.1930* We assume here that all the packets sent to the OFFCHANNEL1931* queue are sent in ROC session.1932*/1933flush_work(&mvm->roc_done_wk);1934}19351936wiphy_delayed_work_cancel(mvm->hw->wiphy,1937&mvmvif->prevent_esr_done_wk);19381939wiphy_delayed_work_cancel(mvm->hw->wiphy,1940&mvmvif->mlo_int_scan_wk);19411942wiphy_work_cancel(mvm->hw->wiphy, &mvmvif->unblock_esr_tpt_wk);1943wiphy_delayed_work_cancel(mvm->hw->wiphy,1944&mvmvif->unblock_esr_tmp_non_bss_wk);19451946cancel_delayed_work_sync(&mvmvif->csa_work);1947}19481949static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw,1950struct ieee80211_vif *vif)1951{1952struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);1953struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);1954struct iwl_probe_resp_data *probe_data;19551956iwl_mvm_prepare_mac_removal(mvm, vif);19571958if (!(vif->type == NL80211_IFTYPE_AP ||1959vif->type == NL80211_IFTYPE_ADHOC))1960iwl_mvm_tcm_rm_vif(mvm, vif);19611962mutex_lock(&mvm->mutex);19631964if (vif == mvm->csme_vif) {1965iwl_mei_set_netdev(NULL);1966mvm->csme_vif = NULL;1967}19681969probe_data = rcu_dereference_protected(mvmvif->deflink.probe_resp_data,1970lockdep_is_held(&mvm->mutex));1971RCU_INIT_POINTER(mvmvif->deflink.probe_resp_data, NULL);1972if (probe_data)1973kfree_rcu(probe_data, rcu_head);19741975if (mvm->bf_allowed_vif == mvmvif) {1976mvm->bf_allowed_vif = NULL;1977vif->driver_flags &= ~(IEEE80211_VIF_BEACON_FILTER |1978IEEE80211_VIF_SUPPORTS_CQM_RSSI);1979}19801981if (vif->bss_conf.ftm_responder)1982memset(&mvm->ftm_resp_stats, 0, sizeof(mvm->ftm_resp_stats));19831984iwl_mvm_vif_dbgfs_rm_link(mvm, vif);19851986/*1987* For AP/GO interface, the tear down of the resources allocated to the1988* interface is be handled as part of the stop_ap flow.1989*/1990if (vif->type == NL80211_IFTYPE_AP ||1991vif->type == NL80211_IFTYPE_ADHOC)1992goto out;19931994iwl_mvm_power_update_mac(mvm);19951996/* Before the interface removal, mac80211 would cancel the ROC, and the1997* ROC worker would be scheduled if needed. The worker would be flushed1998* in iwl_mvm_prepare_mac_removal() and thus at this point there is no1999* binding etc. so nothing needs to be done here.2000*/2001if (vif->type == NL80211_IFTYPE_P2P_DEVICE) {2002if (mvmvif->deflink.phy_ctxt) {2003iwl_mvm_phy_ctxt_unref(mvm, mvmvif->deflink.phy_ctxt);2004mvmvif->deflink.phy_ctxt = NULL;2005}2006mvm->p2p_device_vif = NULL;2007}20082009iwl_mvm_mac_ctxt_remove(mvm, vif);20102011RCU_INIT_POINTER(mvm->vif_id_to_mac[mvmvif->id], NULL);20122013if (vif->type == NL80211_IFTYPE_MONITOR)2014mvm->monitor_on = false;20152016out:2017if (vif->type == NL80211_IFTYPE_AP ||2018vif->type == NL80211_IFTYPE_ADHOC) {2019iwl_mvm_dealloc_int_sta(mvm, &mvmvif->deflink.mcast_sta);2020iwl_mvm_dealloc_bcast_sta(mvm, vif);2021}20222023mutex_unlock(&mvm->mutex);2024}20252026struct iwl_mvm_mc_iter_data {2027struct iwl_mvm *mvm;2028int port_id;2029};20302031static void iwl_mvm_mc_iface_iterator(void *_data, u8 *mac,2032struct ieee80211_vif *vif)2033{2034struct iwl_mvm_mc_iter_data *data = _data;2035struct iwl_mvm *mvm = data->mvm;2036struct iwl_mcast_filter_cmd *cmd = mvm->mcast_filter_cmd;2037struct iwl_host_cmd hcmd = {2038.id = MCAST_FILTER_CMD,2039.flags = CMD_ASYNC,2040.dataflags[0] = IWL_HCMD_DFL_NOCOPY,2041};2042int ret, len;20432044/* if we don't have free ports, mcast frames will be dropped */2045if (WARN_ON_ONCE(data->port_id >= MAX_PORT_ID_NUM))2046return;20472048if (vif->type != NL80211_IFTYPE_STATION ||2049!vif->cfg.assoc)2050return;20512052cmd->port_id = data->port_id++;2053memcpy(cmd->bssid, vif->bss_conf.bssid, ETH_ALEN);2054len = roundup(sizeof(*cmd) + cmd->count * ETH_ALEN, 4);20552056hcmd.len[0] = len;2057hcmd.data[0] = cmd;20582059ret = iwl_mvm_send_cmd(mvm, &hcmd);2060if (ret)2061IWL_ERR(mvm, "mcast filter cmd error. ret=%d\n", ret);2062}20632064static void iwl_mvm_recalc_multicast(struct iwl_mvm *mvm)2065{2066struct iwl_mvm_mc_iter_data iter_data = {2067.mvm = mvm,2068};2069int ret;20702071lockdep_assert_held(&mvm->mutex);20722073if (WARN_ON_ONCE(!mvm->mcast_filter_cmd))2074return;20752076ieee80211_iterate_active_interfaces_atomic(2077mvm->hw, IEEE80211_IFACE_ITER_NORMAL,2078iwl_mvm_mc_iface_iterator, &iter_data);20792080/*2081* Send a (synchronous) ech command so that we wait for the2082* multiple asynchronous MCAST_FILTER_CMD commands sent by2083* the interface iterator. Otherwise, we might get here over2084* and over again (by userspace just sending a lot of these)2085* and the CPU can send them faster than the firmware can2086* process them.2087* Note that the CPU is still faster - but with this we'll2088* actually send fewer commands overall because the CPU will2089* not schedule the work in mac80211 as frequently if it's2090* still running when rescheduled (possibly multiple times).2091*/2092ret = iwl_mvm_send_cmd_pdu(mvm, ECHO_CMD, 0, 0, NULL);2093if (ret)2094IWL_ERR(mvm, "Failed to synchronize multicast groups update\n");2095}20962097u64 iwl_mvm_prepare_multicast(struct ieee80211_hw *hw,2098struct netdev_hw_addr_list *mc_list)2099{2100struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);2101struct iwl_mcast_filter_cmd *cmd;2102struct netdev_hw_addr *addr;2103int addr_count;2104bool pass_all;2105int len;21062107addr_count = netdev_hw_addr_list_count(mc_list);2108pass_all = addr_count > MAX_MCAST_FILTERING_ADDRESSES ||2109IWL_MVM_FW_MCAST_FILTER_PASS_ALL;2110if (pass_all)2111addr_count = 0;21122113len = roundup(sizeof(*cmd) + addr_count * ETH_ALEN, 4);2114cmd = kzalloc(len, GFP_ATOMIC);2115if (!cmd)2116return 0;21172118if (pass_all) {2119cmd->pass_all = 1;2120#if defined(__linux__)2121return (u64)(unsigned long)cmd;2122#elif defined(__FreeBSD__)2123return (u64)(uintptr_t)cmd;2124#endif2125}21262127netdev_hw_addr_list_for_each(addr, mc_list) {2128#if defined(__linux__)2129IWL_DEBUG_MAC80211(mvm, "mcast addr (%d): %pM\n",2130cmd->count, addr->addr);2131#elif defined(__FreeBSD__)2132IWL_DEBUG_MAC80211(mvm, "mcast addr (%d): %6D\n",2133cmd->count, addr->addr, ":");2134#endif2135memcpy(&cmd->addr_list[cmd->count * ETH_ALEN],2136addr->addr, ETH_ALEN);2137cmd->count++;2138}21392140#if defined(__linux__)2141return (u64)(unsigned long)cmd;2142#elif defined(__FreeBSD__)2143return (u64)(uintptr_t)cmd;2144#endif2145}21462147void iwl_mvm_configure_filter(struct ieee80211_hw *hw,2148unsigned int changed_flags,2149unsigned int *total_flags, u64 multicast)2150{2151struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);2152#if defined(__linux__)2153struct iwl_mcast_filter_cmd *cmd = (void *)(unsigned long)multicast;2154#elif defined(__FreeBSD__)2155struct iwl_mcast_filter_cmd *cmd = (void *)(uintptr_t)multicast;2156#endif21572158guard(mvm)(mvm);21592160/* replace previous configuration */2161kfree(mvm->mcast_filter_cmd);2162mvm->mcast_filter_cmd = cmd;21632164if (!cmd)2165goto out;21662167if (changed_flags & FIF_ALLMULTI)2168cmd->pass_all = !!(*total_flags & FIF_ALLMULTI);21692170if (cmd->pass_all)2171cmd->count = 0;21722173iwl_mvm_recalc_multicast(mvm);2174out:2175*total_flags = 0;2176}21772178static void iwl_mvm_config_iface_filter(struct ieee80211_hw *hw,2179struct ieee80211_vif *vif,2180unsigned int filter_flags,2181unsigned int changed_flags)2182{2183struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);21842185/* We support only filter for probe requests */2186if (!(changed_flags & FIF_PROBE_REQ))2187return;21882189/* Supported only for p2p client interfaces */2190if (vif->type != NL80211_IFTYPE_STATION || !vif->cfg.assoc ||2191!vif->p2p)2192return;21932194guard(mvm)(mvm);2195iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL);2196}21972198int iwl_mvm_update_mu_groups(struct iwl_mvm *mvm, struct ieee80211_vif *vif)2199{2200struct iwl_mu_group_mgmt_cmd cmd = {};22012202memcpy(cmd.membership_status, vif->bss_conf.mu_group.membership,2203WLAN_MEMBERSHIP_LEN);2204memcpy(cmd.user_position, vif->bss_conf.mu_group.position,2205WLAN_USER_POSITION_LEN);22062207return iwl_mvm_send_cmd_pdu(mvm,2208WIDE_ID(DATA_PATH_GROUP,2209UPDATE_MU_GROUPS_CMD),22100, sizeof(cmd), &cmd);2211}22122213static void iwl_mvm_mu_mimo_iface_iterator(void *_data, u8 *mac,2214struct ieee80211_vif *vif)2215{2216if (vif->bss_conf.mu_mimo_owner) {2217struct iwl_mu_group_mgmt_notif *notif = _data;22182219/*2220* MU-MIMO Group Id action frame is little endian. We treat2221* the data received from firmware as if it came from the2222* action frame, so no conversion is needed.2223*/2224ieee80211_update_mu_groups(vif, 0,2225(u8 *)¬if->membership_status,2226(u8 *)¬if->user_position);2227}2228}22292230void iwl_mvm_mu_mimo_grp_notif(struct iwl_mvm *mvm,2231struct iwl_rx_cmd_buffer *rxb)2232{2233struct iwl_rx_packet *pkt = rxb_addr(rxb);2234struct iwl_mu_group_mgmt_notif *notif = (void *)pkt->data;22352236ieee80211_iterate_active_interfaces_atomic(2237mvm->hw, IEEE80211_IFACE_ITER_NORMAL,2238iwl_mvm_mu_mimo_iface_iterator, notif);2239}22402241static u8 iwl_mvm_he_get_ppe_val(u8 *ppe, u8 ppe_pos_bit)2242{2243u8 byte_num = ppe_pos_bit / 8;2244u8 bit_num = ppe_pos_bit % 8;2245u8 residue_bits;2246u8 res;22472248if (bit_num <= 5)2249return (ppe[byte_num] >> bit_num) &2250(BIT(IEEE80211_PPE_THRES_INFO_PPET_SIZE) - 1);22512252/*2253* If bit_num > 5, we have to combine bits with next byte.2254* Calculate how many bits we need to take from current byte (called2255* here "residue_bits"), and add them to bits from next byte.2256*/22572258residue_bits = 8 - bit_num;22592260res = (ppe[byte_num + 1] &2261(BIT(IEEE80211_PPE_THRES_INFO_PPET_SIZE - residue_bits) - 1)) <<2262residue_bits;2263res += (ppe[byte_num] >> bit_num) & (BIT(residue_bits) - 1);22642265return res;2266}22672268static void iwl_mvm_parse_ppe(struct iwl_mvm *mvm,2269struct iwl_he_pkt_ext_v2 *pkt_ext, u8 nss,2270u8 ru_index_bitmap, u8 *ppe, u8 ppe_pos_bit,2271bool inheritance)2272{2273int i;22742275/*2276* FW currently supports only nss == MAX_HE_SUPP_NSS2277*2278* If nss > MAX: we can ignore values we don't support2279* If nss < MAX: we can set zeros in other streams2280*/2281if (nss > MAX_HE_SUPP_NSS) {2282IWL_DEBUG_INFO(mvm, "Got NSS = %d - trimming to %d\n", nss,2283MAX_HE_SUPP_NSS);2284nss = MAX_HE_SUPP_NSS;2285}22862287for (i = 0; i < nss; i++) {2288u8 ru_index_tmp = ru_index_bitmap << 1;2289u8 low_th = IWL_HE_PKT_EXT_NONE, high_th = IWL_HE_PKT_EXT_NONE;2290u8 bw;22912292for (bw = 0;2293bw < ARRAY_SIZE(pkt_ext->pkt_ext_qam_th[i]);2294bw++) {2295ru_index_tmp >>= 1;22962297/*2298* According to the 11be spec, if for a specific BW the PPE Thresholds2299* isn't present - it should inherit the thresholds from the last2300* BW for which we had PPE Thresholds. In 11ax though, we don't have2301* this inheritance - continue in this case2302*/2303if (!(ru_index_tmp & 1)) {2304if (inheritance)2305goto set_thresholds;2306else2307continue;2308}23092310high_th = iwl_mvm_he_get_ppe_val(ppe, ppe_pos_bit);2311ppe_pos_bit += IEEE80211_PPE_THRES_INFO_PPET_SIZE;2312low_th = iwl_mvm_he_get_ppe_val(ppe, ppe_pos_bit);2313ppe_pos_bit += IEEE80211_PPE_THRES_INFO_PPET_SIZE;23142315set_thresholds:2316pkt_ext->pkt_ext_qam_th[i][bw][0] = low_th;2317pkt_ext->pkt_ext_qam_th[i][bw][1] = high_th;2318}2319}2320}23212322static void iwl_mvm_set_pkt_ext_from_he_ppe(struct iwl_mvm *mvm,2323struct ieee80211_link_sta *link_sta,2324struct iwl_he_pkt_ext_v2 *pkt_ext,2325bool inheritance)2326{2327u8 nss = (link_sta->he_cap.ppe_thres[0] &2328IEEE80211_PPE_THRES_NSS_MASK) + 1;2329u8 *ppe = &link_sta->he_cap.ppe_thres[0];2330u8 ru_index_bitmap =2331u8_get_bits(*ppe,2332IEEE80211_PPE_THRES_RU_INDEX_BITMASK_MASK);2333/* Starting after PPE header */2334u8 ppe_pos_bit = IEEE80211_HE_PPE_THRES_INFO_HEADER_SIZE;23352336iwl_mvm_parse_ppe(mvm, pkt_ext, nss, ru_index_bitmap, ppe, ppe_pos_bit,2337inheritance);2338}23392340static int2341iwl_mvm_set_pkt_ext_from_nominal_padding(struct iwl_he_pkt_ext_v2 *pkt_ext,2342u8 nominal_padding)2343{2344int low_th = -1;2345int high_th = -1;2346int i;23472348/* all the macros are the same for EHT and HE */2349switch (nominal_padding) {2350case IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_0US:2351low_th = IWL_HE_PKT_EXT_NONE;2352high_th = IWL_HE_PKT_EXT_NONE;2353break;2354case IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_8US:2355low_th = IWL_HE_PKT_EXT_BPSK;2356high_th = IWL_HE_PKT_EXT_NONE;2357break;2358case IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_16US:2359case IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_20US:2360low_th = IWL_HE_PKT_EXT_NONE;2361high_th = IWL_HE_PKT_EXT_BPSK;2362break;2363}23642365if (low_th < 0 || high_th < 0)2366return -EINVAL;23672368/* Set the PPE thresholds accordingly */2369for (i = 0; i < MAX_HE_SUPP_NSS; i++) {2370u8 bw;23712372for (bw = 0;2373bw < ARRAY_SIZE(pkt_ext->pkt_ext_qam_th[i]);2374bw++) {2375pkt_ext->pkt_ext_qam_th[i][bw][0] = low_th;2376pkt_ext->pkt_ext_qam_th[i][bw][1] = high_th;2377}2378}23792380return 0;2381}23822383static void iwl_mvm_get_optimal_ppe_info(struct iwl_he_pkt_ext_v2 *pkt_ext,2384u8 nominal_padding)2385{2386int i;23872388for (i = 0; i < MAX_HE_SUPP_NSS; i++) {2389u8 bw;23902391for (bw = 0; bw < ARRAY_SIZE(pkt_ext->pkt_ext_qam_th[i]);2392bw++) {2393u8 *qam_th = &pkt_ext->pkt_ext_qam_th[i][bw][0];23942395if (nominal_padding >2396IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_8US &&2397qam_th[1] == IWL_HE_PKT_EXT_NONE)2398qam_th[1] = IWL_HE_PKT_EXT_4096QAM;2399else if (nominal_padding ==2400IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_8US &&2401qam_th[0] == IWL_HE_PKT_EXT_NONE &&2402qam_th[1] == IWL_HE_PKT_EXT_NONE)2403qam_th[0] = IWL_HE_PKT_EXT_4096QAM;2404}2405}2406}24072408/* Set the pkt_ext field according to PPE Thresholds element */2409int iwl_mvm_set_sta_pkt_ext(struct iwl_mvm *mvm,2410struct ieee80211_link_sta *link_sta,2411struct iwl_he_pkt_ext_v2 *pkt_ext)2412{2413u8 nominal_padding;2414int i, ret = 0;24152416if (WARN_ON(!link_sta))2417return -EINVAL;24182419/* Initialize the PPE thresholds to "None" (7), as described in Table2420* 9-262ac of 80211.ax/D3.0.2421*/2422memset(pkt_ext, IWL_HE_PKT_EXT_NONE,2423sizeof(struct iwl_he_pkt_ext_v2));24242425if (link_sta->eht_cap.has_eht) {2426nominal_padding =2427u8_get_bits(link_sta->eht_cap.eht_cap_elem.phy_cap_info[5],2428IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_MASK);24292430/* If PPE Thresholds exists, parse them into a FW-familiar2431* format.2432*/2433if (link_sta->eht_cap.eht_cap_elem.phy_cap_info[5] &2434IEEE80211_EHT_PHY_CAP5_PPE_THRESHOLD_PRESENT) {2435u8 nss = (link_sta->eht_cap.eht_ppe_thres[0] &2436IEEE80211_EHT_PPE_THRES_NSS_MASK) + 1;2437u8 *ppe = &link_sta->eht_cap.eht_ppe_thres[0];2438u8 ru_index_bitmap =2439u16_get_bits(*ppe,2440IEEE80211_EHT_PPE_THRES_RU_INDEX_BITMASK_MASK);2441/* Starting after PPE header */2442u8 ppe_pos_bit = IEEE80211_EHT_PPE_THRES_INFO_HEADER_SIZE;24432444iwl_mvm_parse_ppe(mvm, pkt_ext, nss, ru_index_bitmap,2445ppe, ppe_pos_bit, true);2446/* EHT PPE Thresholds doesn't exist - set the API according to2447* HE PPE Tresholds2448*/2449} else if (link_sta->he_cap.he_cap_elem.phy_cap_info[6] &2450IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT) {2451/* Even though HE Capabilities IE doesn't contain PPE2452* Thresholds for BW 320Mhz, thresholds for this BW will2453* be filled in with the same values as 160Mhz, due to2454* the inheritance, as required.2455*/2456iwl_mvm_set_pkt_ext_from_he_ppe(mvm, link_sta, pkt_ext,2457true);24582459/* According to the requirements, for MCSs 12-13 the2460* maximum value between HE PPE Threshold and Common2461* Nominal Packet Padding needs to be taken2462*/2463iwl_mvm_get_optimal_ppe_info(pkt_ext, nominal_padding);24642465/* if PPE Thresholds doesn't present in both EHT IE and HE IE -2466* take the Thresholds from Common Nominal Packet Padding field2467*/2468} else {2469ret = iwl_mvm_set_pkt_ext_from_nominal_padding(pkt_ext,2470nominal_padding);2471}2472} else if (link_sta->he_cap.has_he) {2473/* If PPE Thresholds exist, parse them into a FW-familiar format. */2474if (link_sta->he_cap.he_cap_elem.phy_cap_info[6] &2475IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT) {2476iwl_mvm_set_pkt_ext_from_he_ppe(mvm, link_sta, pkt_ext,2477false);2478/* PPE Thresholds doesn't exist - set the API PPE values2479* according to Common Nominal Packet Padding field.2480*/2481} else {2482nominal_padding =2483u8_get_bits(link_sta->he_cap.he_cap_elem.phy_cap_info[9],2484IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_MASK);2485if (nominal_padding != IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_RESERVED)2486ret = iwl_mvm_set_pkt_ext_from_nominal_padding(pkt_ext,2487nominal_padding);2488}2489}24902491for (i = 0; i < MAX_HE_SUPP_NSS; i++) {2492int bw;24932494for (bw = 0;2495bw < ARRAY_SIZE(*pkt_ext->pkt_ext_qam_th[i]);2496bw++) {2497u8 *qam_th =2498&pkt_ext->pkt_ext_qam_th[i][bw][0];24992500IWL_DEBUG_HT(mvm,2501"PPE table: nss[%d] bw[%d] PPET8 = %d, PPET16 = %d\n",2502i, bw, qam_th[0], qam_th[1]);2503}2504}2505return ret;2506}25072508/*2509* This function sets the MU EDCA parameters ans returns whether MU EDCA2510* is enabled or not2511*/2512bool iwl_mvm_set_fw_mu_edca_params(struct iwl_mvm *mvm,2513const struct iwl_mvm_vif_link_info *link_info,2514struct iwl_he_backoff_conf *trig_based_txf)2515{2516int i;2517/* Mark MU EDCA as enabled, unless none detected on some AC */2518bool mu_edca_enabled = true;25192520for (i = 0; i < IEEE80211_NUM_ACS; i++) {2521const struct ieee80211_he_mu_edca_param_ac_rec *mu_edca =2522&link_info->queue_params[i].mu_edca_param_rec;2523u8 ac = iwl_mvm_mac80211_ac_to_ucode_ac(i);25242525if (!link_info->queue_params[i].mu_edca) {2526mu_edca_enabled = false;2527break;2528}25292530trig_based_txf[ac].cwmin =2531cpu_to_le16(mu_edca->ecw_min_max & 0xf);2532trig_based_txf[ac].cwmax =2533cpu_to_le16((mu_edca->ecw_min_max & 0xf0) >> 4);2534trig_based_txf[ac].aifsn =2535cpu_to_le16(mu_edca->aifsn & 0xf);2536trig_based_txf[ac].mu_time =2537cpu_to_le16(mu_edca->mu_edca_timer);2538}25392540return mu_edca_enabled;2541}25422543bool iwl_mvm_is_nic_ack_enabled(struct iwl_mvm *mvm, struct ieee80211_vif *vif)2544{2545const struct ieee80211_supported_band *sband;2546const struct ieee80211_sta_he_cap *own_he_cap = NULL;25472548/* This capability is the same for all bands,2549* so take it from one of them.2550*/2551sband = mvm->hw->wiphy->bands[NL80211_BAND_2GHZ];2552own_he_cap = ieee80211_get_he_iftype_cap_vif(sband, vif);25532554return (own_he_cap && (own_he_cap->he_cap_elem.mac_cap_info[2] &2555IEEE80211_HE_MAC_CAP2_ACK_EN));2556}25572558__le32 iwl_mvm_get_sta_htc_flags(struct ieee80211_sta *sta,2559struct ieee80211_link_sta *link_sta)2560{2561u8 *mac_cap_info =2562&link_sta->he_cap.he_cap_elem.mac_cap_info[0];2563__le32 htc_flags = 0;25642565if (mac_cap_info[0] & IEEE80211_HE_MAC_CAP0_HTC_HE)2566htc_flags |= cpu_to_le32(IWL_HE_HTC_SUPPORT);2567if ((mac_cap_info[1] & IEEE80211_HE_MAC_CAP1_LINK_ADAPTATION) ||2568(mac_cap_info[2] & IEEE80211_HE_MAC_CAP2_LINK_ADAPTATION)) {2569u8 link_adap =2570((mac_cap_info[2] &2571IEEE80211_HE_MAC_CAP2_LINK_ADAPTATION) << 1) +2572(mac_cap_info[1] &2573IEEE80211_HE_MAC_CAP1_LINK_ADAPTATION);25742575if (link_adap == 2)2576htc_flags |=2577cpu_to_le32(IWL_HE_HTC_LINK_ADAP_UNSOLICITED);2578else if (link_adap == 3)2579htc_flags |= cpu_to_le32(IWL_HE_HTC_LINK_ADAP_BOTH);2580}2581if (mac_cap_info[2] & IEEE80211_HE_MAC_CAP2_BSR)2582htc_flags |= cpu_to_le32(IWL_HE_HTC_BSR_SUPP);2583if (mac_cap_info[3] & IEEE80211_HE_MAC_CAP3_OMI_CONTROL)2584htc_flags |= cpu_to_le32(IWL_HE_HTC_OMI_SUPP);2585if (mac_cap_info[4] & IEEE80211_HE_MAC_CAP4_BQR)2586htc_flags |= cpu_to_le32(IWL_HE_HTC_BQR_SUPP);25872588return htc_flags;2589}25902591static void iwl_mvm_cfg_he_sta(struct iwl_mvm *mvm,2592struct ieee80211_vif *vif, u8 sta_id)2593{2594struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);2595struct iwl_he_sta_context_cmd_v3 sta_ctxt_cmd = {2596.sta_id = sta_id,2597.tid_limit = IWL_MAX_TID_COUNT,2598.bss_color = vif->bss_conf.he_bss_color.color,2599.htc_trig_based_pkt_ext = vif->bss_conf.htc_trig_based_pkt_ext,2600.frame_time_rts_th =2601cpu_to_le16(vif->bss_conf.frame_time_rts_th),2602};2603struct iwl_he_sta_context_cmd_v2 sta_ctxt_cmd_v2 = {};2604u32 cmd_id = WIDE_ID(DATA_PATH_GROUP, STA_HE_CTXT_CMD);2605u8 ver = iwl_fw_lookup_cmd_ver(mvm->fw, cmd_id, 2);2606int size;2607struct ieee80211_sta *sta;2608u32 flags;2609int i;2610void *cmd;26112612if (!fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_MBSSID_HE))2613ver = 1;26142615switch (ver) {2616case 1:2617/* same layout as v2 except some data at the end */2618cmd = &sta_ctxt_cmd_v2;2619size = sizeof(struct iwl_he_sta_context_cmd_v1);2620break;2621case 2:2622cmd = &sta_ctxt_cmd_v2;2623size = sizeof(struct iwl_he_sta_context_cmd_v2);2624break;2625case 3:2626cmd = &sta_ctxt_cmd;2627size = sizeof(struct iwl_he_sta_context_cmd_v3);2628break;2629default:2630IWL_ERR(mvm, "bad STA_HE_CTXT_CMD version %d\n", ver);2631return;2632}26332634rcu_read_lock();26352636sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_ctxt_cmd.sta_id]);2637if (IS_ERR_OR_NULL(sta)) {2638rcu_read_unlock();2639WARN(1, "Can't find STA to configure HE\n");2640return;2641}26422643if (!sta->deflink.he_cap.has_he) {2644rcu_read_unlock();2645return;2646}26472648flags = 0;26492650/* Block 26-tone RU OFDMA transmissions */2651if (mvmvif->deflink.he_ru_2mhz_block)2652flags |= STA_CTXT_HE_RU_2MHZ_BLOCK;26532654/* HTC flags */2655sta_ctxt_cmd.htc_flags = iwl_mvm_get_sta_htc_flags(sta, &sta->deflink);26562657/* PPE Thresholds */2658if (!iwl_mvm_set_sta_pkt_ext(mvm, &sta->deflink, &sta_ctxt_cmd.pkt_ext))2659flags |= STA_CTXT_HE_PACKET_EXT;26602661if (sta->deflink.he_cap.he_cap_elem.mac_cap_info[2] &2662IEEE80211_HE_MAC_CAP2_32BIT_BA_BITMAP)2663flags |= STA_CTXT_HE_32BIT_BA_BITMAP;26642665if (sta->deflink.he_cap.he_cap_elem.mac_cap_info[2] &2666IEEE80211_HE_MAC_CAP2_ACK_EN)2667flags |= STA_CTXT_HE_ACK_ENABLED;26682669rcu_read_unlock();26702671if (iwl_mvm_set_fw_mu_edca_params(mvm, &mvmvif->deflink,2672&sta_ctxt_cmd.trig_based_txf[0]))2673flags |= STA_CTXT_HE_MU_EDCA_CW;26742675if (vif->bss_conf.uora_exists) {2676flags |= STA_CTXT_HE_TRIG_RND_ALLOC;26772678sta_ctxt_cmd.rand_alloc_ecwmin =2679vif->bss_conf.uora_ocw_range & 0x7;2680sta_ctxt_cmd.rand_alloc_ecwmax =2681(vif->bss_conf.uora_ocw_range >> 3) & 0x7;2682}26832684if (!iwl_mvm_is_nic_ack_enabled(mvm, vif))2685flags |= STA_CTXT_HE_NIC_NOT_ACK_ENABLED;26862687if (vif->bss_conf.nontransmitted) {2688flags |= STA_CTXT_HE_REF_BSSID_VALID;2689ether_addr_copy(sta_ctxt_cmd.ref_bssid_addr,2690vif->bss_conf.transmitter_bssid);2691sta_ctxt_cmd.max_bssid_indicator =2692vif->bss_conf.bssid_indicator;2693sta_ctxt_cmd.bssid_index = vif->bss_conf.bssid_index;2694sta_ctxt_cmd.ema_ap = vif->bss_conf.ema_ap;2695sta_ctxt_cmd.profile_periodicity =2696vif->bss_conf.profile_periodicity;2697}26982699sta_ctxt_cmd.flags = cpu_to_le32(flags);27002701if (ver < 3) {2702/* fields before pkt_ext */2703BUILD_BUG_ON(offsetof(typeof(sta_ctxt_cmd), pkt_ext) !=2704offsetof(typeof(sta_ctxt_cmd_v2), pkt_ext));2705memcpy(&sta_ctxt_cmd_v2, &sta_ctxt_cmd,2706offsetof(typeof(sta_ctxt_cmd), pkt_ext));27072708/* pkt_ext */2709for (i = 0;2710i < ARRAY_SIZE(sta_ctxt_cmd_v2.pkt_ext.pkt_ext_qam_th);2711i++) {2712u8 bw;27132714for (bw = 0;2715bw < ARRAY_SIZE(sta_ctxt_cmd_v2.pkt_ext.pkt_ext_qam_th[i]);2716bw++) {2717BUILD_BUG_ON(sizeof(sta_ctxt_cmd.pkt_ext.pkt_ext_qam_th[i][bw]) !=2718sizeof(sta_ctxt_cmd_v2.pkt_ext.pkt_ext_qam_th[i][bw]));27192720memcpy(&sta_ctxt_cmd_v2.pkt_ext.pkt_ext_qam_th[i][bw],2721&sta_ctxt_cmd.pkt_ext.pkt_ext_qam_th[i][bw],2722sizeof(sta_ctxt_cmd.pkt_ext.pkt_ext_qam_th[i][bw]));2723}2724}27252726/* fields after pkt_ext */2727BUILD_BUG_ON(sizeof(sta_ctxt_cmd) -2728offsetofend(typeof(sta_ctxt_cmd), pkt_ext) !=2729sizeof(sta_ctxt_cmd_v2) -2730offsetofend(typeof(sta_ctxt_cmd_v2), pkt_ext));2731memcpy((u8 *)&sta_ctxt_cmd_v2 +2732offsetofend(typeof(sta_ctxt_cmd_v2), pkt_ext),2733(u8 *)&sta_ctxt_cmd +2734offsetofend(typeof(sta_ctxt_cmd), pkt_ext),2735sizeof(sta_ctxt_cmd) -2736offsetofend(typeof(sta_ctxt_cmd), pkt_ext));2737sta_ctxt_cmd_v2.reserved3 = 0;2738}27392740if (iwl_mvm_send_cmd_pdu(mvm, cmd_id, 0, size, cmd))2741IWL_ERR(mvm, "Failed to config FW to work HE!\n");2742}27432744void iwl_mvm_protect_assoc(struct iwl_mvm *mvm, struct ieee80211_vif *vif,2745u32 duration_override, unsigned int link_id)2746{2747u32 duration = IWL_MVM_TE_SESSION_PROTECTION_MAX_TIME_MS;2748u32 min_duration = IWL_MVM_TE_SESSION_PROTECTION_MIN_TIME_MS;27492750if (duration_override > duration)2751duration = duration_override;27522753/* Try really hard to protect the session and hear a beacon2754* The new session protection command allows us to protect the2755* session for a much longer time since the firmware will internally2756* create two events: a 300TU one with a very high priority that2757* won't be fragmented which should be enough for 99% of the cases,2758* and another one (which we configure here to be 900TU long) which2759* will have a slightly lower priority, but more importantly, can be2760* fragmented so that it'll allow other activities to run.2761*/2762if (fw_has_capa(&mvm->fw->ucode_capa,2763IWL_UCODE_TLV_CAPA_SESSION_PROT_CMD))2764iwl_mvm_schedule_session_protection(mvm, vif, 900,2765min_duration, false,2766link_id);2767else2768iwl_mvm_protect_session(mvm, vif, duration,2769min_duration, 500, false);2770}27712772/* Handle association common part to MLD and non-MLD modes */2773void iwl_mvm_bss_info_changed_station_assoc(struct iwl_mvm *mvm,2774struct ieee80211_vif *vif,2775u64 changes)2776{2777struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);2778int ret;2779int link_id;27802781/* The firmware tracks the MU-MIMO group on its own.2782* However, on HW restart we should restore this data.2783*/2784if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) &&2785(changes & BSS_CHANGED_MU_GROUPS) && vif->bss_conf.mu_mimo_owner) {2786ret = iwl_mvm_update_mu_groups(mvm, vif);2787if (ret)2788IWL_ERR(mvm,2789"failed to update VHT MU_MIMO groups\n");2790}27912792iwl_mvm_recalc_multicast(mvm);27932794/* reset rssi values */2795for_each_mvm_vif_valid_link(mvmvif, link_id)2796mvmvif->link[link_id]->bf_data.ave_beacon_signal = 0;27972798iwl_mvm_bt_coex_vif_change(mvm);2799iwl_mvm_update_smps_on_active_links(mvm, vif, IWL_MVM_SMPS_REQ_TT,2800IEEE80211_SMPS_AUTOMATIC);2801if (fw_has_capa(&mvm->fw->ucode_capa,2802IWL_UCODE_TLV_CAPA_UMAC_SCAN))2803iwl_mvm_config_scan(mvm);2804}28052806/* Execute the common part for MLD and non-MLD modes */2807void2808iwl_mvm_bss_info_changed_station_common(struct iwl_mvm *mvm,2809struct ieee80211_vif *vif,2810struct ieee80211_bss_conf *link_conf,2811u64 changes)2812{2813struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);2814int ret;28152816if (changes & BSS_CHANGED_BEACON_INFO) {2817/* We received a beacon from the associated AP so2818* remove the session protection.2819*/2820iwl_mvm_stop_session_protection(mvm, vif);28212822iwl_mvm_sf_update(mvm, vif, false);2823WARN_ON(iwl_mvm_enable_beacon_filter(mvm, vif));2824}28252826if (changes & (BSS_CHANGED_PS | BSS_CHANGED_P2P_PS | BSS_CHANGED_QOS |2827/* Send power command on every beacon change,2828* because we may have not enabled beacon abort yet.2829*/2830BSS_CHANGED_BEACON_INFO)) {2831ret = iwl_mvm_power_update_mac(mvm);2832if (ret)2833IWL_ERR(mvm, "failed to update power mode\n");2834}28352836if (changes & BSS_CHANGED_CQM) {2837struct iwl_mvm_vif_link_info *link_info =2838mvmvif->link[link_conf->link_id];28392840IWL_DEBUG_MAC80211(mvm, "CQM info_changed\n");2841if (link_info)2842link_info->bf_data.last_cqm_event = 0;28432844if (mvmvif->bf_enabled) {2845/* FIXME: need to update per link when FW API will2846* support it2847*/2848ret = iwl_mvm_enable_beacon_filter(mvm, vif);2849if (ret)2850IWL_ERR(mvm,2851"failed to update CQM thresholds\n");2852}2853}28542855if (changes & BSS_CHANGED_BANDWIDTH)2856iwl_mvm_update_link_smps(vif, link_conf);28572858if (changes & BSS_CHANGED_TPE) {2859IWL_DEBUG_CALIB(mvm, "Changing TPE\n");2860iwl_mvm_send_ap_tx_power_constraint_cmd(mvm, vif,2861link_conf,2862false);2863}2864}28652866static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,2867struct ieee80211_vif *vif,2868struct ieee80211_bss_conf *bss_conf,2869u64 changes)2870{2871struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);2872int ret;2873int i;28742875/*2876* Re-calculate the tsf id, as the leader-follower relations depend2877* on the beacon interval, which was not known when the station2878* interface was added.2879*/2880if (changes & BSS_CHANGED_ASSOC && vif->cfg.assoc) {2881if ((vif->bss_conf.he_support &&2882!iwlwifi_mod_params.disable_11ax))2883iwl_mvm_cfg_he_sta(mvm, vif, mvmvif->deflink.ap_sta_id);28842885iwl_mvm_mac_ctxt_recalc_tsf_id(mvm, vif);2886}28872888/* Update MU EDCA params */2889if (changes & BSS_CHANGED_QOS && mvmvif->associated &&2890vif->cfg.assoc &&2891(vif->bss_conf.he_support && !iwlwifi_mod_params.disable_11ax))2892iwl_mvm_cfg_he_sta(mvm, vif, mvmvif->deflink.ap_sta_id);28932894/*2895* If we're not associated yet, take the (new) BSSID before associating2896* so the firmware knows. If we're already associated, then use the old2897* BSSID here, and we'll send a cleared one later in the CHANGED_ASSOC2898* branch for disassociation below.2899*/2900if (changes & BSS_CHANGED_BSSID && !mvmvif->associated)2901memcpy(mvmvif->deflink.bssid, bss_conf->bssid, ETH_ALEN);29022903ret = iwl_mvm_mac_ctxt_changed(mvm, vif, false, mvmvif->deflink.bssid);2904if (ret)2905IWL_ERR(mvm, "failed to update MAC %pM\n", vif->addr);29062907/* after sending it once, adopt mac80211 data */2908memcpy(mvmvif->deflink.bssid, bss_conf->bssid, ETH_ALEN);2909mvmvif->associated = vif->cfg.assoc;29102911if (changes & BSS_CHANGED_ASSOC) {2912if (vif->cfg.assoc) {2913mvmvif->session_prot_connection_loss = false;29142915/* clear statistics to get clean beacon counter */2916iwl_mvm_request_statistics(mvm, true);2917for_each_mvm_vif_valid_link(mvmvif, i)2918memset(&mvmvif->link[i]->beacon_stats, 0,2919sizeof(mvmvif->link[i]->beacon_stats));29202921/* add quota for this interface */2922ret = iwl_mvm_update_quotas(mvm, true, NULL);2923if (ret) {2924IWL_ERR(mvm, "failed to update quotas\n");2925return;2926}29272928if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART,2929&mvm->status) &&2930!fw_has_capa(&mvm->fw->ucode_capa,2931IWL_UCODE_TLV_CAPA_SESSION_PROT_CMD)) {2932/*2933* If we're restarting then the firmware will2934* obviously have lost synchronisation with2935* the AP. It will attempt to synchronise by2936* itself, but we can make it more reliable by2937* scheduling a session protection time event.2938*2939* The firmware needs to receive a beacon to2940* catch up with synchronisation, use 110% of2941* the beacon interval.2942*2943* Set a large maximum delay to allow for more2944* than a single interface.2945*2946* For new firmware versions, rely on the2947* firmware. This is relevant for DCM scenarios2948* only anyway.2949*/2950u32 dur = (11 * vif->bss_conf.beacon_int) / 10;2951iwl_mvm_protect_session(mvm, vif, dur, dur,29525 * dur, false);2953} else if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART,2954&mvm->status) &&2955!vif->bss_conf.dtim_period) {2956/*2957* If we're not restarting and still haven't2958* heard a beacon (dtim period unknown) then2959* make sure we still have enough minimum time2960* remaining in the time event, since the auth2961* might actually have taken quite a while2962* (especially for SAE) and so the remaining2963* time could be small without us having heard2964* a beacon yet.2965*/2966iwl_mvm_protect_assoc(mvm, vif, 0, 0);2967}29682969iwl_mvm_sf_update(mvm, vif, false);2970iwl_mvm_power_vif_assoc(mvm, vif);2971if (vif->p2p) {2972iwl_mvm_update_smps(mvm, vif,2973IWL_MVM_SMPS_REQ_PROT,2974IEEE80211_SMPS_DYNAMIC, 0);2975}2976} else if (mvmvif->deflink.ap_sta_id != IWL_INVALID_STA) {2977iwl_mvm_mei_host_disassociated(mvm);2978/*2979* If update fails - SF might be running in associated2980* mode while disassociated - which is forbidden.2981*/2982ret = iwl_mvm_sf_update(mvm, vif, false);2983WARN_ONCE(ret &&2984!test_bit(IWL_MVM_STATUS_HW_RESTART_REQUESTED,2985&mvm->status),2986"Failed to update SF upon disassociation\n");29872988/* remove quota for this interface */2989ret = iwl_mvm_update_quotas(mvm, false, NULL);2990if (ret)2991IWL_ERR(mvm, "failed to update quotas\n");29922993/* this will take the cleared BSSID from bss_conf */2994ret = iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL);2995if (ret)2996IWL_ERR(mvm,2997"failed to update MAC %pM (clear after unassoc)\n",2998vif->addr);2999}30003001iwl_mvm_bss_info_changed_station_assoc(mvm, vif, changes);3002}30033004iwl_mvm_bss_info_changed_station_common(mvm, vif, &vif->bss_conf,3005changes);3006}30073008bool iwl_mvm_start_ap_ibss_common(struct ieee80211_hw *hw,3009struct ieee80211_vif *vif,3010int *ret)3011{3012struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);3013struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);3014int i;30153016lockdep_assert_held(&mvm->mutex);30173018mvmvif->ap_assoc_sta_count = 0;30193020/* must be set before quota calculations */3021mvmvif->ap_ibss_active = true;30223023/* send all the early keys to the device now */3024for (i = 0; i < ARRAY_SIZE(mvmvif->ap_early_keys); i++) {3025struct ieee80211_key_conf *key = mvmvif->ap_early_keys[i];30263027if (!key)3028continue;30293030mvmvif->ap_early_keys[i] = NULL;30313032*ret = __iwl_mvm_mac_set_key(hw, SET_KEY, vif, NULL, key);3033if (*ret)3034return true;3035}30363037if (vif->type == NL80211_IFTYPE_AP && !vif->p2p) {3038iwl_mvm_vif_set_low_latency(mvmvif, true,3039LOW_LATENCY_VIF_TYPE);3040iwl_mvm_send_low_latency_cmd(mvm, true, mvmvif->id);3041}30423043/* power updated needs to be done before quotas */3044iwl_mvm_power_update_mac(mvm);30453046return false;3047}30483049static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw,3050struct ieee80211_vif *vif,3051struct ieee80211_bss_conf *link_conf)3052{3053struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);3054struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);3055int ret;30563057mutex_lock(&mvm->mutex);30583059/*3060* Re-calculate the tsf id, as the leader-follower relations depend on3061* the beacon interval, which was not known when the AP interface3062* was added.3063*/3064if (vif->type == NL80211_IFTYPE_AP)3065iwl_mvm_mac_ctxt_recalc_tsf_id(mvm, vif);30663067/* For older devices need to send beacon template before adding mac3068* context. For the newer, the beacon is a resource that belongs to a3069* MAC, so need to send beacon template after adding the mac.3070*/3071if (mvm->trans->mac_cfg->device_family > IWL_DEVICE_FAMILY_22000) {3072/* Add the mac context */3073ret = iwl_mvm_mac_ctxt_add(mvm, vif);3074if (ret)3075goto out_unlock;30763077/* Send the beacon template */3078ret = iwl_mvm_mac_ctxt_beacon_changed(mvm, vif, link_conf);3079if (ret)3080goto out_unlock;3081} else {3082/* Send the beacon template */3083ret = iwl_mvm_mac_ctxt_beacon_changed(mvm, vif, link_conf);3084if (ret)3085goto out_unlock;30863087/* Add the mac context */3088ret = iwl_mvm_mac_ctxt_add(mvm, vif);3089if (ret)3090goto out_unlock;3091}30923093/* Perform the binding */3094ret = iwl_mvm_binding_add_vif(mvm, vif);3095if (ret)3096goto out_remove;30973098/*3099* This is not very nice, but the simplest:3100* For older FWs adding the mcast sta before the bcast station may3101* cause assert 0x2b00.3102* This is fixed in later FW so make the order of removal depend on3103* the TLV3104*/3105if (fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_STA_TYPE)) {3106ret = iwl_mvm_add_mcast_sta(mvm, vif);3107if (ret)3108goto out_unbind;3109/*3110* Send the bcast station. At this stage the TBTT and DTIM time3111* events are added and applied to the scheduler3112*/3113ret = iwl_mvm_send_add_bcast_sta(mvm, vif);3114if (ret) {3115iwl_mvm_rm_mcast_sta(mvm, vif);3116goto out_unbind;3117}3118} else {3119/*3120* Send the bcast station. At this stage the TBTT and DTIM time3121* events are added and applied to the scheduler3122*/3123ret = iwl_mvm_send_add_bcast_sta(mvm, vif);3124if (ret)3125goto out_unbind;3126ret = iwl_mvm_add_mcast_sta(mvm, vif);3127if (ret) {3128iwl_mvm_send_rm_bcast_sta(mvm, vif);3129goto out_unbind;3130}3131}31323133if (iwl_mvm_start_ap_ibss_common(hw, vif, &ret))3134goto out_failed;31353136ret = iwl_mvm_update_quotas(mvm, false, NULL);3137if (ret)3138goto out_failed;31393140/* Need to update the P2P Device MAC (only GO, IBSS is single vif) */3141if (vif->p2p && mvm->p2p_device_vif)3142iwl_mvm_mac_ctxt_changed(mvm, mvm->p2p_device_vif, false, NULL);31433144iwl_mvm_bt_coex_vif_change(mvm);31453146/* we don't support TDLS during DCM */3147if (iwl_mvm_phy_ctx_count(mvm) > 1)3148iwl_mvm_teardown_tdls_peers(mvm);31493150iwl_mvm_ftm_restart_responder(mvm, vif, &vif->bss_conf);31513152goto out_unlock;31533154out_failed:3155iwl_mvm_power_update_mac(mvm);3156mvmvif->ap_ibss_active = false;3157iwl_mvm_send_rm_bcast_sta(mvm, vif);3158iwl_mvm_rm_mcast_sta(mvm, vif);3159out_unbind:3160iwl_mvm_binding_remove_vif(mvm, vif);3161out_remove:3162iwl_mvm_mac_ctxt_remove(mvm, vif);3163out_unlock:3164mutex_unlock(&mvm->mutex);3165return ret;3166}31673168static int iwl_mvm_start_ap(struct ieee80211_hw *hw,3169struct ieee80211_vif *vif,3170struct ieee80211_bss_conf *link_conf)3171{3172return iwl_mvm_start_ap_ibss(hw, vif, link_conf);3173}31743175static int iwl_mvm_start_ibss(struct ieee80211_hw *hw,3176struct ieee80211_vif *vif)3177{3178return iwl_mvm_start_ap_ibss(hw, vif, &vif->bss_conf);3179}31803181/* Common part for MLD and non-MLD ops */3182void iwl_mvm_stop_ap_ibss_common(struct iwl_mvm *mvm,3183struct ieee80211_vif *vif)3184{3185struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);31863187lockdep_assert_held(&mvm->mutex);31883189iwl_mvm_prepare_mac_removal(mvm, vif);31903191/* Handle AP stop while in CSA */3192if (rcu_access_pointer(mvm->csa_vif) == vif) {3193iwl_mvm_remove_time_event(mvm, mvmvif,3194&mvmvif->time_event_data);3195RCU_INIT_POINTER(mvm->csa_vif, NULL);3196mvmvif->csa_countdown = false;3197}31983199if (rcu_access_pointer(mvm->csa_tx_blocked_vif) == vif) {3200RCU_INIT_POINTER(mvm->csa_tx_blocked_vif, NULL);3201mvm->csa_tx_block_bcn_timeout = 0;3202}32033204mvmvif->ap_ibss_active = false;3205mvm->ap_last_beacon_gp2 = 0;32063207if (vif->type == NL80211_IFTYPE_AP && !vif->p2p) {3208iwl_mvm_vif_set_low_latency(mvmvif, false,3209LOW_LATENCY_VIF_TYPE);3210iwl_mvm_send_low_latency_cmd(mvm, false, mvmvif->id);3211}32123213iwl_mvm_bt_coex_vif_change(mvm);3214}32153216static void iwl_mvm_stop_ap_ibss(struct ieee80211_hw *hw,3217struct ieee80211_vif *vif,3218struct ieee80211_bss_conf *link_conf)3219{3220struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);32213222guard(mvm)(mvm);32233224iwl_mvm_stop_ap_ibss_common(mvm, vif);32253226/* Need to update the P2P Device MAC (only GO, IBSS is single vif) */3227if (vif->p2p && mvm->p2p_device_vif)3228iwl_mvm_mac_ctxt_changed(mvm, mvm->p2p_device_vif, false, NULL);32293230iwl_mvm_update_quotas(mvm, false, NULL);32313232iwl_mvm_ftm_responder_clear(mvm, vif);32333234/*3235* This is not very nice, but the simplest:3236* For older FWs removing the mcast sta before the bcast station may3237* cause assert 0x2b00.3238* This is fixed in later FW (which will stop beaconing when removing3239* bcast station).3240* So make the order of removal depend on the TLV3241*/3242if (!fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_STA_TYPE))3243iwl_mvm_rm_mcast_sta(mvm, vif);3244iwl_mvm_send_rm_bcast_sta(mvm, vif);3245if (fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_STA_TYPE))3246iwl_mvm_rm_mcast_sta(mvm, vif);3247iwl_mvm_binding_remove_vif(mvm, vif);32483249iwl_mvm_power_update_mac(mvm);32503251iwl_mvm_mac_ctxt_remove(mvm, vif);3252}32533254static void iwl_mvm_stop_ap(struct ieee80211_hw *hw,3255struct ieee80211_vif *vif,3256struct ieee80211_bss_conf *link_conf)3257{3258iwl_mvm_stop_ap_ibss(hw, vif, link_conf);3259}32603261static void iwl_mvm_stop_ibss(struct ieee80211_hw *hw,3262struct ieee80211_vif *vif)3263{3264iwl_mvm_stop_ap_ibss(hw, vif, &vif->bss_conf);3265}32663267static void3268iwl_mvm_bss_info_changed_ap_ibss(struct iwl_mvm *mvm,3269struct ieee80211_vif *vif,3270struct ieee80211_bss_conf *bss_conf,3271u64 changes)3272{3273struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);32743275/* Changes will be applied when the AP/IBSS is started */3276if (!mvmvif->ap_ibss_active)3277return;32783279if (changes & (BSS_CHANGED_ERP_CTS_PROT | BSS_CHANGED_HT |3280BSS_CHANGED_BANDWIDTH | BSS_CHANGED_QOS) &&3281iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL))3282IWL_ERR(mvm, "failed to update MAC %pM\n", vif->addr);32833284/* Need to send a new beacon template to the FW */3285if (changes & BSS_CHANGED_BEACON &&3286iwl_mvm_mac_ctxt_beacon_changed(mvm, vif, &vif->bss_conf))3287IWL_WARN(mvm, "Failed updating beacon data\n");32883289if (changes & BSS_CHANGED_FTM_RESPONDER) {3290int ret = iwl_mvm_ftm_start_responder(mvm, vif, &vif->bss_conf);32913292if (ret)3293IWL_WARN(mvm, "Failed to enable FTM responder (%d)\n",3294ret);3295}32963297}32983299static void iwl_mvm_bss_info_changed(struct ieee80211_hw *hw,3300struct ieee80211_vif *vif,3301struct ieee80211_bss_conf *bss_conf,3302u64 changes)3303{3304struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);33053306guard(mvm)(mvm);33073308if (changes & BSS_CHANGED_IDLE && !vif->cfg.idle)3309iwl_mvm_scan_stop(mvm, IWL_MVM_SCAN_SCHED, true);33103311switch (vif->type) {3312case NL80211_IFTYPE_STATION:3313iwl_mvm_bss_info_changed_station(mvm, vif, bss_conf, changes);3314break;3315case NL80211_IFTYPE_AP:3316case NL80211_IFTYPE_ADHOC:3317iwl_mvm_bss_info_changed_ap_ibss(mvm, vif, bss_conf, changes);3318break;3319case NL80211_IFTYPE_MONITOR:3320if (changes & BSS_CHANGED_MU_GROUPS)3321iwl_mvm_update_mu_groups(mvm, vif);3322break;3323default:3324/* shouldn't happen */3325WARN_ON_ONCE(1);3326}33273328if (changes & BSS_CHANGED_TXPOWER) {3329IWL_DEBUG_CALIB(mvm, "Changing TX Power to %d dBm\n",3330bss_conf->txpower);3331iwl_mvm_set_tx_power(mvm, bss_conf, bss_conf->txpower);3332}3333}33343335int iwl_mvm_mac_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,3336struct ieee80211_scan_request *hw_req)3337{3338struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);33393340if (hw_req->req.n_channels == 0 ||3341hw_req->req.n_channels > mvm->fw->ucode_capa.n_scan_channels)3342return -EINVAL;33433344guard(mvm)(mvm);3345return iwl_mvm_reg_scan_start(mvm, vif, &hw_req->req, &hw_req->ies);3346}33473348void iwl_mvm_mac_cancel_hw_scan(struct ieee80211_hw *hw,3349struct ieee80211_vif *vif)3350{3351struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);33523353guard(mvm)(mvm);33543355/* Due to a race condition, it's possible that mac80211 asks3356* us to stop a hw_scan when it's already stopped. This can3357* happen, for instance, if we stopped the scan ourselves,3358* called ieee80211_scan_completed() and the userspace called3359* cancel scan before ieee80211_scan_work() could run.3360* To handle that, simply return if the scan is not running.3361*/3362if (mvm->scan_status & IWL_MVM_SCAN_REGULAR)3363iwl_mvm_scan_stop(mvm, IWL_MVM_SCAN_REGULAR, true);3364}33653366void3367iwl_mvm_mac_allow_buffered_frames(struct ieee80211_hw *hw,3368struct ieee80211_sta *sta, u16 tids,3369int num_frames,3370enum ieee80211_frame_release_type reason,3371bool more_data)3372{3373struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);33743375/* Called when we need to transmit (a) frame(s) from mac80211 */33763377iwl_mvm_sta_modify_sleep_tx_count(mvm, sta, reason, num_frames,3378tids, more_data, false);3379}33803381void3382iwl_mvm_mac_release_buffered_frames(struct ieee80211_hw *hw,3383struct ieee80211_sta *sta, u16 tids,3384int num_frames,3385enum ieee80211_frame_release_type reason,3386bool more_data)3387{3388struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);33893390/* Called when we need to transmit (a) frame(s) from agg or dqa queue */33913392iwl_mvm_sta_modify_sleep_tx_count(mvm, sta, reason, num_frames,3393tids, more_data, true);3394}33953396static void __iwl_mvm_mac_sta_notify(struct ieee80211_hw *hw,3397enum sta_notify_cmd cmd,3398struct ieee80211_sta *sta)3399{3400struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);3401struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);3402unsigned long txqs = 0, tids = 0;3403int tid;34043405/*3406* If we have TVQM then we get too high queue numbers - luckily3407* we really shouldn't get here with that because such hardware3408* should have firmware supporting buffer station offload.3409*/3410if (WARN_ON(iwl_mvm_has_new_tx_api(mvm)))3411return;34123413spin_lock_bh(&mvmsta->lock);3414for (tid = 0; tid < ARRAY_SIZE(mvmsta->tid_data); tid++) {3415struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid];34163417if (tid_data->txq_id == IWL_MVM_INVALID_QUEUE)3418continue;34193420__set_bit(tid_data->txq_id, &txqs);34213422if (iwl_mvm_tid_queued(mvm, tid_data) == 0)3423continue;34243425__set_bit(tid, &tids);3426}34273428switch (cmd) {3429case STA_NOTIFY_SLEEP:3430for_each_set_bit(tid, &tids, IWL_MAX_TID_COUNT)3431ieee80211_sta_set_buffered(sta, tid, true);34323433if (txqs)3434iwl_trans_freeze_txq_timer(mvm->trans, txqs, true);3435/*3436* The fw updates the STA to be asleep. Tx packets on the Tx3437* queues to this station will not be transmitted. The fw will3438* send a Tx response with TX_STATUS_FAIL_DEST_PS.3439*/3440break;3441case STA_NOTIFY_AWAKE:3442if (WARN_ON(mvmsta->deflink.sta_id == IWL_INVALID_STA))3443break;34443445if (txqs)3446iwl_trans_freeze_txq_timer(mvm->trans, txqs, false);3447iwl_mvm_sta_modify_ps_wake(mvm, sta);3448break;3449default:3450break;3451}3452spin_unlock_bh(&mvmsta->lock);3453}34543455void iwl_mvm_mac_sta_notify(struct ieee80211_hw *hw, struct ieee80211_vif *vif,3456enum sta_notify_cmd cmd, struct ieee80211_sta *sta)3457{3458__iwl_mvm_mac_sta_notify(hw, cmd, sta);3459}34603461void iwl_mvm_sta_pm_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb)3462{3463struct iwl_rx_packet *pkt = rxb_addr(rxb);3464struct iwl_mvm_pm_state_notification *notif = (void *)pkt->data;3465struct ieee80211_sta *sta;3466struct iwl_mvm_sta *mvmsta;3467bool sleeping = (notif->type != IWL_MVM_PM_EVENT_AWAKE);34683469if (WARN_ON(notif->sta_id >= mvm->fw->ucode_capa.num_stations))3470return;34713472rcu_read_lock();3473sta = rcu_dereference(mvm->fw_id_to_mac_id[notif->sta_id]);3474if (WARN_ON(IS_ERR_OR_NULL(sta))) {3475rcu_read_unlock();3476return;3477}34783479mvmsta = iwl_mvm_sta_from_mac80211(sta);34803481if (!mvmsta->vif ||3482mvmsta->vif->type != NL80211_IFTYPE_AP) {3483rcu_read_unlock();3484return;3485}34863487if (mvmsta->sleeping != sleeping) {3488mvmsta->sleeping = sleeping;3489__iwl_mvm_mac_sta_notify(mvm->hw,3490sleeping ? STA_NOTIFY_SLEEP : STA_NOTIFY_AWAKE,3491sta);3492ieee80211_sta_ps_transition(sta, sleeping);3493}34943495if (sleeping) {3496switch (notif->type) {3497case IWL_MVM_PM_EVENT_AWAKE:3498case IWL_MVM_PM_EVENT_ASLEEP:3499break;3500case IWL_MVM_PM_EVENT_UAPSD:3501ieee80211_sta_uapsd_trigger(sta, IEEE80211_NUM_TIDS);3502break;3503case IWL_MVM_PM_EVENT_PS_POLL:3504ieee80211_sta_pspoll(sta);3505break;3506default:3507break;3508}3509}35103511rcu_read_unlock();3512}35133514void iwl_mvm_sta_pre_rcu_remove(struct ieee80211_hw *hw,3515struct ieee80211_vif *vif,3516struct ieee80211_sta *sta)3517{3518struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);3519struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);3520unsigned int link_id;35213522lockdep_assert_wiphy(mvm->hw->wiphy);35233524/*3525* This is called before mac80211 does RCU synchronisation,3526* so here we already invalidate our internal RCU-protected3527* station pointer. The rest of the code will thus no longer3528* be able to find the station this way, and we don't rely3529* on further RCU synchronisation after the sta_state()3530* callback deleted the station.3531* Since there's mvm->mutex here, no need to have RCU lock for3532* mvm_sta->link access.3533*/3534guard(mvm)(mvm);3535for (link_id = 0; link_id < ARRAY_SIZE(mvm_sta->link); link_id++) {3536struct iwl_mvm_link_sta *link_sta;3537u32 sta_id;35383539if (!mvm_sta->link[link_id])3540continue;35413542link_sta = rcu_dereference_protected(mvm_sta->link[link_id],3543lockdep_is_held(&mvm->mutex));3544sta_id = link_sta->sta_id;3545if (sta == rcu_access_pointer(mvm->fw_id_to_mac_id[sta_id])) {3546RCU_INIT_POINTER(mvm->fw_id_to_mac_id[sta_id],3547ERR_PTR(-ENOENT));3548RCU_INIT_POINTER(mvm->fw_id_to_link_sta[sta_id], NULL);3549}3550}3551}35523553static void iwl_mvm_check_uapsd(struct iwl_mvm *mvm, struct ieee80211_vif *vif,3554const u8 *bssid)3555{3556int i;35573558if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) {3559struct iwl_mvm_tcm_mac *mdata;35603561mdata = &mvm->tcm.data[iwl_mvm_vif_from_mac80211(vif)->id];3562ewma_rate_init(&mdata->uapsd_nonagg_detect.rate);3563mdata->opened_rx_ba_sessions = false;3564}35653566if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT))3567return;35683569if (vif->p2p && !iwl_mvm_is_p2p_scm_uapsd_supported(mvm)) {3570vif->driver_flags &= ~IEEE80211_VIF_SUPPORTS_UAPSD;3571return;3572}35733574if (!vif->p2p &&3575(iwlwifi_mod_params.uapsd_disable & IWL_DISABLE_UAPSD_BSS)) {3576vif->driver_flags &= ~IEEE80211_VIF_SUPPORTS_UAPSD;3577return;3578}35793580for (i = 0; i < IWL_MVM_UAPSD_NOAGG_LIST_LEN; i++) {3581if (ether_addr_equal(mvm->uapsd_noagg_bssids[i].addr, bssid)) {3582vif->driver_flags &= ~IEEE80211_VIF_SUPPORTS_UAPSD;3583return;3584}3585}35863587vif->driver_flags |= IEEE80211_VIF_SUPPORTS_UAPSD;3588}35893590static void3591iwl_mvm_tdls_check_trigger(struct iwl_mvm *mvm,3592struct ieee80211_vif *vif, u8 *peer_addr,3593enum nl80211_tdls_operation action)3594{3595struct iwl_fw_dbg_trigger_tlv *trig;3596struct iwl_fw_dbg_trigger_tdls *tdls_trig;35973598trig = iwl_fw_dbg_trigger_on(&mvm->fwrt, ieee80211_vif_to_wdev(vif),3599FW_DBG_TRIGGER_TDLS);3600if (!trig)3601return;36023603tdls_trig = (void *)trig->data;36043605if (!(tdls_trig->action_bitmap & BIT(action)))3606return;36073608if (tdls_trig->peer_mode &&3609memcmp(tdls_trig->peer, peer_addr, ETH_ALEN) != 0)3610return;36113612iwl_fw_dbg_collect_trig(&mvm->fwrt, trig,3613"TDLS event occurred, peer %pM, action %d",3614peer_addr, action);3615}36163617struct iwl_mvm_he_obss_narrow_bw_ru_data {3618bool tolerated;3619};36203621static void iwl_mvm_check_he_obss_narrow_bw_ru_iter(struct wiphy *wiphy,3622struct cfg80211_bss *bss,3623void *_data)3624{3625struct iwl_mvm_he_obss_narrow_bw_ru_data *data = _data;3626const struct cfg80211_bss_ies *ies;3627const struct element *elem;36283629rcu_read_lock();3630ies = rcu_dereference(bss->ies);3631elem = cfg80211_find_elem(WLAN_EID_EXT_CAPABILITY, ies->data,3632ies->len);36333634if (!elem || elem->datalen < 10 ||3635!(elem->data[10] &3636WLAN_EXT_CAPA10_OBSS_NARROW_BW_RU_TOLERANCE_SUPPORT)) {3637data->tolerated = false;3638}3639rcu_read_unlock();3640}36413642static void3643iwl_mvm_check_he_obss_narrow_bw_ru(struct ieee80211_hw *hw,3644struct ieee80211_vif *vif,3645unsigned int link_id,3646struct ieee80211_bss_conf *link_conf)3647{3648struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);3649struct iwl_mvm_he_obss_narrow_bw_ru_data iter_data = {3650.tolerated = true,3651};36523653if (WARN_ON_ONCE(!link_conf->chanreq.oper.chan ||3654!mvmvif->link[link_id]))3655return;36563657if (!(link_conf->chanreq.oper.chan->flags & IEEE80211_CHAN_RADAR)) {3658mvmvif->link[link_id]->he_ru_2mhz_block = false;3659return;3660}36613662cfg80211_bss_iter(hw->wiphy, &link_conf->chanreq.oper,3663iwl_mvm_check_he_obss_narrow_bw_ru_iter,3664&iter_data);36653666/*3667* If there is at least one AP on radar channel that cannot3668* tolerate 26-tone RU UL OFDMA transmissions using HE TB PPDU.3669*/3670mvmvif->link[link_id]->he_ru_2mhz_block = !iter_data.tolerated;3671}36723673static void iwl_mvm_reset_cca_40mhz_workaround(struct iwl_mvm *mvm,3674struct ieee80211_vif *vif)3675{3676struct ieee80211_supported_band *sband;3677const struct ieee80211_sta_he_cap *he_cap;36783679if (vif->type != NL80211_IFTYPE_STATION)3680return;36813682if (!mvm->cca_40mhz_workaround)3683return;36843685/* decrement and check that we reached zero */3686mvm->cca_40mhz_workaround--;3687if (mvm->cca_40mhz_workaround)3688return;36893690sband = mvm->hw->wiphy->bands[NL80211_BAND_2GHZ];36913692sband->ht_cap.cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;36933694he_cap = ieee80211_get_he_iftype_cap_vif(sband, vif);36953696if (he_cap) {3697/* we know that ours is writable */3698struct ieee80211_sta_he_cap *he = (void *)(uintptr_t)he_cap;36993700he->he_cap_elem.phy_cap_info[0] |=3701IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G;3702}3703}37043705static void iwl_mvm_mei_host_associated(struct iwl_mvm *mvm,3706struct ieee80211_vif *vif,3707struct iwl_mvm_sta *mvm_sta)3708{3709#if IS_ENABLED(CONFIG_IWLMEI)3710struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);3711struct iwl_mei_conn_info conn_info = {3712.ssid_len = vif->cfg.ssid_len,3713};37143715if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))3716return;37173718if (!mvm->mei_registered)3719return;37203721/* FIXME: MEI needs to be updated for MLO */3722if (!vif->bss_conf.chanreq.oper.chan)3723return;37243725conn_info.channel = vif->bss_conf.chanreq.oper.chan->hw_value;37263727switch (mvm_sta->pairwise_cipher) {3728case WLAN_CIPHER_SUITE_TKIP:3729conn_info.pairwise_cipher = IWL_MEI_CIPHER_TKIP;3730break;3731case WLAN_CIPHER_SUITE_CCMP:3732conn_info.pairwise_cipher = IWL_MEI_CIPHER_CCMP;3733break;3734case WLAN_CIPHER_SUITE_GCMP:3735conn_info.pairwise_cipher = IWL_MEI_CIPHER_GCMP;3736break;3737case WLAN_CIPHER_SUITE_GCMP_256:3738conn_info.pairwise_cipher = IWL_MEI_CIPHER_GCMP_256;3739break;3740case 0:3741/* open profile */3742break;3743default:3744/* cipher not supported, don't send anything to iwlmei */3745return;3746}37473748switch (mvmvif->rekey_data.akm) {3749case WLAN_AKM_SUITE_SAE & 0xff:3750conn_info.auth_mode = IWL_MEI_AKM_AUTH_SAE;3751break;3752case WLAN_AKM_SUITE_PSK & 0xff:3753conn_info.auth_mode = IWL_MEI_AKM_AUTH_RSNA_PSK;3754break;3755case WLAN_AKM_SUITE_8021X & 0xff:3756conn_info.auth_mode = IWL_MEI_AKM_AUTH_RSNA;3757break;3758case 0:3759/* open profile */3760conn_info.auth_mode = IWL_MEI_AKM_AUTH_OPEN;3761break;3762default:3763/* auth method / AKM not supported */3764/* TODO: All the FT vesions of these? */3765return;3766}37673768memcpy(conn_info.ssid, vif->cfg.ssid, vif->cfg.ssid_len);3769memcpy(conn_info.bssid, vif->bss_conf.bssid, ETH_ALEN);37703771/* TODO: add support for collocated AP data */3772iwl_mei_host_associated(&conn_info, NULL);3773#endif3774}37753776static int iwl_mvm_mac_ctxt_changed_wrapper(struct iwl_mvm *mvm,3777struct ieee80211_vif *vif,3778bool force_assoc_off)3779{3780return iwl_mvm_mac_ctxt_changed(mvm, vif, force_assoc_off, NULL);3781}37823783static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw,3784struct ieee80211_vif *vif,3785struct ieee80211_sta *sta,3786enum ieee80211_sta_state old_state,3787enum ieee80211_sta_state new_state)3788{3789static const struct iwl_mvm_sta_state_ops callbacks = {3790.add_sta = iwl_mvm_add_sta,3791.update_sta = iwl_mvm_update_sta,3792.rm_sta = iwl_mvm_rm_sta,3793.mac_ctxt_changed = iwl_mvm_mac_ctxt_changed_wrapper,3794};37953796return iwl_mvm_mac_sta_state_common(hw, vif, sta, old_state, new_state,3797&callbacks);3798}37993800/* FIXME: temporary making two assumptions in all sta handling functions:3801* (1) when setting sta state, the link exists and protected3802* (2) if a link is valid in sta then it's valid in vif (can3803* use same index in the link array)3804*/3805static void iwl_mvm_rs_rate_init_all_links(struct iwl_mvm *mvm,3806struct ieee80211_vif *vif,3807struct ieee80211_sta *sta)3808{3809struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);3810unsigned int link_id;38113812for_each_mvm_vif_valid_link(mvmvif, link_id) {3813struct ieee80211_bss_conf *conf =3814link_conf_dereference_check(vif, link_id);3815struct ieee80211_link_sta *link_sta =3816link_sta_dereference_check(sta, link_id);38173818if (!conf || !link_sta || !mvmvif->link[link_id]->phy_ctxt)3819continue;38203821iwl_mvm_rs_rate_init(mvm, vif, sta, conf, link_sta,3822mvmvif->link[link_id]->phy_ctxt->channel->band);3823}3824}38253826static bool iwl_mvm_vif_conf_from_sta(struct iwl_mvm *mvm,3827struct ieee80211_vif *vif,3828struct ieee80211_sta *sta)3829{3830struct ieee80211_link_sta *link_sta;3831unsigned int link_id;38323833/* Beacon interval check - firmware will crash if the beacon3834* interval is less than 16. We can't avoid connecting at all,3835* so refuse the station state change, this will cause mac802113836* to abandon attempts to connect to this AP, and eventually3837* wpa_s will blocklist the AP...3838*/38393840for_each_sta_active_link(vif, sta, link_sta, link_id) {3841struct ieee80211_bss_conf *link_conf =3842link_conf_dereference_protected(vif, link_id);38433844if (!link_conf)3845continue;38463847if (link_conf->beacon_int < IWL_MVM_MIN_BEACON_INTERVAL_TU) {3848IWL_ERR(mvm,3849"Beacon interval %d for AP %pM is too small\n",3850link_conf->beacon_int, link_sta->addr);3851return false;3852}38533854link_conf->he_support = link_sta->he_cap.has_he;3855}38563857return true;3858}38593860static void iwl_mvm_vif_set_he_support(struct ieee80211_hw *hw,3861struct ieee80211_vif *vif,3862struct ieee80211_sta *sta,3863bool is_sta)3864{3865struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);3866struct ieee80211_link_sta *link_sta;3867unsigned int link_id;38683869for_each_sta_active_link(vif, sta, link_sta, link_id) {3870struct ieee80211_bss_conf *link_conf =3871link_conf_dereference_protected(vif, link_id);38723873if (!link_conf || !mvmvif->link[link_id])3874continue;38753876link_conf->he_support = link_sta->he_cap.has_he;38773878if (is_sta) {3879mvmvif->link[link_id]->he_ru_2mhz_block = false;3880if (link_sta->he_cap.has_he)3881iwl_mvm_check_he_obss_narrow_bw_ru(hw, vif,3882link_id,3883link_conf);3884}3885}3886}38873888static int3889iwl_mvm_sta_state_notexist_to_none(struct iwl_mvm *mvm,3890struct ieee80211_vif *vif,3891struct ieee80211_sta *sta,3892const struct iwl_mvm_sta_state_ops *callbacks)3893{3894struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);3895struct ieee80211_link_sta *link_sta;3896unsigned int i;3897int ret;38983899lockdep_assert_held(&mvm->mutex);39003901if (vif->type == NL80211_IFTYPE_STATION &&3902!iwl_mvm_vif_conf_from_sta(mvm, vif, sta))3903return -EINVAL;39043905if (sta->tdls &&3906(vif->p2p ||3907iwl_mvm_tdls_sta_count(mvm, NULL) == IWL_TDLS_STA_COUNT ||3908iwl_mvm_phy_ctx_count(mvm) > 1)) {3909IWL_DEBUG_MAC80211(mvm, "refusing TDLS sta\n");3910return -EBUSY;3911}39123913ret = callbacks->add_sta(mvm, vif, sta);3914if (sta->tdls && ret == 0) {3915iwl_mvm_recalc_tdls_state(mvm, vif, true);3916iwl_mvm_tdls_check_trigger(mvm, vif, sta->addr,3917NL80211_TDLS_SETUP);3918}39193920if (ret)3921return ret;39223923for_each_sta_active_link(vif, sta, link_sta, i)3924link_sta->agg.max_rc_amsdu_len = 1;39253926ieee80211_sta_recalc_aggregates(sta);39273928if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls)3929mvmvif->ap_sta = sta;39303931/*3932* Initialize the rates here already - this really tells3933* the firmware only what the supported legacy rates are3934* (may be) since it's initialized already from what the3935* AP advertised in the beacon/probe response. This will3936* allow the firmware to send auth/assoc frames with one3937* of the supported rates already, rather than having to3938* use a mandatory rate.3939* If we're the AP, we'll just assume mandatory rates at3940* this point, but we know nothing about the STA anyway.3941*/3942iwl_mvm_rs_rate_init_all_links(mvm, vif, sta);39433944return 0;3945}39463947static int3948iwl_mvm_sta_state_auth_to_assoc(struct ieee80211_hw *hw,3949struct iwl_mvm *mvm,3950struct ieee80211_vif *vif,3951struct ieee80211_sta *sta,3952const struct iwl_mvm_sta_state_ops *callbacks)3953{3954struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);3955struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);3956struct ieee80211_link_sta *link_sta;3957unsigned int link_id;39583959lockdep_assert_held(&mvm->mutex);39603961if (vif->type == NL80211_IFTYPE_AP) {3962iwl_mvm_vif_set_he_support(hw, vif, sta, false);3963mvmvif->ap_assoc_sta_count++;3964callbacks->mac_ctxt_changed(mvm, vif, false);39653966/* since the below is not for MLD API, it's ok to use3967* the default bss_conf3968*/3969if (!mvm->mld_api_is_used &&3970(vif->bss_conf.he_support &&3971!iwlwifi_mod_params.disable_11ax))3972iwl_mvm_cfg_he_sta(mvm, vif, mvm_sta->deflink.sta_id);3973} else if (vif->type == NL80211_IFTYPE_STATION) {3974iwl_mvm_vif_set_he_support(hw, vif, sta, true);39753976callbacks->mac_ctxt_changed(mvm, vif, false);39773978if (!mvm->mld_api_is_used)3979goto out;39803981for_each_sta_active_link(vif, sta, link_sta, link_id) {3982struct ieee80211_bss_conf *link_conf =3983link_conf_dereference_protected(vif, link_id);39843985if (WARN_ON(!link_conf))3986return -EINVAL;3987if (!mvmvif->link[link_id])3988continue;39893990iwl_mvm_link_changed(mvm, vif, link_conf,3991LINK_CONTEXT_MODIFY_ALL &3992~LINK_CONTEXT_MODIFY_ACTIVE,3993true);3994}3995}39963997out:3998iwl_mvm_rs_rate_init_all_links(mvm, vif, sta);39994000return callbacks->update_sta(mvm, vif, sta);4001}40024003static int4004iwl_mvm_sta_state_assoc_to_authorized(struct iwl_mvm *mvm,4005struct ieee80211_vif *vif,4006struct ieee80211_sta *sta,4007const struct iwl_mvm_sta_state_ops *callbacks)4008{4009struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);4010struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);40114012lockdep_assert_held(&mvm->mutex);40134014/* we don't support TDLS during DCM */4015if (iwl_mvm_phy_ctx_count(mvm) > 1)4016iwl_mvm_teardown_tdls_peers(mvm);40174018if (sta->tdls) {4019iwl_mvm_tdls_check_trigger(mvm, vif, sta->addr,4020NL80211_TDLS_ENABLE_LINK);4021} else {4022/* enable beacon filtering */4023WARN_ON(iwl_mvm_enable_beacon_filter(mvm, vif));40244025mvmvif->authorized = 1;40264027if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) {4028mvmvif->link_selection_res = vif->active_links;4029mvmvif->link_selection_primary =4030vif->active_links ? __ffs(vif->active_links) : 0;4031}40324033callbacks->mac_ctxt_changed(mvm, vif, false);4034iwl_mvm_mei_host_associated(mvm, vif, mvm_sta);40354036memset(&mvmvif->last_esr_exit, 0,4037sizeof(mvmvif->last_esr_exit));40384039iwl_mvm_block_esr(mvm, vif, IWL_MVM_ESR_BLOCKED_TPT, 0);40404041/* Block until FW notif will arrive */4042iwl_mvm_block_esr(mvm, vif, IWL_MVM_ESR_BLOCKED_FW, 0);40434044/* when client is authorized (AP station marked as such),4045* try to enable the best link(s).4046*/4047if (vif->type == NL80211_IFTYPE_STATION &&4048!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))4049iwl_mvm_select_links(mvm, vif);4050}40514052mvm_sta->authorized = true;40534054/* MFP is set by default before the station is authorized.4055* Clear it here in case it's not used.4056*/4057if (!sta->mfp) {4058int ret = callbacks->update_sta(mvm, vif, sta);40594060if (ret)4061return ret;4062}40634064iwl_mvm_rs_rate_init_all_links(mvm, vif, sta);40654066return 0;4067}40684069static int4070iwl_mvm_sta_state_authorized_to_assoc(struct iwl_mvm *mvm,4071struct ieee80211_vif *vif,4072struct ieee80211_sta *sta,4073const struct iwl_mvm_sta_state_ops *callbacks)4074{4075struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);4076struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);40774078lockdep_assert_held(&mvm->mutex);40794080mvmsta->authorized = false;40814082/* once we move into assoc state, need to update rate scale to4083* disable using wide bandwidth4084*/4085iwl_mvm_rs_rate_init_all_links(mvm, vif, sta);40864087if (!sta->tdls) {4088/* Set this but don't call iwl_mvm_mac_ctxt_changed()4089* yet to avoid sending high prio again for a little4090* time.4091*/4092mvmvif->authorized = 0;4093mvmvif->link_selection_res = 0;40944095/* disable beacon filtering */4096iwl_mvm_disable_beacon_filter(mvm, vif);40974098wiphy_delayed_work_cancel(mvm->hw->wiphy,4099&mvmvif->prevent_esr_done_wk);41004101wiphy_delayed_work_cancel(mvm->hw->wiphy,4102&mvmvif->mlo_int_scan_wk);41034104wiphy_work_cancel(mvm->hw->wiphy, &mvmvif->unblock_esr_tpt_wk);4105wiphy_delayed_work_cancel(mvm->hw->wiphy,4106&mvmvif->unblock_esr_tmp_non_bss_wk);4107}41084109return 0;4110}41114112void iwl_mvm_smps_workaround(struct iwl_mvm *mvm, struct ieee80211_vif *vif,4113bool update)4114{4115struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);41164117if (!iwl_mvm_has_rlc_offload(mvm) ||4118iwl_fw_lookup_cmd_ver(mvm->fw, MAC_PM_POWER_TABLE, 0) >= 2)4119return;41204121mvmvif->ps_disabled = !vif->cfg.ps;41224123if (update)4124iwl_mvm_power_update_mac(mvm);4125}41264127/* Common part for MLD and non-MLD modes */4128int iwl_mvm_mac_sta_state_common(struct ieee80211_hw *hw,4129struct ieee80211_vif *vif,4130struct ieee80211_sta *sta,4131enum ieee80211_sta_state old_state,4132enum ieee80211_sta_state new_state,4133const struct iwl_mvm_sta_state_ops *callbacks)4134{4135struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);4136struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);4137struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);4138struct ieee80211_link_sta *link_sta;4139unsigned int link_id;4140int ret;41414142IWL_DEBUG_MAC80211(mvm, "station %pM state change %d->%d\n",4143sta->addr, old_state, new_state);41444145/*4146* If we are in a STA removal flow and in DQA mode:4147*4148* This is after the sync_rcu part, so the queues have already been4149* flushed. No more TXs on their way in mac80211's path, and no more in4150* the queues.4151* Also, we won't be getting any new TX frames for this station.4152* What we might have are deferred TX frames that need to be taken care4153* of.4154*4155* Drop any still-queued deferred-frame before removing the STA, and4156* make sure the worker is no longer handling frames for this STA.4157*/4158if (old_state == IEEE80211_STA_NONE &&4159new_state == IEEE80211_STA_NOTEXIST) {4160flush_work(&mvm->add_stream_wk);41614162/*4163* No need to make sure deferred TX indication is off since the4164* worker will already remove it if it was on4165*/41664167/*4168* Additionally, reset the 40 MHz capability if we disconnected4169* from the AP now.4170*/4171iwl_mvm_reset_cca_40mhz_workaround(mvm, vif);41724173/* Also free dup data just in case any assertions below fail */4174kfree(mvm_sta->dup_data);4175}41764177mutex_lock(&mvm->mutex);41784179/* this would be a mac80211 bug ... but don't crash, unless we had a4180* firmware crash while we were activating a link, in which case it is4181* legit to have phy_ctxt = NULL. Don't bother not to WARN if we are in4182* recovery flow since we spit tons of error messages anyway.4183*/4184for_each_sta_active_link(vif, sta, link_sta, link_id) {4185if (WARN_ON_ONCE(!mvmvif->link[link_id] ||4186!mvmvif->link[link_id]->phy_ctxt)) {4187mutex_unlock(&mvm->mutex);4188return test_bit(IWL_MVM_STATUS_HW_RESTART_REQUESTED,4189&mvm->status) ? 0 : -EINVAL;4190}4191}41924193/* track whether or not the station is associated */4194mvm_sta->sta_state = new_state;41954196if (old_state == IEEE80211_STA_NOTEXIST &&4197new_state == IEEE80211_STA_NONE) {4198ret = iwl_mvm_sta_state_notexist_to_none(mvm, vif, sta,4199callbacks);4200if (ret < 0)4201goto out_unlock;4202} else if (old_state == IEEE80211_STA_NONE &&4203new_state == IEEE80211_STA_AUTH) {4204/*4205* EBS may be disabled due to previous failures reported by FW.4206* Reset EBS status here assuming environment has been changed.4207*/4208mvm->last_ebs_successful = true;4209iwl_mvm_check_uapsd(mvm, vif, sta->addr);4210ret = 0;4211} else if (old_state == IEEE80211_STA_AUTH &&4212new_state == IEEE80211_STA_ASSOC) {4213ret = iwl_mvm_sta_state_auth_to_assoc(hw, mvm, vif, sta,4214callbacks);4215} else if (old_state == IEEE80211_STA_ASSOC &&4216new_state == IEEE80211_STA_AUTHORIZED) {4217ret = iwl_mvm_sta_state_assoc_to_authorized(mvm, vif, sta,4218callbacks);4219iwl_mvm_smps_workaround(mvm, vif, true);4220} else if (old_state == IEEE80211_STA_AUTHORIZED &&4221new_state == IEEE80211_STA_ASSOC) {4222ret = iwl_mvm_sta_state_authorized_to_assoc(mvm, vif, sta,4223callbacks);4224} else if (old_state == IEEE80211_STA_ASSOC &&4225new_state == IEEE80211_STA_AUTH) {4226if (vif->type == NL80211_IFTYPE_AP) {4227mvmvif->ap_assoc_sta_count--;4228callbacks->mac_ctxt_changed(mvm, vif, false);4229} else if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls)4230iwl_mvm_stop_session_protection(mvm, vif);4231ret = 0;4232} else if (old_state == IEEE80211_STA_AUTH &&4233new_state == IEEE80211_STA_NONE) {4234ret = 0;4235} else if (old_state == IEEE80211_STA_NONE &&4236new_state == IEEE80211_STA_NOTEXIST) {4237if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) {4238iwl_mvm_stop_session_protection(mvm, vif);4239mvmvif->ap_sta = NULL;4240}4241ret = callbacks->rm_sta(mvm, vif, sta);4242if (sta->tdls) {4243iwl_mvm_recalc_tdls_state(mvm, vif, false);4244iwl_mvm_tdls_check_trigger(mvm, vif, sta->addr,4245NL80211_TDLS_DISABLE_LINK);4246}42474248if (unlikely(ret &&4249test_bit(IWL_MVM_STATUS_HW_RESTART_REQUESTED,4250&mvm->status)))4251ret = 0;4252} else {4253ret = -EIO;4254}4255out_unlock:4256mutex_unlock(&mvm->mutex);42574258if (sta->tdls && ret == 0) {4259if (old_state == IEEE80211_STA_NOTEXIST &&4260new_state == IEEE80211_STA_NONE)4261ieee80211_reserve_tid(sta, IWL_MVM_TDLS_FW_TID);4262else if (old_state == IEEE80211_STA_NONE &&4263new_state == IEEE80211_STA_NOTEXIST)4264ieee80211_unreserve_tid(sta, IWL_MVM_TDLS_FW_TID);4265}42664267return ret;4268}42694270int iwl_mvm_mac_set_rts_threshold(struct ieee80211_hw *hw, int radio_idx,4271u32 value)4272{4273struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);42744275mvm->rts_threshold = value;42764277return 0;4278}42794280void iwl_mvm_sta_rc_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif,4281struct ieee80211_link_sta *link_sta, u32 changed)4282{4283struct ieee80211_sta *sta = link_sta->sta;4284struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);42854286if (changed & (IEEE80211_RC_BW_CHANGED |4287IEEE80211_RC_SUPP_RATES_CHANGED |4288IEEE80211_RC_NSS_CHANGED))4289iwl_mvm_rs_rate_init_all_links(mvm, vif, sta);42904291if (vif->type == NL80211_IFTYPE_STATION &&4292changed & IEEE80211_RC_NSS_CHANGED)4293iwl_mvm_sf_update(mvm, vif, false);4294}42954296static int iwl_mvm_mac_conf_tx(struct ieee80211_hw *hw,4297struct ieee80211_vif *vif,4298unsigned int link_id, u16 ac,4299const struct ieee80211_tx_queue_params *params)4300{4301struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);4302struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);43034304mvmvif->deflink.queue_params[ac] = *params;43054306/*4307* No need to update right away, we'll get BSS_CHANGED_QOS4308* The exception is P2P_DEVICE interface which needs immediate update.4309*/4310if (vif->type == NL80211_IFTYPE_P2P_DEVICE) {4311guard(mvm)(mvm);4312return iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL);4313}4314return 0;4315}43164317void iwl_mvm_mac_mgd_prepare_tx(struct ieee80211_hw *hw,4318struct ieee80211_vif *vif,4319struct ieee80211_prep_tx_info *info)4320{4321struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);4322struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);43234324if (info->was_assoc && !mvmvif->session_prot_connection_loss)4325return;43264327guard(mvm)(mvm);4328iwl_mvm_protect_assoc(mvm, vif, info->duration, info->link_id);4329}43304331void iwl_mvm_mac_mgd_complete_tx(struct ieee80211_hw *hw,4332struct ieee80211_vif *vif,4333struct ieee80211_prep_tx_info *info)4334{4335struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);43364337/* for successful cases (auth/assoc), don't cancel session protection */4338if (info->success)4339return;43404341guard(mvm)(mvm);4342iwl_mvm_stop_session_protection(mvm, vif);4343}43444345int iwl_mvm_mac_sched_scan_start(struct ieee80211_hw *hw,4346struct ieee80211_vif *vif,4347struct cfg80211_sched_scan_request *req,4348struct ieee80211_scan_ies *ies)4349{4350struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);43514352guard(mvm)(mvm);43534354if (!vif->cfg.idle)4355return -EBUSY;43564357return iwl_mvm_sched_scan_start(mvm, vif, req, ies, IWL_MVM_SCAN_SCHED);4358}43594360int iwl_mvm_mac_sched_scan_stop(struct ieee80211_hw *hw,4361struct ieee80211_vif *vif)4362{4363struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);4364int ret;43654366mutex_lock(&mvm->mutex);43674368/* Due to a race condition, it's possible that mac80211 asks4369* us to stop a sched_scan when it's already stopped. This4370* can happen, for instance, if we stopped the scan ourselves,4371* called ieee80211_sched_scan_stopped() and the userspace called4372* stop sched scan before ieee80211_sched_scan_stopped_work()4373* could run. To handle this, simply return if the scan is4374* not running.4375*/4376if (!(mvm->scan_status & IWL_MVM_SCAN_SCHED)) {4377mutex_unlock(&mvm->mutex);4378return 0;4379}43804381ret = iwl_mvm_scan_stop(mvm, IWL_MVM_SCAN_SCHED, false);4382mutex_unlock(&mvm->mutex);4383iwl_mvm_wait_for_async_handlers(mvm);43844385return ret;4386}43874388static int __iwl_mvm_mac_set_key(struct ieee80211_hw *hw,4389enum set_key_cmd cmd,4390struct ieee80211_vif *vif,4391struct ieee80211_sta *sta,4392struct ieee80211_key_conf *key)4393{4394struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);4395struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);4396struct iwl_mvm_sta *mvmsta = NULL;4397struct iwl_mvm_key_pn *ptk_pn = NULL;4398int keyidx = key->keyidx;4399u32 sec_key_id = WIDE_ID(DATA_PATH_GROUP, SEC_KEY_CMD);4400u8 sec_key_ver = iwl_fw_lookup_cmd_ver(mvm->fw, sec_key_id, 0);4401int ret, i;4402u8 key_offset;44034404if (sta)4405mvmsta = iwl_mvm_sta_from_mac80211(sta);44064407switch (key->cipher) {4408case WLAN_CIPHER_SUITE_TKIP:4409if (!mvm->trans->mac_cfg->gen2) {4410key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;4411key->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE;4412} else if (vif->type == NL80211_IFTYPE_STATION) {4413key->flags |= IEEE80211_KEY_FLAG_PUT_MIC_SPACE;4414} else {4415IWL_DEBUG_MAC80211(mvm, "Use SW encryption for TKIP\n");4416return -EOPNOTSUPP;4417}4418break;4419case WLAN_CIPHER_SUITE_CCMP:4420case WLAN_CIPHER_SUITE_GCMP:4421case WLAN_CIPHER_SUITE_GCMP_256:4422if (!iwl_mvm_has_new_tx_api(mvm))4423key->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE;4424break;4425case WLAN_CIPHER_SUITE_AES_CMAC:4426case WLAN_CIPHER_SUITE_BIP_GMAC_128:4427case WLAN_CIPHER_SUITE_BIP_GMAC_256:4428WARN_ON_ONCE(!ieee80211_hw_check(hw, MFP_CAPABLE));4429break;4430case WLAN_CIPHER_SUITE_WEP40:4431case WLAN_CIPHER_SUITE_WEP104:4432if (vif->type == NL80211_IFTYPE_STATION)4433break;4434if (iwl_mvm_has_new_tx_api(mvm))4435return -EOPNOTSUPP;4436/* support HW crypto on TX */4437return 0;4438default:4439return -EOPNOTSUPP;4440}44414442switch (cmd) {4443case SET_KEY:4444if (vif->type == NL80211_IFTYPE_STATION &&4445(keyidx == 6 || keyidx == 7))4446rcu_assign_pointer(mvmvif->bcn_prot.keys[keyidx - 6],4447key);44484449if ((vif->type == NL80211_IFTYPE_ADHOC ||4450vif->type == NL80211_IFTYPE_AP) && !sta) {4451/*4452* GTK on AP interface is a TX-only key, return 0;4453* on IBSS they're per-station and because we're lazy4454* we don't support them for RX, so do the same.4455* CMAC/GMAC in AP/IBSS modes must be done in software4456* on older NICs.4457*4458* Except, of course, beacon protection - it must be4459* offloaded since we just set a beacon template, and4460* then we must also offload the IGTK (not just BIGTK)4461* for firmware reasons.4462*4463* So just check for beacon protection - if we don't4464* have it we cannot get here with keyidx >= 6, and4465* if we do have it we need to send the key to FW in4466* all cases (CMAC/GMAC).4467*/4468if (!wiphy_ext_feature_isset(hw->wiphy,4469NL80211_EXT_FEATURE_BEACON_PROTECTION) &&4470(key->cipher == WLAN_CIPHER_SUITE_AES_CMAC ||4471key->cipher == WLAN_CIPHER_SUITE_BIP_GMAC_128 ||4472key->cipher == WLAN_CIPHER_SUITE_BIP_GMAC_256)) {4473ret = -EOPNOTSUPP;4474break;4475}44764477if (key->cipher != WLAN_CIPHER_SUITE_GCMP &&4478key->cipher != WLAN_CIPHER_SUITE_GCMP_256 &&4479!iwl_mvm_has_new_tx_api(mvm)) {4480key->hw_key_idx = STA_KEY_IDX_INVALID;4481ret = 0;4482break;4483}44844485if (!mvmvif->ap_ibss_active) {4486for (i = 0;4487i < ARRAY_SIZE(mvmvif->ap_early_keys);4488i++) {4489if (!mvmvif->ap_early_keys[i]) {4490mvmvif->ap_early_keys[i] = key;4491break;4492}4493}44944495if (i >= ARRAY_SIZE(mvmvif->ap_early_keys))4496ret = -ENOSPC;4497else4498ret = 0;44994500break;4501}4502}45034504/* During FW restart, in order to restore the state as it was,4505* don't try to reprogram keys we previously failed for.4506*/4507if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) &&4508key->hw_key_idx == STA_KEY_IDX_INVALID) {4509IWL_DEBUG_MAC80211(mvm,4510"skip invalid idx key programming during restart\n");4511ret = 0;4512break;4513}45144515if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) &&4516mvmsta && iwl_mvm_has_new_rx_api(mvm) &&4517key->flags & IEEE80211_KEY_FLAG_PAIRWISE &&4518(key->cipher == WLAN_CIPHER_SUITE_CCMP ||4519key->cipher == WLAN_CIPHER_SUITE_GCMP ||4520key->cipher == WLAN_CIPHER_SUITE_GCMP_256)) {4521struct ieee80211_key_seq seq;4522int tid, q;45234524WARN_ON(rcu_access_pointer(mvmsta->ptk_pn[keyidx]));4525ptk_pn = kzalloc(struct_size(ptk_pn, q,4526mvm->trans->info.num_rxqs),4527GFP_KERNEL);4528if (!ptk_pn) {4529ret = -ENOMEM;4530break;4531}45324533for (tid = 0; tid < IWL_MAX_TID_COUNT; tid++) {4534ieee80211_get_key_rx_seq(key, tid, &seq);4535for (q = 0; q < mvm->trans->info.num_rxqs; q++)4536memcpy(ptk_pn->q[q].pn[tid],4537seq.ccmp.pn,4538IEEE80211_CCMP_PN_LEN);4539}45404541rcu_assign_pointer(mvmsta->ptk_pn[keyidx], ptk_pn);4542}45434544/* in HW restart reuse the index, otherwise request a new one */4545if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))4546key_offset = key->hw_key_idx;4547else4548key_offset = STA_KEY_IDX_INVALID;45494550if (mvmsta && key->flags & IEEE80211_KEY_FLAG_PAIRWISE)4551mvmsta->pairwise_cipher = key->cipher;45524553IWL_DEBUG_MAC80211(mvm, "set hwcrypto key (sta:%pM, id:%d)\n",4554sta ? sta->addr : NULL, key->keyidx);45554556if (sec_key_ver)4557ret = iwl_mvm_sec_key_add(mvm, vif, sta, key);4558else4559ret = iwl_mvm_set_sta_key(mvm, vif, sta, key, key_offset);45604561if (ret) {4562IWL_WARN(mvm, "set key failed\n");4563key->hw_key_idx = STA_KEY_IDX_INVALID;4564if (ptk_pn) {4565RCU_INIT_POINTER(mvmsta->ptk_pn[keyidx], NULL);4566kfree(ptk_pn);4567}4568/*4569* can't add key for RX, but we don't need it4570* in the device for TX so still return 0,4571* unless we have new TX API where we cannot4572* put key material into the TX_CMD4573*/4574if (iwl_mvm_has_new_tx_api(mvm))4575ret = -EOPNOTSUPP;4576else4577ret = 0;4578}45794580break;4581case DISABLE_KEY:4582if (vif->type == NL80211_IFTYPE_STATION &&4583(keyidx == 6 || keyidx == 7))4584RCU_INIT_POINTER(mvmvif->bcn_prot.keys[keyidx - 6],4585NULL);45864587ret = -ENOENT;4588for (i = 0; i < ARRAY_SIZE(mvmvif->ap_early_keys); i++) {4589if (mvmvif->ap_early_keys[i] == key) {4590mvmvif->ap_early_keys[i] = NULL;4591ret = 0;4592}4593}45944595/* found in pending list - don't do anything else */4596if (ret == 0)4597break;45984599if (key->hw_key_idx == STA_KEY_IDX_INVALID) {4600ret = 0;4601break;4602}46034604if (mvmsta && iwl_mvm_has_new_rx_api(mvm) &&4605key->flags & IEEE80211_KEY_FLAG_PAIRWISE &&4606(key->cipher == WLAN_CIPHER_SUITE_CCMP ||4607key->cipher == WLAN_CIPHER_SUITE_GCMP ||4608key->cipher == WLAN_CIPHER_SUITE_GCMP_256)) {4609ptk_pn = rcu_dereference_protected(4610mvmsta->ptk_pn[keyidx],4611lockdep_is_held(&mvm->mutex));4612RCU_INIT_POINTER(mvmsta->ptk_pn[keyidx], NULL);4613if (ptk_pn)4614kfree_rcu(ptk_pn, rcu_head);4615}46164617IWL_DEBUG_MAC80211(mvm, "disable hwcrypto key\n");4618if (sec_key_ver)4619ret = iwl_mvm_sec_key_del(mvm, vif, sta, key);4620else4621ret = iwl_mvm_remove_sta_key(mvm, vif, sta, key);4622break;4623default:4624ret = -EINVAL;4625}46264627return ret;4628}46294630int iwl_mvm_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,4631struct ieee80211_vif *vif, struct ieee80211_sta *sta,4632struct ieee80211_key_conf *key)4633{4634struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);46354636/* When resuming from wowlan, FW already knows about the newest keys */4637if (test_bit(IWL_MVM_STATUS_IN_D3, &mvm->status))4638return 0;46394640guard(mvm)(mvm);4641return __iwl_mvm_mac_set_key(hw, cmd, vif, sta, key);4642}46434644void iwl_mvm_mac_update_tkip_key(struct ieee80211_hw *hw,4645struct ieee80211_vif *vif,4646struct ieee80211_key_conf *keyconf,4647struct ieee80211_sta *sta,4648u32 iv32, u16 *phase1key)4649{4650struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);46514652if (keyconf->hw_key_idx == STA_KEY_IDX_INVALID)4653return;46544655iwl_mvm_update_tkip_key(mvm, vif, keyconf, sta, iv32, phase1key);4656}465746584659static bool iwl_mvm_rx_aux_roc(struct iwl_notif_wait_data *notif_wait,4660struct iwl_rx_packet *pkt, void *data)4661{4662struct iwl_mvm *mvm =4663container_of(notif_wait, struct iwl_mvm, notif_wait);4664struct iwl_hs20_roc_res *resp;4665int resp_len = iwl_rx_packet_payload_len(pkt);4666struct iwl_mvm_time_event_data *te_data = data;46674668if (WARN_ON(pkt->hdr.cmd != HOT_SPOT_CMD))4669return true;46704671if (WARN_ON_ONCE(resp_len != sizeof(*resp))) {4672IWL_ERR(mvm, "Invalid HOT_SPOT_CMD response\n");4673return true;4674}46754676resp = (void *)pkt->data;46774678IWL_DEBUG_TE(mvm,4679"Aux ROC: Received response from ucode: status=%d uid=%d\n",4680resp->status, resp->event_unique_id);46814682te_data->uid = le32_to_cpu(resp->event_unique_id);4683IWL_DEBUG_TE(mvm, "TIME_EVENT_CMD response - UID = 0x%x\n",4684te_data->uid);46854686spin_lock_bh(&mvm->time_event_lock);4687list_add_tail(&te_data->list, &mvm->aux_roc_te_list);4688spin_unlock_bh(&mvm->time_event_lock);46894690return true;4691}46924693static int iwl_mvm_send_aux_roc_cmd(struct iwl_mvm *mvm,4694struct ieee80211_channel *channel,4695struct ieee80211_vif *vif,4696int duration)4697{4698int res;4699struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);4700struct iwl_mvm_time_event_data *te_data = &mvmvif->hs_time_event_data;4701static const u16 time_event_response[] = { HOT_SPOT_CMD };4702struct iwl_notification_wait wait_time_event;4703u32 req_dur, delay;4704struct iwl_hs20_roc_req aux_roc_req = {4705.action = cpu_to_le32(FW_CTXT_ACTION_ADD),4706.id_and_color =4707cpu_to_le32(FW_CMD_ID_AND_COLOR(MAC_INDEX_AUX, 0)),4708.sta_id_and_color = cpu_to_le32(mvm->aux_sta.sta_id),4709};4710struct iwl_hs20_roc_req_tail *tail = iwl_mvm_chan_info_cmd_tail(mvm,4711&aux_roc_req.channel_info);4712u16 len = sizeof(aux_roc_req) - iwl_mvm_chan_info_padding(mvm);47134714/* Set the channel info data */4715iwl_mvm_set_chan_info(mvm, &aux_roc_req.channel_info, channel->hw_value,4716iwl_mvm_phy_band_from_nl80211(channel->band),4717IWL_PHY_CHANNEL_MODE20,47180);47194720/* Set the time and duration */4721tail->apply_time = cpu_to_le32(iwl_mvm_get_systime(mvm));47224723iwl_mvm_roc_duration_and_delay(vif, duration, &req_dur, &delay);4724tail->duration = cpu_to_le32(req_dur);4725tail->apply_time_max_delay = cpu_to_le32(delay);47264727IWL_DEBUG_TE(mvm,4728"ROC: Requesting to remain on channel %u for %ums\n",4729channel->hw_value, req_dur);4730IWL_DEBUG_TE(mvm,4731"\t(requested = %ums, max_delay = %ums)\n",4732duration, delay);47334734/* Set the node address */4735memcpy(tail->node_addr, vif->addr, ETH_ALEN);47364737lockdep_assert_held(&mvm->mutex);47384739spin_lock_bh(&mvm->time_event_lock);47404741if (WARN_ON(te_data->id == HOT_SPOT_CMD)) {4742spin_unlock_bh(&mvm->time_event_lock);4743return -EIO;4744}47454746te_data->vif = vif;4747te_data->duration = duration;4748te_data->id = HOT_SPOT_CMD;47494750spin_unlock_bh(&mvm->time_event_lock);47514752/*4753* Use a notification wait, which really just processes the4754* command response and doesn't wait for anything, in order4755* to be able to process the response and get the UID inside4756* the RX path. Using CMD_WANT_SKB doesn't work because it4757* stores the buffer and then wakes up this thread, by which4758* time another notification (that the time event started)4759* might already be processed unsuccessfully.4760*/4761iwl_init_notification_wait(&mvm->notif_wait, &wait_time_event,4762time_event_response,4763ARRAY_SIZE(time_event_response),4764iwl_mvm_rx_aux_roc, te_data);47654766res = iwl_mvm_send_cmd_pdu(mvm, HOT_SPOT_CMD, 0, len,4767&aux_roc_req);47684769if (res) {4770IWL_ERR(mvm, "Couldn't send HOT_SPOT_CMD: %d\n", res);4771iwl_remove_notification(&mvm->notif_wait, &wait_time_event);4772goto out_clear_te;4773}47744775/* No need to wait for anything, so just pass 1 (0 isn't valid) */4776res = iwl_wait_notification(&mvm->notif_wait, &wait_time_event, 1);4777/* should never fail */4778WARN_ON_ONCE(res);47794780if (res) {4781out_clear_te:4782spin_lock_bh(&mvm->time_event_lock);4783iwl_mvm_te_clear_data(mvm, te_data);4784spin_unlock_bh(&mvm->time_event_lock);4785}47864787return res;4788}47894790static int iwl_mvm_add_aux_sta_for_hs20(struct iwl_mvm *mvm, u32 lmac_id)4791{4792int ret = 0;47934794lockdep_assert_held(&mvm->mutex);47954796if (!fw_has_capa(&mvm->fw->ucode_capa,4797IWL_UCODE_TLV_CAPA_HOTSPOT_SUPPORT)) {4798IWL_ERR(mvm, "hotspot not supported\n");4799return -EINVAL;4800}48014802if (iwl_mvm_has_new_station_api(mvm->fw)) {4803ret = iwl_mvm_add_aux_sta(mvm, lmac_id);4804WARN(ret, "Failed to allocate aux station");4805}48064807return ret;4808}48094810static int iwl_mvm_roc_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif)4811{4812int ret;48134814lockdep_assert_held(&mvm->mutex);48154816ret = iwl_mvm_binding_add_vif(mvm, vif);4817if (WARN(ret, "Failed binding P2P_DEVICE\n"))4818return ret;48194820/* The station and queue allocation must be done only after the binding4821* is done, as otherwise the FW might incorrectly configure its state.4822*/4823return iwl_mvm_add_p2p_bcast_sta(mvm, vif);4824}48254826static int iwl_mvm_roc(struct ieee80211_hw *hw,4827struct ieee80211_vif *vif,4828struct ieee80211_channel *channel,4829int duration,4830enum ieee80211_roc_type type)4831{4832static const struct iwl_mvm_roc_ops ops = {4833.add_aux_sta_for_hs20 = iwl_mvm_add_aux_sta_for_hs20,4834.link = iwl_mvm_roc_link,4835};48364837return iwl_mvm_roc_common(hw, vif, channel, duration, type, &ops);4838}48394840static int iwl_mvm_roc_station(struct iwl_mvm *mvm,4841struct ieee80211_channel *channel,4842struct ieee80211_vif *vif,4843int duration)4844{4845int ret;4846u32 cmd_id = WIDE_ID(MAC_CONF_GROUP, ROC_CMD);4847u8 fw_ver = iwl_fw_lookup_cmd_ver(mvm->fw, cmd_id,4848IWL_FW_CMD_VER_UNKNOWN);48494850if (fw_ver == IWL_FW_CMD_VER_UNKNOWN) {4851ret = iwl_mvm_send_aux_roc_cmd(mvm, channel, vif, duration);4852} else if (fw_ver >= 3) {4853ret = iwl_mvm_roc_add_cmd(mvm, channel, vif, duration,4854ROC_ACTIVITY_HOTSPOT);4855} else {4856ret = -EOPNOTSUPP;4857IWL_ERR(mvm, "ROC command version %d mismatch!\n", fw_ver);4858}48594860return ret;4861}48624863static int iwl_mvm_roc_p2p(struct iwl_mvm *mvm,4864struct ieee80211_channel *channel,4865struct ieee80211_vif *vif,4866int duration,4867enum ieee80211_roc_type type)4868{4869enum iwl_roc_activity activity;4870int ret;48714872lockdep_assert_held(&mvm->mutex);48734874switch (type) {4875case IEEE80211_ROC_TYPE_NORMAL:4876activity = ROC_ACTIVITY_P2P_DISC;4877break;4878case IEEE80211_ROC_TYPE_MGMT_TX:4879activity = ROC_ACTIVITY_P2P_NEG;4880break;4881default:4882WARN_ONCE(1, "Got an invalid P2P ROC type\n");4883return -EINVAL;4884}48854886ret = iwl_mvm_mld_add_aux_sta(mvm,4887iwl_mvm_get_lmac_id(mvm, channel->band));4888if (ret)4889return ret;48904891return iwl_mvm_roc_add_cmd(mvm, channel, vif, duration, activity);4892}48934894static int iwl_mvm_p2p_find_phy_ctxt(struct iwl_mvm *mvm,4895struct ieee80211_vif *vif,4896struct ieee80211_channel *channel)4897{4898struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);4899struct cfg80211_chan_def chandef;4900int i;49014902lockdep_assert_held(&mvm->mutex);49034904if (mvmvif->deflink.phy_ctxt &&4905channel == mvmvif->deflink.phy_ctxt->channel)4906return 0;49074908/* Try using a PHY context that is already in use */4909for (i = 0; i < NUM_PHY_CTX; i++) {4910struct iwl_mvm_phy_ctxt *phy_ctxt = &mvm->phy_ctxts[i];49114912if (!phy_ctxt->ref || mvmvif->deflink.phy_ctxt == phy_ctxt)4913continue;49144915if (channel == phy_ctxt->channel) {4916if (mvmvif->deflink.phy_ctxt)4917iwl_mvm_phy_ctxt_unref(mvm,4918mvmvif->deflink.phy_ctxt);49194920mvmvif->deflink.phy_ctxt = phy_ctxt;4921iwl_mvm_phy_ctxt_ref(mvm, mvmvif->deflink.phy_ctxt);4922return 0;4923}4924}49254926/* We already have a phy_ctxt, but it's not on the right channel */4927if (mvmvif->deflink.phy_ctxt)4928iwl_mvm_phy_ctxt_unref(mvm, mvmvif->deflink.phy_ctxt);49294930mvmvif->deflink.phy_ctxt = iwl_mvm_get_free_phy_ctxt(mvm);4931if (!mvmvif->deflink.phy_ctxt)4932return -ENOSPC;49334934cfg80211_chandef_create(&chandef, channel, NL80211_CHAN_NO_HT);49354936return iwl_mvm_phy_ctxt_add(mvm, mvmvif->deflink.phy_ctxt,4937&chandef, NULL, 1, 1);4938}49394940/* Execute the common part for MLD and non-MLD modes */4941int iwl_mvm_roc_common(struct ieee80211_hw *hw, struct ieee80211_vif *vif,4942struct ieee80211_channel *channel, int duration,4943enum ieee80211_roc_type type,4944const struct iwl_mvm_roc_ops *ops)4945{4946struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);4947struct ieee80211_vif *bss_vif = iwl_mvm_get_bss_vif(mvm);4948u32 lmac_id;4949int ret;49504951IWL_DEBUG_MAC80211(mvm, "enter (%d, %d, %d)\n", channel->hw_value,4952duration, type);49534954/*4955* Flush the done work, just in case it's still pending, so that4956* the work it does can complete and we can accept new frames.4957*/4958flush_work(&mvm->roc_done_wk);49594960if (!IS_ERR_OR_NULL(bss_vif)) {4961ret = iwl_mvm_block_esr_sync(mvm, bss_vif,4962IWL_MVM_ESR_BLOCKED_ROC);4963if (ret)4964return ret;4965}49664967guard(mvm)(mvm);49684969switch (vif->type) {4970case NL80211_IFTYPE_STATION:4971lmac_id = iwl_mvm_get_lmac_id(mvm, channel->band);49724973/* Use aux roc framework (HS20) */4974ret = ops->add_aux_sta_for_hs20(mvm, lmac_id);4975if (!ret)4976ret = iwl_mvm_roc_station(mvm, channel, vif, duration);4977return ret;4978case NL80211_IFTYPE_P2P_DEVICE:4979/* handle below */4980break;4981default:4982IWL_ERR(mvm, "ROC: Invalid vif type=%u\n", vif->type);4983return -EINVAL;4984}49854986if (iwl_mvm_has_p2p_over_aux(mvm)) {4987ret = iwl_mvm_roc_p2p(mvm, channel, vif, duration, type);4988return ret;4989}49904991ret = iwl_mvm_p2p_find_phy_ctxt(mvm, vif, channel);4992if (ret)4993return ret;49944995ret = ops->link(mvm, vif);4996if (ret)4997return ret;49984999return iwl_mvm_start_p2p_roc(mvm, vif, duration, type);5000}50015002int iwl_mvm_cancel_roc(struct ieee80211_hw *hw,5003struct ieee80211_vif *vif)5004{5005struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);50065007IWL_DEBUG_MAC80211(mvm, "enter\n");50085009iwl_mvm_stop_roc(mvm, vif);50105011IWL_DEBUG_MAC80211(mvm, "leave\n");5012return 0;5013}50145015struct iwl_mvm_chanctx_usage_data {5016struct iwl_mvm *mvm;5017struct ieee80211_chanctx_conf *ctx;5018bool use_def;5019};50205021static void iwl_mvm_chanctx_usage_iter(void *_data, u8 *mac,5022struct ieee80211_vif *vif)5023{5024struct iwl_mvm_chanctx_usage_data *data = _data;5025struct ieee80211_bss_conf *link_conf;5026int link_id;50275028for_each_vif_active_link(vif, link_conf, link_id) {5029if (rcu_access_pointer(link_conf->chanctx_conf) != data->ctx)5030continue;50315032if (iwl_mvm_enable_fils(data->mvm, vif, data->ctx))5033data->use_def = true;50345035if (vif->type == NL80211_IFTYPE_AP && link_conf->ftmr_params)5036data->use_def = true;5037}5038}50395040struct cfg80211_chan_def *5041iwl_mvm_chanctx_def(struct iwl_mvm *mvm, struct ieee80211_chanctx_conf *ctx)5042{5043struct iwl_mvm_chanctx_usage_data data = {5044.mvm = mvm,5045.ctx = ctx,5046.use_def = false,5047};50485049ieee80211_iterate_active_interfaces_atomic(mvm->hw,5050IEEE80211_IFACE_ITER_NORMAL,5051iwl_mvm_chanctx_usage_iter,5052&data);50535054return data.use_def ? &ctx->def : &ctx->min_def;5055}50565057static int __iwl_mvm_add_chanctx(struct iwl_mvm *mvm,5058struct ieee80211_chanctx_conf *ctx)5059{5060u16 *phy_ctxt_id = (u16 *)ctx->drv_priv;5061struct iwl_mvm_phy_ctxt *phy_ctxt;5062struct cfg80211_chan_def *def = iwl_mvm_chanctx_def(mvm, ctx);5063int ret;50645065lockdep_assert_held(&mvm->mutex);50665067IWL_DEBUG_MAC80211(mvm, "Add channel context\n");50685069phy_ctxt = iwl_mvm_get_free_phy_ctxt(mvm);5070if (!phy_ctxt) {5071ret = -ENOSPC;5072goto out;5073}50745075ret = iwl_mvm_phy_ctxt_add(mvm, phy_ctxt, def, &ctx->ap,5076ctx->rx_chains_static,5077ctx->rx_chains_dynamic);5078if (ret) {5079IWL_ERR(mvm, "Failed to add PHY context\n");5080goto out;5081}50825083*phy_ctxt_id = phy_ctxt->id;5084out:5085return ret;5086}50875088int iwl_mvm_add_chanctx(struct ieee80211_hw *hw,5089struct ieee80211_chanctx_conf *ctx)5090{5091struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);50925093guard(mvm)(mvm);5094return __iwl_mvm_add_chanctx(mvm, ctx);5095}50965097static void __iwl_mvm_remove_chanctx(struct iwl_mvm *mvm,5098struct ieee80211_chanctx_conf *ctx)5099{5100u16 *phy_ctxt_id = (u16 *)ctx->drv_priv;5101struct iwl_mvm_phy_ctxt *phy_ctxt = &mvm->phy_ctxts[*phy_ctxt_id];51025103lockdep_assert_held(&mvm->mutex);51045105iwl_mvm_phy_ctxt_unref(mvm, phy_ctxt);5106}51075108void iwl_mvm_remove_chanctx(struct ieee80211_hw *hw,5109struct ieee80211_chanctx_conf *ctx)5110{5111struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);51125113guard(mvm)(mvm);5114__iwl_mvm_remove_chanctx(mvm, ctx);5115}51165117void iwl_mvm_change_chanctx(struct ieee80211_hw *hw,5118struct ieee80211_chanctx_conf *ctx, u32 changed)5119{5120struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);5121u16 *phy_ctxt_id = (u16 *)ctx->drv_priv;5122struct iwl_mvm_phy_ctxt *phy_ctxt = &mvm->phy_ctxts[*phy_ctxt_id];5123struct cfg80211_chan_def *def = iwl_mvm_chanctx_def(mvm, ctx);51245125if (WARN_ONCE((phy_ctxt->ref > 1) &&5126(changed & ~(IEEE80211_CHANCTX_CHANGE_WIDTH |5127IEEE80211_CHANCTX_CHANGE_RX_CHAINS |5128IEEE80211_CHANCTX_CHANGE_RADAR |5129IEEE80211_CHANCTX_CHANGE_MIN_DEF)),5130"Cannot change PHY. Ref=%d, changed=0x%X\n",5131phy_ctxt->ref, changed))5132return;51335134guard(mvm)(mvm);51355136/* we are only changing the min_width, may be a noop */5137if (changed == IEEE80211_CHANCTX_CHANGE_MIN_DEF) {5138if (phy_ctxt->width == def->width)5139return;51405141/* we are just toggling between 20_NOHT and 20 */5142if (phy_ctxt->width <= NL80211_CHAN_WIDTH_20 &&5143def->width <= NL80211_CHAN_WIDTH_20)5144return;5145}51465147iwl_mvm_bt_coex_vif_change(mvm);5148iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, def, &ctx->ap,5149ctx->rx_chains_static,5150ctx->rx_chains_dynamic);5151}51525153/*5154* This function executes the common part for MLD and non-MLD modes.5155*5156* Returns true if we're done assigning the chanctx5157* (either on failure or success)5158*/5159static bool5160__iwl_mvm_assign_vif_chanctx_common(struct iwl_mvm *mvm,5161struct ieee80211_vif *vif,5162struct ieee80211_chanctx_conf *ctx,5163bool switching_chanctx, int *ret)5164{5165u16 *phy_ctxt_id = (u16 *)ctx->drv_priv;5166struct iwl_mvm_phy_ctxt *phy_ctxt = &mvm->phy_ctxts[*phy_ctxt_id];5167struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);51685169lockdep_assert_held(&mvm->mutex);51705171mvmvif->deflink.phy_ctxt = phy_ctxt;51725173switch (vif->type) {5174case NL80211_IFTYPE_AP:5175/* only needed if we're switching chanctx (i.e. during CSA) */5176if (switching_chanctx) {5177mvmvif->ap_ibss_active = true;5178break;5179}5180fallthrough;5181case NL80211_IFTYPE_ADHOC:5182/*5183* The AP binding flow is handled as part of the start_ap flow5184* (in bss_info_changed), similarly for IBSS.5185*/5186*ret = 0;5187return true;5188case NL80211_IFTYPE_STATION:5189break;5190case NL80211_IFTYPE_MONITOR:5191/* always disable PS when a monitor interface is active */5192mvmvif->ps_disabled = true;5193break;5194default:5195*ret = -EINVAL;5196return true;5197}5198return false;5199}52005201static int __iwl_mvm_assign_vif_chanctx(struct iwl_mvm *mvm,5202struct ieee80211_vif *vif,5203struct ieee80211_bss_conf *link_conf,5204struct ieee80211_chanctx_conf *ctx,5205bool switching_chanctx)5206{5207struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);5208int ret;52095210if (WARN_ON(!link_conf))5211return -EINVAL;52125213if (__iwl_mvm_assign_vif_chanctx_common(mvm, vif, ctx,5214switching_chanctx, &ret))5215goto out;52165217ret = iwl_mvm_binding_add_vif(mvm, vif);5218if (ret)5219goto out;52205221/*5222* Power state must be updated before quotas,5223* otherwise fw will complain.5224*/5225iwl_mvm_power_update_mac(mvm);52265227/* Setting the quota at this stage is only required for monitor5228* interfaces. For the other types, the bss_info changed flow5229* will handle quota settings.5230*/5231if (vif->type == NL80211_IFTYPE_MONITOR) {5232mvmvif->monitor_active = true;5233ret = iwl_mvm_update_quotas(mvm, false, NULL);5234if (ret)5235goto out_remove_binding;52365237ret = iwl_mvm_add_snif_sta(mvm, vif);5238if (ret)5239goto out_remove_binding;52405241}52425243/* Handle binding during CSA */5244if (vif->type == NL80211_IFTYPE_AP) {5245iwl_mvm_update_quotas(mvm, false, NULL);5246iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL);5247}52485249if (vif->type == NL80211_IFTYPE_STATION) {5250if (!switching_chanctx) {5251mvmvif->csa_bcn_pending = false;5252goto out;5253}52545255mvmvif->csa_bcn_pending = true;52565257if (!fw_has_capa(&mvm->fw->ucode_capa,5258IWL_UCODE_TLV_CAPA_CHANNEL_SWITCH_CMD)) {5259u32 duration = 5 * vif->bss_conf.beacon_int;52605261/* Protect the session to make sure we hear the first5262* beacon on the new channel.5263*/5264iwl_mvm_protect_session(mvm, vif, duration, duration,5265vif->bss_conf.beacon_int / 2,5266true);5267}52685269iwl_mvm_update_quotas(mvm, false, NULL);52705271iwl_mvm_send_ap_tx_power_constraint_cmd(mvm, vif,5272link_conf,5273false);5274}52755276goto out;52775278out_remove_binding:5279iwl_mvm_binding_remove_vif(mvm, vif);5280iwl_mvm_power_update_mac(mvm);5281out:5282if (ret)5283mvmvif->deflink.phy_ctxt = NULL;5284return ret;5285}52865287static int iwl_mvm_assign_vif_chanctx(struct ieee80211_hw *hw,5288struct ieee80211_vif *vif,5289struct ieee80211_bss_conf *link_conf,5290struct ieee80211_chanctx_conf *ctx)5291{5292struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);52935294guard(mvm)(mvm);5295return __iwl_mvm_assign_vif_chanctx(mvm, vif, link_conf, ctx, false);5296}52975298/*5299* This function executes the common part for MLD and non-MLD modes.5300*5301* Returns if chanctx unassign chanctx is done5302* (either on failure or success)5303*/5304static bool __iwl_mvm_unassign_vif_chanctx_common(struct iwl_mvm *mvm,5305struct ieee80211_vif *vif,5306bool switching_chanctx)5307{5308struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);53095310lockdep_assert_held(&mvm->mutex);5311iwl_mvm_remove_time_event(mvm, mvmvif,5312&mvmvif->time_event_data);53135314switch (vif->type) {5315case NL80211_IFTYPE_ADHOC:5316return true;5317case NL80211_IFTYPE_MONITOR:5318mvmvif->monitor_active = false;5319mvmvif->ps_disabled = false;5320break;5321case NL80211_IFTYPE_AP:5322/* This part is triggered only during CSA */5323if (!switching_chanctx || !mvmvif->ap_ibss_active)5324return true;53255326mvmvif->csa_countdown = false;53275328/* Set CS bit on all the stations */5329iwl_mvm_modify_all_sta_disable_tx(mvm, mvmvif, true);53305331/* Save blocked iface, the timeout is set on the next beacon */5332rcu_assign_pointer(mvm->csa_tx_blocked_vif, vif);53335334mvmvif->ap_ibss_active = false;5335break;5336default:5337break;5338}5339return false;5340}53415342static void __iwl_mvm_unassign_vif_chanctx(struct iwl_mvm *mvm,5343struct ieee80211_vif *vif,5344struct ieee80211_bss_conf *link_conf,5345struct ieee80211_chanctx_conf *ctx,5346bool switching_chanctx)5347{5348struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);5349struct ieee80211_vif *disabled_vif = NULL;53505351if (__iwl_mvm_unassign_vif_chanctx_common(mvm, vif, switching_chanctx))5352goto out;53535354if (vif->type == NL80211_IFTYPE_MONITOR)5355iwl_mvm_rm_snif_sta(mvm, vif);535653575358if (vif->type == NL80211_IFTYPE_STATION && switching_chanctx) {5359disabled_vif = vif;5360if (!fw_has_capa(&mvm->fw->ucode_capa,5361IWL_UCODE_TLV_CAPA_CHANNEL_SWITCH_CMD))5362iwl_mvm_mac_ctxt_changed(mvm, vif, true, NULL);5363}53645365iwl_mvm_update_quotas(mvm, false, disabled_vif);5366iwl_mvm_binding_remove_vif(mvm, vif);53675368out:5369if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_CHANNEL_SWITCH_CMD) &&5370switching_chanctx)5371return;5372mvmvif->deflink.phy_ctxt = NULL;5373iwl_mvm_power_update_mac(mvm);5374}53755376static void iwl_mvm_unassign_vif_chanctx(struct ieee80211_hw *hw,5377struct ieee80211_vif *vif,5378struct ieee80211_bss_conf *link_conf,5379struct ieee80211_chanctx_conf *ctx)5380{5381struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);53825383guard(mvm)(mvm);5384__iwl_mvm_unassign_vif_chanctx(mvm, vif, link_conf, ctx, false);5385}53865387static int5388iwl_mvm_switch_vif_chanctx_swap(struct iwl_mvm *mvm,5389struct ieee80211_vif_chanctx_switch *vifs,5390const struct iwl_mvm_switch_vif_chanctx_ops *ops)5391{5392int ret;53935394guard(mvm)(mvm);5395ops->__unassign_vif_chanctx(mvm, vifs[0].vif, vifs[0].link_conf,5396vifs[0].old_ctx, true);5397__iwl_mvm_remove_chanctx(mvm, vifs[0].old_ctx);53985399ret = __iwl_mvm_add_chanctx(mvm, vifs[0].new_ctx);5400if (ret) {5401IWL_ERR(mvm, "failed to add new_ctx during channel switch\n");5402goto out_reassign;5403}54045405ret = ops->__assign_vif_chanctx(mvm, vifs[0].vif, vifs[0].link_conf,5406vifs[0].new_ctx, true);5407if (ret) {5408IWL_ERR(mvm,5409"failed to assign new_ctx during channel switch\n");5410goto out_remove;5411}54125413/* we don't support TDLS during DCM - can be caused by channel switch */5414if (iwl_mvm_phy_ctx_count(mvm) > 1)5415iwl_mvm_teardown_tdls_peers(mvm);54165417return 0;54185419out_remove:5420__iwl_mvm_remove_chanctx(mvm, vifs[0].new_ctx);54215422out_reassign:5423if (__iwl_mvm_add_chanctx(mvm, vifs[0].old_ctx)) {5424IWL_ERR(mvm, "failed to add old_ctx back after failure.\n");5425goto out_restart;5426}54275428if (ops->__assign_vif_chanctx(mvm, vifs[0].vif, vifs[0].link_conf,5429vifs[0].old_ctx, true)) {5430IWL_ERR(mvm, "failed to reassign old_ctx after failure.\n");5431goto out_restart;5432}54335434return ret;54355436out_restart:5437/* things keep failing, better restart the hw */5438iwl_force_nmi(mvm->trans);5439return ret;5440}54415442static int5443iwl_mvm_switch_vif_chanctx_reassign(struct iwl_mvm *mvm,5444struct ieee80211_vif_chanctx_switch *vifs,5445const struct iwl_mvm_switch_vif_chanctx_ops *ops)5446{5447int ret;54485449guard(mvm)(mvm);5450ops->__unassign_vif_chanctx(mvm, vifs[0].vif, vifs[0].link_conf,5451vifs[0].old_ctx, true);54525453ret = ops->__assign_vif_chanctx(mvm, vifs[0].vif, vifs[0].link_conf,5454vifs[0].new_ctx, true);5455if (ret) {5456IWL_ERR(mvm,5457"failed to assign new_ctx during channel switch\n");5458goto out_reassign;5459}54605461return 0;54625463out_reassign:5464if (ops->__assign_vif_chanctx(mvm, vifs[0].vif, vifs[0].link_conf,5465vifs[0].old_ctx, true)) {5466IWL_ERR(mvm, "failed to reassign old_ctx after failure.\n");5467goto out_restart;5468}54695470return ret;54715472out_restart:5473/* things keep failing, better restart the hw */5474iwl_force_nmi(mvm->trans);5475return ret;5476}54775478/* Execute the common part for both MLD and non-MLD modes */5479int5480iwl_mvm_switch_vif_chanctx_common(struct ieee80211_hw *hw,5481struct ieee80211_vif_chanctx_switch *vifs,5482int n_vifs,5483enum ieee80211_chanctx_switch_mode mode,5484const struct iwl_mvm_switch_vif_chanctx_ops *ops)5485{5486struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);5487int ret;54885489/* we only support a single-vif right now */5490if (n_vifs > 1)5491return -EOPNOTSUPP;54925493switch (mode) {5494case CHANCTX_SWMODE_SWAP_CONTEXTS:5495ret = iwl_mvm_switch_vif_chanctx_swap(mvm, vifs, ops);5496break;5497case CHANCTX_SWMODE_REASSIGN_VIF:5498ret = iwl_mvm_switch_vif_chanctx_reassign(mvm, vifs, ops);5499break;5500default:5501ret = -EOPNOTSUPP;5502break;5503}55045505return ret;5506}55075508static int iwl_mvm_switch_vif_chanctx(struct ieee80211_hw *hw,5509struct ieee80211_vif_chanctx_switch *vifs,5510int n_vifs,5511enum ieee80211_chanctx_switch_mode mode)5512{5513static const struct iwl_mvm_switch_vif_chanctx_ops ops = {5514.__assign_vif_chanctx = __iwl_mvm_assign_vif_chanctx,5515.__unassign_vif_chanctx = __iwl_mvm_unassign_vif_chanctx,5516};55175518return iwl_mvm_switch_vif_chanctx_common(hw, vifs, n_vifs, mode, &ops);5519}55205521int iwl_mvm_tx_last_beacon(struct ieee80211_hw *hw)5522{5523struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);55245525return mvm->ibss_manager;5526}55275528static int iwl_mvm_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta,5529bool set)5530{5531struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);5532struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);55335534if (!mvm_sta || !mvm_sta->vif) {5535IWL_ERR(mvm, "Station is not associated to a vif\n");5536return -EINVAL;5537}55385539return iwl_mvm_mac_ctxt_beacon_changed(mvm, mvm_sta->vif,5540&mvm_sta->vif->bss_conf);5541}55425543void iwl_mvm_channel_switch(struct ieee80211_hw *hw, struct ieee80211_vif *vif,5544struct ieee80211_channel_switch *chsw)5545{5546/* By implementing this operation, we prevent mac80211 from5547* starting its own channel switch timer, so that we can call5548* ieee80211_chswitch_done() ourselves at the right time5549* (which is when the absence time event starts).5550*/55515552IWL_DEBUG_MAC80211(IWL_MAC80211_GET_MVM(hw),5553"dummy channel switch op\n");5554}55555556static int iwl_mvm_schedule_client_csa(struct iwl_mvm *mvm,5557struct ieee80211_vif *vif,5558struct ieee80211_channel_switch *chsw)5559{5560struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);5561struct iwl_chan_switch_te_cmd cmd = {5562.mac_id = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id,5563mvmvif->color)),5564.action = cpu_to_le32(FW_CTXT_ACTION_ADD),5565.tsf = cpu_to_le32(chsw->timestamp),5566.cs_count = chsw->count,5567.cs_mode = chsw->block_tx,5568};55695570lockdep_assert_held(&mvm->mutex);55715572if (chsw->delay)5573cmd.cs_delayed_bcn_count =5574DIV_ROUND_UP(chsw->delay, vif->bss_conf.beacon_int);55755576return iwl_mvm_send_cmd_pdu(mvm,5577WIDE_ID(MAC_CONF_GROUP,5578CHANNEL_SWITCH_TIME_EVENT_CMD),55790, sizeof(cmd), &cmd);5580}55815582static int iwl_mvm_old_pre_chan_sw_sta(struct iwl_mvm *mvm,5583struct ieee80211_vif *vif,5584struct ieee80211_channel_switch *chsw)5585{5586struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);5587u32 apply_time;55885589/* Schedule the time event to a bit before beacon 1,5590* to make sure we're in the new channel when the5591* GO/AP arrives. In case count <= 1 immediately schedule the5592* TE (this might result with some packet loss or connection5593* loss).5594*/5595if (chsw->count <= 1)5596apply_time = 0;5597else5598apply_time = chsw->device_timestamp +5599((vif->bss_conf.beacon_int * (chsw->count - 1) -5600IWL_MVM_CHANNEL_SWITCH_TIME_CLIENT) * 1024);56015602if (chsw->block_tx)5603iwl_mvm_csa_client_absent(mvm, vif);56045605if (mvmvif->bf_enabled) {5606int ret = iwl_mvm_disable_beacon_filter(mvm, vif);56075608if (ret)5609return ret;5610}56115612iwl_mvm_schedule_csa_period(mvm, vif, vif->bss_conf.beacon_int,5613apply_time);56145615return 0;5616}56175618static void iwl_mvm_csa_block_txqs(void *data, struct ieee80211_sta *sta)5619{5620int i;56215622for (i = 0; i < ARRAY_SIZE(sta->txq); i++) {5623struct iwl_mvm_txq *mvmtxq =5624iwl_mvm_txq_from_mac80211(sta->txq[i]);56255626set_bit(IWL_MVM_TXQ_STATE_STOP_AP_CSA, &mvmtxq->state);5627}5628}56295630#define IWL_MAX_CSA_BLOCK_TX 15005631int iwl_mvm_pre_channel_switch(struct iwl_mvm *mvm,5632struct ieee80211_vif *vif,5633struct ieee80211_channel_switch *chsw)5634{5635struct ieee80211_vif *csa_vif;5636struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);5637struct iwl_mvm_txq *mvmtxq;5638int ret;56395640lockdep_assert_held(&mvm->mutex);56415642mvmvif->csa_failed = false;5643mvmvif->csa_blocks_tx = false;56445645IWL_DEBUG_MAC80211(mvm, "pre CSA to freq %d\n",5646chsw->chandef.center_freq1);56475648iwl_fw_dbg_trigger_simple_stop(&mvm->fwrt,5649ieee80211_vif_to_wdev(vif),5650FW_DBG_TRIGGER_CHANNEL_SWITCH);56515652switch (vif->type) {5653case NL80211_IFTYPE_AP:5654csa_vif =5655rcu_dereference_protected(mvm->csa_vif,5656lockdep_is_held(&mvm->mutex));5657if (WARN_ONCE(csa_vif && csa_vif->bss_conf.csa_active,5658"Another CSA is already in progress"))5659return -EBUSY;56605661/* we still didn't unblock tx. prevent new CS meanwhile */5662if (rcu_dereference_protected(mvm->csa_tx_blocked_vif,5663lockdep_is_held(&mvm->mutex)))5664return -EBUSY;56655666rcu_assign_pointer(mvm->csa_vif, vif);56675668if (WARN_ONCE(mvmvif->csa_countdown,5669"Previous CSA countdown didn't complete"))5670return -EBUSY;56715672mvmvif->csa_target_freq = chsw->chandef.chan->center_freq;56735674if (!chsw->block_tx)5675break;5676/* don't need blocking in driver otherwise - mac80211 will do */5677if (!ieee80211_hw_check(mvm->hw, HANDLES_QUIET_CSA))5678break;56795680mvmvif->csa_blocks_tx = true;5681mvmtxq = iwl_mvm_txq_from_mac80211(vif->txq);5682set_bit(IWL_MVM_TXQ_STATE_STOP_AP_CSA, &mvmtxq->state);5683ieee80211_iterate_stations_atomic(mvm->hw,5684iwl_mvm_csa_block_txqs,5685NULL);5686break;5687case NL80211_IFTYPE_STATION:5688mvmvif->csa_blocks_tx = chsw->block_tx;56895690/*5691* In the new flow FW is in charge of timing the switch so there5692* is no need for all of this5693*/5694if (iwl_fw_lookup_notif_ver(mvm->fw, MAC_CONF_GROUP,5695CHANNEL_SWITCH_ERROR_NOTIF,56960))5697break;56985699/*5700* We haven't configured the firmware to be associated yet since5701* we don't know the dtim period. In this case, the firmware can't5702* track the beacons.5703*/5704if (!vif->cfg.assoc || !vif->bss_conf.dtim_period)5705return -EBUSY;57065707if (chsw->delay > IWL_MAX_CSA_BLOCK_TX &&5708hweight16(vif->valid_links) <= 1)5709schedule_delayed_work(&mvmvif->csa_work, 0);57105711if (chsw->block_tx) {5712/*5713* In case of undetermined / long time with immediate5714* quiet monitor status to gracefully disconnect5715*/5716if (!chsw->count ||5717chsw->count * vif->bss_conf.beacon_int >5718IWL_MAX_CSA_BLOCK_TX)5719schedule_delayed_work(&mvmvif->csa_work,5720msecs_to_jiffies(IWL_MAX_CSA_BLOCK_TX));5721}57225723if (!fw_has_capa(&mvm->fw->ucode_capa,5724IWL_UCODE_TLV_CAPA_CHANNEL_SWITCH_CMD)) {5725ret = iwl_mvm_old_pre_chan_sw_sta(mvm, vif, chsw);5726if (ret)5727return ret;5728} else {5729iwl_mvm_schedule_client_csa(mvm, vif, chsw);5730}57315732mvmvif->csa_count = chsw->count;5733mvmvif->csa_misbehave = false;5734break;5735default:5736break;5737}57385739mvmvif->ps_disabled = true;57405741ret = iwl_mvm_power_update_ps(mvm);5742if (ret)5743return ret;57445745/* we won't be on this channel any longer */5746iwl_mvm_teardown_tdls_peers(mvm);57475748return ret;5749}57505751static int iwl_mvm_mac_pre_channel_switch(struct ieee80211_hw *hw,5752struct ieee80211_vif *vif,5753struct ieee80211_channel_switch *chsw)5754{5755struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);57565757guard(mvm)(mvm);5758return iwl_mvm_pre_channel_switch(mvm, vif, chsw);5759}57605761void iwl_mvm_channel_switch_rx_beacon(struct ieee80211_hw *hw,5762struct ieee80211_vif *vif,5763struct ieee80211_channel_switch *chsw)5764{5765struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);5766struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);5767struct iwl_chan_switch_te_cmd cmd = {5768.mac_id = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id,5769mvmvif->color)),5770.action = cpu_to_le32(FW_CTXT_ACTION_MODIFY),5771.tsf = cpu_to_le32(chsw->timestamp),5772.cs_count = chsw->count,5773.cs_mode = chsw->block_tx,5774};57755776/*5777* In the new flow FW is in charge of timing the switch so there is no5778* need for all of this5779*/5780if (iwl_fw_lookup_notif_ver(mvm->fw, MAC_CONF_GROUP,5781CHANNEL_SWITCH_ERROR_NOTIF, 0))5782return;57835784if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_CS_MODIFY))5785return;57865787IWL_DEBUG_MAC80211(mvm, "Modify CSA on mac %d count = %d (old %d) mode = %d\n",5788mvmvif->id, chsw->count, mvmvif->csa_count, chsw->block_tx);57895790if (chsw->count >= mvmvif->csa_count && chsw->block_tx) {5791if (mvmvif->csa_misbehave) {5792struct ieee80211_bss_conf *link_conf;57935794/* Second time, give up on this AP*/57955796link_conf = wiphy_dereference(hw->wiphy,5797vif->link_conf[chsw->link_id]);5798if (WARN_ON(!link_conf))5799return;58005801iwl_mvm_abort_channel_switch(hw, vif, link_conf);5802ieee80211_chswitch_done(vif, false, 0);5803mvmvif->csa_misbehave = false;5804return;5805}5806mvmvif->csa_misbehave = true;5807}5808mvmvif->csa_count = chsw->count;58095810guard(mvm)(mvm);5811if (mvmvif->csa_failed)5812return;58135814WARN_ON(iwl_mvm_send_cmd_pdu(mvm,5815WIDE_ID(MAC_CONF_GROUP,5816CHANNEL_SWITCH_TIME_EVENT_CMD),58170, sizeof(cmd), &cmd));5818}58195820static void iwl_mvm_flush_no_vif(struct iwl_mvm *mvm, u32 queues, bool drop)5821{5822int i;58235824if (!iwl_mvm_has_new_tx_api(mvm)) {5825/* we can't ask the firmware anything if it is dead */5826if (test_bit(IWL_MVM_STATUS_HW_RESTART_REQUESTED,5827&mvm->status))5828return;5829if (drop) {5830guard(mvm)(mvm);5831iwl_mvm_flush_tx_path(mvm,5832iwl_mvm_flushable_queues(mvm) & queues);5833} else {5834iwl_trans_wait_tx_queues_empty(mvm->trans, queues);5835}5836return;5837}58385839guard(mvm)(mvm);5840for (i = 0; i < mvm->fw->ucode_capa.num_stations; i++) {5841struct ieee80211_sta *sta;58425843sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i],5844lockdep_is_held(&mvm->mutex));5845if (IS_ERR_OR_NULL(sta))5846continue;58475848if (drop)5849iwl_mvm_flush_sta_tids(mvm, i, 0xFFFF);5850else5851iwl_mvm_wait_sta_queues_empty(mvm,5852iwl_mvm_sta_from_mac80211(sta));5853}5854}58555856void iwl_mvm_mac_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,5857u32 queues, bool drop)5858{5859struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);5860struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);5861struct iwl_mvm_sta *mvmsta;5862struct ieee80211_sta *sta;5863bool ap_sta_done = false;5864int i;5865u32 msk = 0;58665867if (!vif) {5868iwl_mvm_flush_no_vif(mvm, queues, drop);5869return;5870}58715872if (!drop && hweight16(vif->active_links) <= 1) {5873int link_id = vif->active_links ? __ffs(vif->active_links) : 0;5874struct ieee80211_bss_conf *link_conf;58755876link_conf = wiphy_dereference(hw->wiphy,5877vif->link_conf[link_id]);5878if (WARN_ON(!link_conf))5879return;5880if (link_conf->csa_active && mvmvif->csa_blocks_tx)5881drop = true;5882}58835884/* Make sure we're done with the deferred traffic before flushing */5885flush_work(&mvm->add_stream_wk);58865887mutex_lock(&mvm->mutex);58885889/* flush the AP-station and all TDLS peers */5890for (i = 0; i < mvm->fw->ucode_capa.num_stations; i++) {5891sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i],5892lockdep_is_held(&mvm->mutex));5893if (IS_ERR_OR_NULL(sta))5894continue;58955896mvmsta = iwl_mvm_sta_from_mac80211(sta);5897if (mvmsta->vif != vif)5898continue;58995900if (sta == mvmvif->ap_sta) {5901if (ap_sta_done)5902continue;5903ap_sta_done = true;5904}59055906if (drop) {5907if (iwl_mvm_flush_sta(mvm, mvmsta->deflink.sta_id,5908mvmsta->tfd_queue_msk))5909IWL_ERR(mvm, "flush request fail\n");5910} else {5911if (iwl_mvm_has_new_tx_api(mvm))5912iwl_mvm_wait_sta_queues_empty(mvm, mvmsta);5913else /* only used for !iwl_mvm_has_new_tx_api() below */5914msk |= mvmsta->tfd_queue_msk;5915}5916}59175918mutex_unlock(&mvm->mutex);59195920/* this can take a while, and we may need/want other operations5921* to succeed while doing this, so do it without the mutex held5922* If the firmware is dead, this can't work...5923*/5924if (!drop && !iwl_mvm_has_new_tx_api(mvm) &&5925!test_bit(IWL_MVM_STATUS_HW_RESTART_REQUESTED,5926&mvm->status))5927iwl_trans_wait_tx_queues_empty(mvm->trans, msk);5928}59295930void iwl_mvm_mac_flush_sta(struct ieee80211_hw *hw, struct ieee80211_vif *vif,5931struct ieee80211_sta *sta)5932{5933struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);5934struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);5935struct iwl_mvm_link_sta *mvm_link_sta;5936struct ieee80211_link_sta *link_sta;5937int link_id;59385939guard(mvm)(mvm);5940for_each_sta_active_link(vif, sta, link_sta, link_id) {5941mvm_link_sta = rcu_dereference_protected(mvmsta->link[link_id],5942lockdep_is_held(&mvm->mutex));5943if (!mvm_link_sta)5944continue;59455946if (iwl_mvm_flush_sta(mvm, mvm_link_sta->sta_id,5947mvmsta->tfd_queue_msk))5948IWL_ERR(mvm, "flush request fail\n");5949}5950}59515952static int iwl_mvm_mac_get_acs_survey(struct iwl_mvm *mvm, int idx,5953struct survey_info *survey)5954{5955int chan_idx;5956enum nl80211_band band;5957int ret;59585959mutex_lock(&mvm->mutex);59605961if (!mvm->acs_survey) {5962ret = -ENOENT;5963goto out;5964}59655966/* Find and return the next entry that has a non-zero active time */5967for (band = 0; band < NUM_NL80211_BANDS; band++) {5968struct ieee80211_supported_band *sband =5969mvm->hw->wiphy->bands[band];59705971if (!sband)5972continue;59735974for (chan_idx = 0; chan_idx < sband->n_channels; chan_idx++) {5975struct iwl_mvm_acs_survey_channel *info =5976&mvm->acs_survey->bands[band][chan_idx];59775978if (!info->time)5979continue;59805981/* Found (the next) channel to report */5982survey->channel = &sband->channels[chan_idx];5983survey->filled = SURVEY_INFO_TIME |5984SURVEY_INFO_TIME_BUSY |5985SURVEY_INFO_TIME_RX |5986SURVEY_INFO_TIME_TX;5987survey->time = info->time;5988survey->time_busy = info->time_busy;5989survey->time_rx = info->time_rx;5990survey->time_tx = info->time_tx;5991survey->noise = info->noise;5992if (survey->noise < 0)5993survey->filled |= SURVEY_INFO_NOISE_DBM;59945995/* Clear time so that channel is only reported once */5996info->time = 0;59975998ret = 0;5999goto out;6000}6001}60026003ret = -ENOENT;60046005out:6006mutex_unlock(&mvm->mutex);60076008return ret;6009}60106011int iwl_mvm_mac_get_survey(struct ieee80211_hw *hw, int idx,6012struct survey_info *survey)6013{6014struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);6015u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw,6016WIDE_ID(SYSTEM_GROUP,6017SYSTEM_STATISTICS_CMD),6018IWL_FW_CMD_VER_UNKNOWN);60196020memset(survey, 0, sizeof(*survey));60216022if (!fw_has_capa(&mvm->fw->ucode_capa,6023IWL_UCODE_TLV_CAPA_RADIO_BEACON_STATS))6024return -ENOENT;60256026/*6027* Return the beacon stats at index zero and pass on following indices6028* to the function returning the full survey, most likely for ACS6029* (Automatic Channel Selection).6030*/6031if (idx > 0)6032return iwl_mvm_mac_get_acs_survey(mvm, idx - 1, survey);60336034guard(mvm)(mvm);60356036if (iwl_mvm_firmware_running(mvm)) {6037int ret = iwl_mvm_request_statistics(mvm, false);60386039if (ret)6040return ret;6041}60426043survey->filled = SURVEY_INFO_TIME_RX |6044SURVEY_INFO_TIME_TX;60456046survey->time_rx = mvm->accu_radio_stats.rx_time +6047mvm->radio_stats.rx_time;6048do_div(survey->time_rx, USEC_PER_MSEC);60496050survey->time_tx = mvm->accu_radio_stats.tx_time +6051mvm->radio_stats.tx_time;6052do_div(survey->time_tx, USEC_PER_MSEC);60536054/* the new fw api doesn't support the following fields */6055if (cmd_ver != IWL_FW_CMD_VER_UNKNOWN)6056return 0;60576058survey->filled |= SURVEY_INFO_TIME |6059SURVEY_INFO_TIME_SCAN;6060survey->time = mvm->accu_radio_stats.on_time_rf +6061mvm->radio_stats.on_time_rf;6062do_div(survey->time, USEC_PER_MSEC);60636064survey->time_scan = mvm->accu_radio_stats.on_time_scan +6065mvm->radio_stats.on_time_scan;6066do_div(survey->time_scan, USEC_PER_MSEC);60676068return 0;6069}60706071static void iwl_mvm_set_sta_rate(u32 rate_n_flags, struct rate_info *rinfo)6072{6073u32 format = rate_n_flags & RATE_MCS_MOD_TYPE_MSK;6074u32 gi_ltf;60756076switch (rate_n_flags & RATE_MCS_CHAN_WIDTH_MSK) {6077case RATE_MCS_CHAN_WIDTH_20:6078rinfo->bw = RATE_INFO_BW_20;6079break;6080case RATE_MCS_CHAN_WIDTH_40:6081rinfo->bw = RATE_INFO_BW_40;6082break;6083case RATE_MCS_CHAN_WIDTH_80:6084rinfo->bw = RATE_INFO_BW_80;6085break;6086case RATE_MCS_CHAN_WIDTH_160:6087rinfo->bw = RATE_INFO_BW_160;6088break;6089case RATE_MCS_CHAN_WIDTH_320:6090rinfo->bw = RATE_INFO_BW_320;6091break;6092}60936094if (format == RATE_MCS_MOD_TYPE_CCK ||6095format == RATE_MCS_MOD_TYPE_LEGACY_OFDM) {6096int rate = u32_get_bits(rate_n_flags, RATE_LEGACY_RATE_MSK);60976098/* add the offset needed to get to the legacy ofdm indices */6099if (format == RATE_MCS_MOD_TYPE_LEGACY_OFDM)6100rate += IWL_FIRST_OFDM_RATE;61016102switch (rate) {6103case IWL_RATE_1M_INDEX:6104rinfo->legacy = 10;6105break;6106case IWL_RATE_2M_INDEX:6107rinfo->legacy = 20;6108break;6109case IWL_RATE_5M_INDEX:6110rinfo->legacy = 55;6111break;6112case IWL_RATE_11M_INDEX:6113rinfo->legacy = 110;6114break;6115case IWL_RATE_6M_INDEX:6116rinfo->legacy = 60;6117break;6118case IWL_RATE_9M_INDEX:6119rinfo->legacy = 90;6120break;6121case IWL_RATE_12M_INDEX:6122rinfo->legacy = 120;6123break;6124case IWL_RATE_18M_INDEX:6125rinfo->legacy = 180;6126break;6127case IWL_RATE_24M_INDEX:6128rinfo->legacy = 240;6129break;6130case IWL_RATE_36M_INDEX:6131rinfo->legacy = 360;6132break;6133case IWL_RATE_48M_INDEX:6134rinfo->legacy = 480;6135break;6136case IWL_RATE_54M_INDEX:6137rinfo->legacy = 540;6138}6139return;6140}61416142rinfo->nss = u32_get_bits(rate_n_flags,6143RATE_MCS_NSS_MSK) + 1;6144rinfo->mcs = format == RATE_MCS_MOD_TYPE_HT ?6145RATE_HT_MCS_INDEX(rate_n_flags) :6146u32_get_bits(rate_n_flags, RATE_MCS_CODE_MSK);61476148if (rate_n_flags & RATE_MCS_SGI_MSK)6149rinfo->flags |= RATE_INFO_FLAGS_SHORT_GI;61506151switch (format) {6152case RATE_MCS_MOD_TYPE_EHT:6153/* TODO: GI/LTF/RU. How does the firmware encode them? */6154rinfo->flags |= RATE_INFO_FLAGS_EHT_MCS;6155break;6156case RATE_MCS_MOD_TYPE_HE:6157gi_ltf = u32_get_bits(rate_n_flags, RATE_MCS_HE_GI_LTF_MSK);61586159rinfo->flags |= RATE_INFO_FLAGS_HE_MCS;61606161if (rate_n_flags & RATE_MCS_HE_106T_MSK) {6162rinfo->bw = RATE_INFO_BW_HE_RU;6163rinfo->he_ru_alloc = NL80211_RATE_INFO_HE_RU_ALLOC_106;6164}61656166switch (rate_n_flags & RATE_MCS_HE_TYPE_MSK) {6167case RATE_MCS_HE_TYPE_SU:6168case RATE_MCS_HE_TYPE_EXT_SU:6169if (gi_ltf == 0 || gi_ltf == 1)6170rinfo->he_gi = NL80211_RATE_INFO_HE_GI_0_8;6171else if (gi_ltf == 2)6172rinfo->he_gi = NL80211_RATE_INFO_HE_GI_1_6;6173else if (gi_ltf == 3)6174rinfo->he_gi = NL80211_RATE_INFO_HE_GI_3_2;6175else6176rinfo->he_gi = NL80211_RATE_INFO_HE_GI_0_8;6177break;6178case RATE_MCS_HE_TYPE_MU:6179if (gi_ltf == 0 || gi_ltf == 1)6180rinfo->he_gi = NL80211_RATE_INFO_HE_GI_0_8;6181else if (gi_ltf == 2)6182rinfo->he_gi = NL80211_RATE_INFO_HE_GI_1_6;6183else6184rinfo->he_gi = NL80211_RATE_INFO_HE_GI_3_2;6185break;6186case RATE_MCS_HE_TYPE_TRIG:6187if (gi_ltf == 0 || gi_ltf == 1)6188rinfo->he_gi = NL80211_RATE_INFO_HE_GI_1_6;6189else6190rinfo->he_gi = NL80211_RATE_INFO_HE_GI_3_2;6191break;6192}61936194if (rate_n_flags & RATE_HE_DUAL_CARRIER_MODE_MSK)6195rinfo->he_dcm = 1;6196break;6197case RATE_MCS_MOD_TYPE_HT:6198rinfo->flags |= RATE_INFO_FLAGS_MCS;6199break;6200case RATE_MCS_MOD_TYPE_VHT:6201rinfo->flags |= RATE_INFO_FLAGS_VHT_MCS;6202break;6203}6204}62056206void iwl_mvm_mac_sta_statistics(struct ieee80211_hw *hw,6207struct ieee80211_vif *vif,6208struct ieee80211_sta *sta,6209struct station_info *sinfo)6210{6211struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);6212struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);6213struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);6214int i;62156216if (mvmsta->deflink.avg_energy) {6217sinfo->signal_avg = -(s8)mvmsta->deflink.avg_energy;6218sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL_AVG);6219}62206221if (iwl_mvm_has_tlc_offload(mvm)) {6222struct iwl_lq_sta_rs_fw *lq_sta = &mvmsta->deflink.lq_sta.rs_fw;62236224iwl_mvm_set_sta_rate(lq_sta->last_rate_n_flags, &sinfo->txrate);6225sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE);6226}62276228/* if beacon filtering isn't on mac80211 does it anyway */6229if (!(vif->driver_flags & IEEE80211_VIF_BEACON_FILTER))6230return;62316232if (!vif->cfg.assoc)6233return;62346235guard(mvm)(mvm);62366237if (sta != mvmvif->ap_sta)6238return;62396240if (iwl_mvm_request_statistics(mvm, false))6241return;62426243sinfo->rx_beacon = 0;6244for_each_mvm_vif_valid_link(mvmvif, i)6245sinfo->rx_beacon += mvmvif->link[i]->beacon_stats.num_beacons +6246mvmvif->link[i]->beacon_stats.accu_num_beacons;62476248sinfo->filled |= BIT_ULL(NL80211_STA_INFO_BEACON_RX);6249if (mvmvif->deflink.beacon_stats.avg_signal) {6250/* firmware only reports a value after RXing a few beacons */6251sinfo->rx_beacon_signal_avg =6252mvmvif->deflink.beacon_stats.avg_signal;6253sinfo->filled |= BIT_ULL(NL80211_STA_INFO_BEACON_SIGNAL_AVG);6254}6255}62566257static void iwl_mvm_event_mlme_callback_ini(struct iwl_mvm *mvm,6258struct ieee80211_vif *vif,6259const struct ieee80211_mlme_event *mlme)6260{6261if ((mlme->data == ASSOC_EVENT || mlme->data == AUTH_EVENT) &&6262(mlme->status == MLME_DENIED || mlme->status == MLME_TIMEOUT)) {6263iwl_dbg_tlv_time_point(&mvm->fwrt,6264IWL_FW_INI_TIME_POINT_ASSOC_FAILED,6265NULL);6266return;6267}62686269if (mlme->data == DEAUTH_RX_EVENT || mlme->data == DEAUTH_TX_EVENT) {6270iwl_dbg_tlv_time_point(&mvm->fwrt,6271IWL_FW_INI_TIME_POINT_DEASSOC,6272NULL);6273return;6274}6275}62766277static void iwl_mvm_event_mlme_callback(struct iwl_mvm *mvm,6278struct ieee80211_vif *vif,6279const struct ieee80211_event *event)6280{6281#define CHECK_MLME_TRIGGER(_cnt, _fmt...) \6282do { \6283if ((trig_mlme->_cnt) && --(trig_mlme->_cnt)) \6284break; \6285iwl_fw_dbg_collect_trig(&(mvm)->fwrt, trig, _fmt); \6286} while (0)62876288struct iwl_fw_dbg_trigger_tlv *trig;6289struct iwl_fw_dbg_trigger_mlme *trig_mlme;62906291if (iwl_trans_dbg_ini_valid(mvm->trans)) {6292iwl_mvm_event_mlme_callback_ini(mvm, vif, &event->u.mlme);6293return;6294}62956296trig = iwl_fw_dbg_trigger_on(&mvm->fwrt, ieee80211_vif_to_wdev(vif),6297FW_DBG_TRIGGER_MLME);6298if (!trig)6299return;63006301trig_mlme = (void *)trig->data;63026303if (event->u.mlme.data == ASSOC_EVENT) {6304if (event->u.mlme.status == MLME_DENIED)6305CHECK_MLME_TRIGGER(stop_assoc_denied,6306"DENIED ASSOC: reason %d",6307event->u.mlme.reason);6308else if (event->u.mlme.status == MLME_TIMEOUT)6309CHECK_MLME_TRIGGER(stop_assoc_timeout,6310"ASSOC TIMEOUT");6311} else if (event->u.mlme.data == AUTH_EVENT) {6312if (event->u.mlme.status == MLME_DENIED)6313CHECK_MLME_TRIGGER(stop_auth_denied,6314"DENIED AUTH: reason %d",6315event->u.mlme.reason);6316else if (event->u.mlme.status == MLME_TIMEOUT)6317CHECK_MLME_TRIGGER(stop_auth_timeout,6318"AUTH TIMEOUT");6319} else if (event->u.mlme.data == DEAUTH_RX_EVENT) {6320CHECK_MLME_TRIGGER(stop_rx_deauth,6321"DEAUTH RX %d", event->u.mlme.reason);6322} else if (event->u.mlme.data == DEAUTH_TX_EVENT) {6323CHECK_MLME_TRIGGER(stop_tx_deauth,6324"DEAUTH TX %d", event->u.mlme.reason);6325}6326#undef CHECK_MLME_TRIGGER6327}63286329static void iwl_mvm_event_bar_rx_callback(struct iwl_mvm *mvm,6330struct ieee80211_vif *vif,6331const struct ieee80211_event *event)6332{6333struct iwl_fw_dbg_trigger_tlv *trig;6334struct iwl_fw_dbg_trigger_ba *ba_trig;63356336trig = iwl_fw_dbg_trigger_on(&mvm->fwrt, ieee80211_vif_to_wdev(vif),6337FW_DBG_TRIGGER_BA);6338if (!trig)6339return;63406341ba_trig = (void *)trig->data;63426343if (!(le16_to_cpu(ba_trig->rx_bar) & BIT(event->u.ba.tid)))6344return;63456346iwl_fw_dbg_collect_trig(&mvm->fwrt, trig,6347"BAR received from %pM, tid %d, ssn %d",6348event->u.ba.sta->addr, event->u.ba.tid,6349event->u.ba.ssn);6350}63516352void iwl_mvm_mac_event_callback(struct ieee80211_hw *hw,6353struct ieee80211_vif *vif,6354const struct ieee80211_event *event)6355{6356struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);63576358switch (event->type) {6359case MLME_EVENT:6360iwl_mvm_event_mlme_callback(mvm, vif, event);6361break;6362case BAR_RX_EVENT:6363iwl_mvm_event_bar_rx_callback(mvm, vif, event);6364break;6365case BA_FRAME_TIMEOUT:6366iwl_mvm_event_frame_timeout_callback(mvm, vif, event->u.ba.sta,6367event->u.ba.tid);6368break;6369default:6370break;6371}6372}63736374#define SYNC_RX_QUEUE_TIMEOUT (HZ)6375void iwl_mvm_sync_rx_queues_internal(struct iwl_mvm *mvm,6376enum iwl_mvm_rxq_notif_type type,6377bool sync,6378const void *data, u32 size)6379{6380DEFINE_RAW_FLEX(struct iwl_rxq_sync_cmd, cmd, payload,6381sizeof(struct iwl_mvm_internal_rxq_notif));6382struct iwl_mvm_internal_rxq_notif *notif =6383(struct iwl_mvm_internal_rxq_notif *)cmd->payload;6384struct iwl_host_cmd hcmd = {6385.id = WIDE_ID(DATA_PATH_GROUP, TRIGGER_RX_QUEUES_NOTIF_CMD),6386.data[0] = cmd,6387.len[0] = __struct_size(cmd),6388.data[1] = data,6389.len[1] = size,6390.flags = CMD_SEND_IN_RFKILL | (sync ? 0 : CMD_ASYNC),6391};6392int ret;63936394cmd->rxq_mask = cpu_to_le32(BIT(mvm->trans->info.num_rxqs) - 1);6395cmd->count = cpu_to_le32(sizeof(struct iwl_mvm_internal_rxq_notif) +6396size);6397notif->type = type;6398notif->sync = sync;63996400/* size must be a multiple of DWORD */6401if (WARN_ON(cmd->count & cpu_to_le32(3)))6402return;64036404if (!iwl_mvm_has_new_rx_api(mvm))6405return;64066407if (sync) {6408notif->cookie = mvm->queue_sync_cookie;6409mvm->queue_sync_state = (1 << mvm->trans->info.num_rxqs) - 1;6410}64116412ret = iwl_mvm_send_cmd(mvm, &hcmd);6413if (ret) {6414IWL_ERR(mvm, "Failed to trigger RX queues sync (%d)\n", ret);6415goto out;6416}64176418if (sync) {6419lockdep_assert_held(&mvm->mutex);6420ret = wait_event_timeout(mvm->rx_sync_waitq,6421READ_ONCE(mvm->queue_sync_state) == 0,6422SYNC_RX_QUEUE_TIMEOUT);6423WARN_ONCE(!ret, "queue sync: failed to sync, state is 0x%lx, cookie %d\n",6424mvm->queue_sync_state,6425mvm->queue_sync_cookie);6426}64276428out:6429if (sync) {6430mvm->queue_sync_state = 0;6431mvm->queue_sync_cookie++;6432}6433}64346435void iwl_mvm_sync_rx_queues(struct ieee80211_hw *hw)6436{6437struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);64386439guard(mvm)(mvm);6440iwl_mvm_sync_rx_queues_internal(mvm, IWL_MVM_RXQ_EMPTY, true, NULL, 0);6441}64426443int6444iwl_mvm_mac_get_ftm_responder_stats(struct ieee80211_hw *hw,6445struct ieee80211_vif *vif,6446struct cfg80211_ftm_responder_stats *stats)6447{6448struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);6449struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);64506451if (vif->p2p || vif->type != NL80211_IFTYPE_AP ||6452!mvmvif->ap_ibss_active || !vif->bss_conf.ftm_responder)6453return -EINVAL;64546455mutex_lock(&mvm->mutex);6456*stats = mvm->ftm_resp_stats;6457mutex_unlock(&mvm->mutex);64586459stats->filled = BIT(NL80211_FTM_STATS_SUCCESS_NUM) |6460BIT(NL80211_FTM_STATS_PARTIAL_NUM) |6461BIT(NL80211_FTM_STATS_FAILED_NUM) |6462BIT(NL80211_FTM_STATS_ASAP_NUM) |6463BIT(NL80211_FTM_STATS_NON_ASAP_NUM) |6464BIT(NL80211_FTM_STATS_TOTAL_DURATION_MSEC) |6465BIT(NL80211_FTM_STATS_UNKNOWN_TRIGGERS_NUM) |6466BIT(NL80211_FTM_STATS_RESCHEDULE_REQUESTS_NUM) |6467BIT(NL80211_FTM_STATS_OUT_OF_WINDOW_TRIGGERS_NUM);64686469return 0;6470}64716472int iwl_mvm_start_pmsr(struct ieee80211_hw *hw, struct ieee80211_vif *vif,6473struct cfg80211_pmsr_request *request)6474{6475struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);64766477guard(mvm)(mvm);6478return iwl_mvm_ftm_start(mvm, vif, request);6479}64806481void iwl_mvm_abort_pmsr(struct ieee80211_hw *hw, struct ieee80211_vif *vif,6482struct cfg80211_pmsr_request *request)6483{6484struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);64856486guard(mvm)(mvm);6487iwl_mvm_ftm_abort(mvm, request);6488}64896490static bool iwl_mvm_can_hw_csum(struct sk_buff *skb)6491{6492u8 protocol = ip_hdr(skb)->protocol;64936494if (!IS_ENABLED(CONFIG_INET))6495return false;64966497return protocol == IPPROTO_TCP || protocol == IPPROTO_UDP;6498}64996500static bool iwl_mvm_mac_can_aggregate(struct ieee80211_hw *hw,6501struct sk_buff *head,6502struct sk_buff *skb)6503{6504struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);65056506/* For now don't aggregate IPv6 in AMSDU */6507if (skb->protocol != htons(ETH_P_IP))6508return false;65096510if (!iwl_mvm_is_csum_supported(mvm))6511return true;65126513return iwl_mvm_can_hw_csum(skb) == iwl_mvm_can_hw_csum(head);6514}65156516int iwl_mvm_set_hw_timestamp(struct ieee80211_hw *hw,6517struct ieee80211_vif *vif,6518struct cfg80211_set_hw_timestamp *hwts)6519{6520struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);6521u32 protocols = 0;65226523/* HW timestamping is only supported for a specific station */6524if (!hwts->macaddr)6525return -EOPNOTSUPP;65266527if (hwts->enable)6528protocols =6529IWL_TIME_SYNC_PROTOCOL_TM | IWL_TIME_SYNC_PROTOCOL_FTM;65306531guard(mvm)(mvm);6532return iwl_mvm_time_sync_config(mvm, hwts->macaddr, protocols);6533}65346535const struct ieee80211_ops iwl_mvm_hw_ops = {6536.tx = iwl_mvm_mac_tx,6537.wake_tx_queue = iwl_mvm_mac_wake_tx_queue,6538.ampdu_action = iwl_mvm_mac_ampdu_action,6539.get_antenna = iwl_mvm_op_get_antenna,6540.set_antenna = iwl_mvm_op_set_antenna,6541.start = iwl_mvm_mac_start,6542.reconfig_complete = iwl_mvm_mac_reconfig_complete,6543.stop = iwl_mvm_mac_stop,6544.add_interface = iwl_mvm_mac_add_interface,6545.remove_interface = iwl_mvm_mac_remove_interface,6546.config = iwl_mvm_mac_config,6547.prepare_multicast = iwl_mvm_prepare_multicast,6548.configure_filter = iwl_mvm_configure_filter,6549.config_iface_filter = iwl_mvm_config_iface_filter,6550.bss_info_changed = iwl_mvm_bss_info_changed,6551.hw_scan = iwl_mvm_mac_hw_scan,6552.cancel_hw_scan = iwl_mvm_mac_cancel_hw_scan,6553.sta_pre_rcu_remove = iwl_mvm_sta_pre_rcu_remove,6554.sta_state = iwl_mvm_mac_sta_state,6555.sta_notify = iwl_mvm_mac_sta_notify,6556.allow_buffered_frames = iwl_mvm_mac_allow_buffered_frames,6557.release_buffered_frames = iwl_mvm_mac_release_buffered_frames,6558.set_rts_threshold = iwl_mvm_mac_set_rts_threshold,6559.link_sta_rc_update = iwl_mvm_sta_rc_update,6560.conf_tx = iwl_mvm_mac_conf_tx,6561.mgd_prepare_tx = iwl_mvm_mac_mgd_prepare_tx,6562.mgd_complete_tx = iwl_mvm_mac_mgd_complete_tx,6563.mgd_protect_tdls_discover = iwl_mvm_mac_mgd_protect_tdls_discover,6564.flush = iwl_mvm_mac_flush,6565.flush_sta = iwl_mvm_mac_flush_sta,6566.sched_scan_start = iwl_mvm_mac_sched_scan_start,6567.sched_scan_stop = iwl_mvm_mac_sched_scan_stop,6568.set_key = iwl_mvm_mac_set_key,6569.update_tkip_key = iwl_mvm_mac_update_tkip_key,6570.remain_on_channel = iwl_mvm_roc,6571.cancel_remain_on_channel = iwl_mvm_cancel_roc,6572.add_chanctx = iwl_mvm_add_chanctx,6573.remove_chanctx = iwl_mvm_remove_chanctx,6574.change_chanctx = iwl_mvm_change_chanctx,6575.assign_vif_chanctx = iwl_mvm_assign_vif_chanctx,6576.unassign_vif_chanctx = iwl_mvm_unassign_vif_chanctx,6577.switch_vif_chanctx = iwl_mvm_switch_vif_chanctx,65786579.start_ap = iwl_mvm_start_ap,6580.stop_ap = iwl_mvm_stop_ap,6581.join_ibss = iwl_mvm_start_ibss,6582.leave_ibss = iwl_mvm_stop_ibss,65836584.tx_last_beacon = iwl_mvm_tx_last_beacon,65856586.set_tim = iwl_mvm_set_tim,65876588.channel_switch = iwl_mvm_channel_switch,6589.pre_channel_switch = iwl_mvm_mac_pre_channel_switch,6590.post_channel_switch = iwl_mvm_post_channel_switch,6591.abort_channel_switch = iwl_mvm_abort_channel_switch,6592.channel_switch_rx_beacon = iwl_mvm_channel_switch_rx_beacon,65936594.tdls_channel_switch = iwl_mvm_tdls_channel_switch,6595.tdls_cancel_channel_switch = iwl_mvm_tdls_cancel_channel_switch,6596.tdls_recv_channel_switch = iwl_mvm_tdls_recv_channel_switch,65976598.event_callback = iwl_mvm_mac_event_callback,65996600.sync_rx_queues = iwl_mvm_sync_rx_queues,66016602#ifdef CONFIG_PM_SLEEP6603/* look at d3.c */6604.suspend = iwl_mvm_suspend,6605.resume = iwl_mvm_resume,6606.set_wakeup = iwl_mvm_set_wakeup,6607.set_rekey_data = iwl_mvm_set_rekey_data,6608#if IS_ENABLED(CONFIG_IPV6)6609.ipv6_addr_change = iwl_mvm_ipv6_addr_change,6610#endif6611.set_default_unicast_key = iwl_mvm_set_default_unicast_key,6612#endif6613.get_survey = iwl_mvm_mac_get_survey,6614.sta_statistics = iwl_mvm_mac_sta_statistics,6615.get_ftm_responder_stats = iwl_mvm_mac_get_ftm_responder_stats,6616.start_pmsr = iwl_mvm_start_pmsr,6617.abort_pmsr = iwl_mvm_abort_pmsr,66186619.can_aggregate_in_amsdu = iwl_mvm_mac_can_aggregate,6620#ifdef CONFIG_IWLWIFI_DEBUGFS6621.vif_add_debugfs = iwl_mvm_vif_add_debugfs,6622.link_sta_add_debugfs = iwl_mvm_link_sta_add_debugfs,6623#endif6624.set_hw_timestamp = iwl_mvm_set_hw_timestamp,6625};662666276628