Path: blob/main/sys/contrib/dev/iwlwifi/mvm/mld-mac80211.c
48285 views
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause1/*2* Copyright (C) 2022-2025 Intel Corporation3*/4#include "mvm.h"56static int iwl_mvm_mld_mac_add_interface(struct ieee80211_hw *hw,7struct ieee80211_vif *vif)8{9struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);10struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);11int ret;12int i;1314guard(mvm)(mvm);1516iwl_mvm_mac_init_mvmvif(mvm, mvmvif);1718mvmvif->mvm = mvm;1920vif->driver_flags |= IEEE80211_VIF_REMOVE_AP_AFTER_DISASSOC;2122/* Not much to do here. The stack will not allow interface23* types or combinations that we didn't advertise, so we24* don't really have to check the types.25*/2627/* make sure that beacon statistics don't go backwards with FW reset */28if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))29for_each_mvm_vif_valid_link(mvmvif, i)30mvmvif->link[i]->beacon_stats.accu_num_beacons +=31mvmvif->link[i]->beacon_stats.num_beacons;3233/* Allocate resources for the MAC context, and add it to the fw */34ret = iwl_mvm_mac_ctxt_init(mvm, vif);35if (ret)36return ret;3738rcu_assign_pointer(mvm->vif_id_to_mac[mvmvif->id], vif);3940mvmvif->features |= hw->netdev_features;4142/* reset deflink MLO parameters */43mvmvif->deflink.fw_link_id = IWL_MVM_FW_LINK_ID_INVALID;44mvmvif->deflink.active = 0;4546ret = iwl_mvm_mld_mac_ctxt_add(mvm, vif);47if (ret)48return ret;4950/* beacon filtering */51ret = iwl_mvm_disable_beacon_filter(mvm, vif);52if (ret)53goto out_remove_mac;5455if (!mvm->bf_allowed_vif &&56vif->type == NL80211_IFTYPE_STATION && !vif->p2p) {57mvm->bf_allowed_vif = mvmvif;58vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER |59IEEE80211_VIF_SUPPORTS_CQM_RSSI;60}6162/* We want link[0] to point to the default link, unless we have MLO and63* in this case this will be modified later by .change_vif_links()64* If we are in the restart flow with an MLD connection, we will wait65* to .change_vif_links() to setup the links.66*/67if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) ||68!ieee80211_vif_is_mld(vif)) {69mvmvif->link[0] = &mvmvif->deflink;7071ret = iwl_mvm_add_link(mvm, vif, &vif->bss_conf);72if (ret)73goto out_free_bf;74}7576/* Save a pointer to p2p device vif, so it can later be used to77* update the p2p device MAC when a GO is started/stopped78*/79if (vif->type == NL80211_IFTYPE_P2P_DEVICE)80mvm->p2p_device_vif = vif;8182ret = iwl_mvm_power_update_mac(mvm);83if (ret)84goto out_free_bf;8586iwl_mvm_tcm_add_vif(mvm, vif);8788if (vif->type == NL80211_IFTYPE_MONITOR) {89mvm->monitor_on = true;90ieee80211_hw_set(mvm->hw, RX_INCLUDES_FCS);91}9293if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))94iwl_mvm_vif_dbgfs_add_link(mvm, vif);9596if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) &&97vif->type == NL80211_IFTYPE_STATION && !vif->p2p &&98!mvm->csme_vif && mvm->mei_registered) {99iwl_mei_set_nic_info(vif->addr, mvm->nvm_data->hw_addr);100iwl_mei_set_netdev(ieee80211_vif_to_wdev(vif)->netdev);101mvm->csme_vif = vif;102}103104if (vif->p2p || iwl_fw_lookup_cmd_ver(mvm->fw, PHY_CONTEXT_CMD, 1) < 5)105vif->driver_flags |= IEEE80211_VIF_IGNORE_OFDMA_WIDER_BW;106107return 0;108109out_free_bf:110if (mvm->bf_allowed_vif == mvmvif) {111mvm->bf_allowed_vif = NULL;112vif->driver_flags &= ~(IEEE80211_VIF_BEACON_FILTER |113IEEE80211_VIF_SUPPORTS_CQM_RSSI);114}115out_remove_mac:116mvmvif->link[0] = NULL;117iwl_mvm_mld_mac_ctxt_remove(mvm, vif);118return ret;119}120121static void iwl_mvm_mld_mac_remove_interface(struct ieee80211_hw *hw,122struct ieee80211_vif *vif)123{124struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);125struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);126struct iwl_probe_resp_data *probe_data;127128iwl_mvm_prepare_mac_removal(mvm, vif);129130if (!(vif->type == NL80211_IFTYPE_AP ||131vif->type == NL80211_IFTYPE_ADHOC))132iwl_mvm_tcm_rm_vif(mvm, vif);133134guard(mvm)(mvm);135136if (vif == mvm->csme_vif) {137iwl_mei_set_netdev(NULL);138mvm->csme_vif = NULL;139}140141if (mvm->bf_allowed_vif == mvmvif) {142mvm->bf_allowed_vif = NULL;143vif->driver_flags &= ~(IEEE80211_VIF_BEACON_FILTER |144IEEE80211_VIF_SUPPORTS_CQM_RSSI);145}146147if (vif->bss_conf.ftm_responder)148memset(&mvm->ftm_resp_stats, 0, sizeof(mvm->ftm_resp_stats));149150iwl_mvm_vif_dbgfs_rm_link(mvm, vif);151152iwl_mvm_power_update_mac(mvm);153154/* Before the interface removal, mac80211 would cancel the ROC, and the155* ROC worker would be scheduled if needed. The worker would be flushed156* in iwl_mvm_prepare_mac_removal() and thus at this point the link is157* not active. So need only to remove the link.158*/159if (vif->type == NL80211_IFTYPE_P2P_DEVICE) {160if (mvmvif->deflink.phy_ctxt) {161iwl_mvm_phy_ctxt_unref(mvm, mvmvif->deflink.phy_ctxt);162mvmvif->deflink.phy_ctxt = NULL;163}164mvm->p2p_device_vif = NULL;165iwl_mvm_remove_link(mvm, vif, &vif->bss_conf);166} else {167iwl_mvm_disable_link(mvm, vif, &vif->bss_conf);168}169170iwl_mvm_mld_mac_ctxt_remove(mvm, vif);171172RCU_INIT_POINTER(mvm->vif_id_to_mac[mvmvif->id], NULL);173174probe_data = rcu_dereference_protected(mvmvif->deflink.probe_resp_data,175lockdep_is_held(&mvm->mutex));176RCU_INIT_POINTER(mvmvif->deflink.probe_resp_data, NULL);177if (probe_data)178kfree_rcu(probe_data, rcu_head);179180if (vif->type == NL80211_IFTYPE_MONITOR) {181mvm->monitor_on = false;182__clear_bit(IEEE80211_HW_RX_INCLUDES_FCS, mvm->hw->flags);183}184}185186static unsigned int iwl_mvm_mld_count_active_links(struct iwl_mvm_vif *mvmvif)187{188unsigned int n_active = 0;189int i;190191for (i = 0; i < IEEE80211_MLD_MAX_NUM_LINKS; i++) {192if (mvmvif->link[i] && mvmvif->link[i]->phy_ctxt)193n_active++;194}195196return n_active;197}198199static int iwl_mvm_esr_mode_active(struct iwl_mvm *mvm,200struct ieee80211_vif *vif)201{202struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);203int link_id, ret = 0;204205mvmvif->esr_active = true;206207/* Indicate to mac80211 that EML is enabled */208vif->driver_flags |= IEEE80211_VIF_EML_ACTIVE;209210iwl_mvm_update_smps_on_active_links(mvm, vif, IWL_MVM_SMPS_REQ_FW,211IEEE80211_SMPS_OFF);212213for_each_mvm_vif_valid_link(mvmvif, link_id) {214struct iwl_mvm_vif_link_info *link = mvmvif->link[link_id];215216if (!link->phy_ctxt)217continue;218219ret = iwl_mvm_phy_send_rlc(mvm, link->phy_ctxt, 2, 2);220if (ret)221break;222223link->phy_ctxt->rlc_disabled = true;224}225226if (vif->active_links == mvmvif->link_selection_res &&227!WARN_ON(!(vif->active_links & BIT(mvmvif->link_selection_primary))))228mvmvif->primary_link = mvmvif->link_selection_primary;229else230mvmvif->primary_link = __ffs(vif->active_links);231232iwl_dbg_tlv_time_point(&mvm->fwrt, IWL_FW_INI_TIME_ESR_LINK_UP,233NULL);234235return ret;236}237238static int239__iwl_mvm_mld_assign_vif_chanctx(struct iwl_mvm *mvm,240struct ieee80211_vif *vif,241struct ieee80211_bss_conf *link_conf,242struct ieee80211_chanctx_conf *ctx,243bool switching_chanctx)244{245u16 *phy_ctxt_id = (u16 *)ctx->drv_priv;246struct iwl_mvm_phy_ctxt *phy_ctxt = &mvm->phy_ctxts[*phy_ctxt_id];247struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);248unsigned int n_active = iwl_mvm_mld_count_active_links(mvmvif);249unsigned int link_id = link_conf->link_id;250int ret;251252if (WARN_ON_ONCE(!mvmvif->link[link_id]))253return -EINVAL;254255/* if the assigned one was not counted yet, count it now */256if (!mvmvif->link[link_id]->phy_ctxt)257n_active++;258259/* mac parameters such as HE support can change at this stage260* For sta, need first to configure correct state from drv_sta_state261* and only after that update mac config.262*/263if (vif->type == NL80211_IFTYPE_AP) {264ret = iwl_mvm_mld_mac_ctxt_changed(mvm, vif, false);265if (ret) {266IWL_ERR(mvm, "failed to update MAC %pM\n", vif->addr);267return -EINVAL;268}269}270271mvmvif->link[link_id]->phy_ctxt = phy_ctxt;272273if (iwl_mvm_is_esr_supported(mvm->fwrt.trans) && n_active > 1) {274mvmvif->link[link_id]->listen_lmac = true;275ret = iwl_mvm_esr_mode_active(mvm, vif);276if (ret) {277IWL_ERR(mvm, "failed to activate ESR mode (%d)\n", ret);278goto out;279}280}281282if (switching_chanctx) {283/* reactivate if we turned this off during channel switch */284if (vif->type == NL80211_IFTYPE_AP)285mvmvif->ap_ibss_active = true;286}287288/* send it first with phy context ID */289ret = iwl_mvm_link_changed(mvm, vif, link_conf, 0, false);290if (ret)291goto out;292293/*294* if link switching (link not active yet) we'll activate it in295* firmware later on link-info change, which mac80211 guarantees296* for link switch after the stations are set up297*/298if (ieee80211_vif_link_active(vif, link_conf->link_id)) {299ret = iwl_mvm_link_changed(mvm, vif, link_conf,300LINK_CONTEXT_MODIFY_ACTIVE |301LINK_CONTEXT_MODIFY_RATES_INFO,302true);303if (ret)304goto out;305}306307if (vif->type == NL80211_IFTYPE_STATION)308iwl_mvm_send_ap_tx_power_constraint_cmd(mvm, vif,309link_conf,310false);311312/*313* Power state must be updated before quotas,314* otherwise fw will complain.315*/316iwl_mvm_power_update_mac(mvm);317318if (vif->type == NL80211_IFTYPE_MONITOR) {319ret = iwl_mvm_mld_add_snif_sta(mvm, vif, link_conf);320if (ret)321goto deactivate;322}323324return 0;325326deactivate:327iwl_mvm_link_changed(mvm, vif, link_conf, LINK_CONTEXT_MODIFY_ACTIVE,328false);329out:330mvmvif->link[link_id]->phy_ctxt = NULL;331iwl_mvm_power_update_mac(mvm);332return ret;333}334335static int iwl_mvm_mld_assign_vif_chanctx(struct ieee80211_hw *hw,336struct ieee80211_vif *vif,337struct ieee80211_bss_conf *link_conf,338struct ieee80211_chanctx_conf *ctx)339{340struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);341342/* update EMLSR mode */343if (ieee80211_vif_type_p2p(vif) != NL80211_IFTYPE_STATION) {344int ret;345346ret = iwl_mvm_esr_non_bss_link(mvm, vif, link_conf->link_id,347true);348/*349* Don't activate this link if failed to exit EMLSR in350* the BSS interface351*/352if (ret)353return ret;354}355356guard(mvm)(mvm);357return __iwl_mvm_mld_assign_vif_chanctx(mvm, vif, link_conf, ctx, false);358}359360static int iwl_mvm_esr_mode_inactive(struct iwl_mvm *mvm,361struct ieee80211_vif *vif)362{363struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);364struct ieee80211_bss_conf *link_conf;365int link_id, ret = 0;366367mvmvif->esr_active = false;368369vif->driver_flags &= ~IEEE80211_VIF_EML_ACTIVE;370371iwl_mvm_update_smps_on_active_links(mvm, vif, IWL_MVM_SMPS_REQ_FW,372IEEE80211_SMPS_AUTOMATIC);373374for_each_vif_active_link(vif, link_conf, link_id) {375struct ieee80211_chanctx_conf *chanctx_conf;376struct iwl_mvm_phy_ctxt *phy_ctxt;377u8 static_chains, dynamic_chains;378379mvmvif->link[link_id]->listen_lmac = false;380381rcu_read_lock();382383chanctx_conf = rcu_dereference(link_conf->chanctx_conf);384phy_ctxt = mvmvif->link[link_id]->phy_ctxt;385386if (!chanctx_conf || !phy_ctxt) {387rcu_read_unlock();388continue;389}390391phy_ctxt->rlc_disabled = false;392static_chains = chanctx_conf->rx_chains_static;393dynamic_chains = chanctx_conf->rx_chains_dynamic;394395rcu_read_unlock();396397ret = iwl_mvm_phy_send_rlc(mvm, phy_ctxt, static_chains,398dynamic_chains);399if (ret)400break;401}402403iwl_dbg_tlv_time_point(&mvm->fwrt, IWL_FW_INI_TIME_ESR_LINK_DOWN,404NULL);405406return ret;407}408409static void410__iwl_mvm_mld_unassign_vif_chanctx(struct iwl_mvm *mvm,411struct ieee80211_vif *vif,412struct ieee80211_bss_conf *link_conf,413struct ieee80211_chanctx_conf *ctx,414bool switching_chanctx)415416{417struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);418unsigned int n_active = iwl_mvm_mld_count_active_links(mvmvif);419unsigned int link_id = link_conf->link_id;420421/* shouldn't happen, but verify link_id is valid before accessing */422if (WARN_ON_ONCE(!mvmvif->link[link_id]))423return;424425if (vif->type == NL80211_IFTYPE_AP && switching_chanctx) {426mvmvif->csa_countdown = false;427428/* Set CS bit on all the stations */429iwl_mvm_modify_all_sta_disable_tx(mvm, mvmvif, true);430431/* Save blocked iface, the timeout is set on the next beacon */432rcu_assign_pointer(mvm->csa_tx_blocked_vif, vif);433434mvmvif->ap_ibss_active = false;435}436437iwl_mvm_link_changed(mvm, vif, link_conf,438LINK_CONTEXT_MODIFY_ACTIVE, false);439440if (iwl_mvm_is_esr_supported(mvm->fwrt.trans) && n_active > 1) {441int ret = iwl_mvm_esr_mode_inactive(mvm, vif);442443if (ret)444IWL_ERR(mvm, "failed to deactivate ESR mode (%d)\n",445ret);446}447448if (vif->type == NL80211_IFTYPE_MONITOR)449iwl_mvm_mld_rm_snif_sta(mvm, vif);450451if (switching_chanctx)452return;453mvmvif->link[link_id]->phy_ctxt = NULL;454iwl_mvm_power_update_mac(mvm);455}456457static void iwl_mvm_mld_unassign_vif_chanctx(struct ieee80211_hw *hw,458struct ieee80211_vif *vif,459struct ieee80211_bss_conf *link_conf,460struct ieee80211_chanctx_conf *ctx)461{462struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);463struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);464465mutex_lock(&mvm->mutex);466__iwl_mvm_mld_unassign_vif_chanctx(mvm, vif, link_conf, ctx, false);467/* in the non-MLD case, remove/re-add the link to clean up FW state */468if (!ieee80211_vif_is_mld(vif) && !mvmvif->ap_sta &&469!WARN_ON_ONCE(vif->cfg.assoc)) {470iwl_mvm_remove_link(mvm, vif, link_conf);471iwl_mvm_add_link(mvm, vif, link_conf);472}473mutex_unlock(&mvm->mutex);474475/* update EMLSR mode */476if (ieee80211_vif_type_p2p(vif) != NL80211_IFTYPE_STATION)477iwl_mvm_esr_non_bss_link(mvm, vif, link_conf->link_id, false);478}479480static void481iwl_mvm_tpe_sta_cmd_data(struct iwl_txpower_constraints_cmd *cmd,482const struct ieee80211_bss_conf *bss_info)483{484u8 i;485486/*487* NOTE: the 0 here is IEEE80211_TPE_CAT_6GHZ_DEFAULT,488* we fully ignore IEEE80211_TPE_CAT_6GHZ_SUBORDINATE489*/490491BUILD_BUG_ON(ARRAY_SIZE(cmd->psd_pwr) !=492ARRAY_SIZE(bss_info->tpe.psd_local[0].power));493494/* if not valid, mac80211 puts default (max value) */495for (i = 0; i < ARRAY_SIZE(cmd->psd_pwr); i++)496cmd->psd_pwr[i] = min(bss_info->tpe.psd_local[0].power[i],497bss_info->tpe.psd_reg_client[0].power[i]);498499BUILD_BUG_ON(ARRAY_SIZE(cmd->eirp_pwr) !=500ARRAY_SIZE(bss_info->tpe.max_local[0].power));501502for (i = 0; i < ARRAY_SIZE(cmd->eirp_pwr); i++)503cmd->eirp_pwr[i] = min(bss_info->tpe.max_local[0].power[i],504bss_info->tpe.max_reg_client[0].power[i]);505}506507void508iwl_mvm_send_ap_tx_power_constraint_cmd(struct iwl_mvm *mvm,509struct ieee80211_vif *vif,510struct ieee80211_bss_conf *bss_conf,511bool is_ap)512{513struct iwl_txpower_constraints_cmd cmd = {};514struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);515struct iwl_mvm_vif_link_info *link_info =516mvmvif->link[bss_conf->link_id];517u32 cmd_id = WIDE_ID(PHY_OPS_GROUP, AP_TX_POWER_CONSTRAINTS_CMD);518u32 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, cmd_id,519IWL_FW_CMD_VER_UNKNOWN);520int ret;521522lockdep_assert_held(&mvm->mutex);523524if (cmd_ver == IWL_FW_CMD_VER_UNKNOWN)525return;526527if (!link_info->active ||528link_info->fw_link_id == IWL_MVM_FW_LINK_ID_INVALID)529return;530531if (bss_conf->chanreq.oper.chan->band != NL80211_BAND_6GHZ)532return;533534cmd.link_id = cpu_to_le16(link_info->fw_link_id);535memset(cmd.psd_pwr, DEFAULT_TPE_TX_POWER, sizeof(cmd.psd_pwr));536memset(cmd.eirp_pwr, DEFAULT_TPE_TX_POWER, sizeof(cmd.eirp_pwr));537538if (is_ap) {539cmd.ap_type = cpu_to_le16(IWL_6GHZ_AP_TYPE_VLP);540} else if (bss_conf->power_type == IEEE80211_REG_UNSET_AP) {541return;542} else {543cmd.ap_type = cpu_to_le16(bss_conf->power_type - 1);544iwl_mvm_tpe_sta_cmd_data(&cmd, bss_conf);545}546547ret = iwl_mvm_send_cmd_pdu(mvm,548WIDE_ID(PHY_OPS_GROUP,549AP_TX_POWER_CONSTRAINTS_CMD),5500, sizeof(cmd), &cmd);551if (ret)552IWL_ERR(mvm,553"failed to send AP_TX_POWER_CONSTRAINTS_CMD (%d)\n",554ret);555}556557static int iwl_mvm_mld_start_ap_ibss(struct ieee80211_hw *hw,558struct ieee80211_vif *vif,559struct ieee80211_bss_conf *link_conf)560{561struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);562struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);563int ret;564565guard(mvm)(mvm);566567if (vif->type == NL80211_IFTYPE_AP)568iwl_mvm_send_ap_tx_power_constraint_cmd(mvm, vif,569link_conf, true);570571/* Send the beacon template */572ret = iwl_mvm_mac_ctxt_beacon_changed(mvm, vif, link_conf);573if (ret)574return ret;575576/* the link should be already activated when assigning chan context */577ret = iwl_mvm_link_changed(mvm, vif, link_conf,578LINK_CONTEXT_MODIFY_ALL &579~LINK_CONTEXT_MODIFY_ACTIVE,580true);581if (ret)582return ret;583584ret = iwl_mvm_mld_add_mcast_sta(mvm, vif, link_conf);585if (ret)586return ret;587588/* Send the bcast station. At this stage the TBTT and DTIM time589* events are added and applied to the scheduler590*/591ret = iwl_mvm_mld_add_bcast_sta(mvm, vif, link_conf);592if (ret)593goto out_rm_mcast;594595if (iwl_mvm_start_ap_ibss_common(hw, vif, &ret))596goto out_failed;597598/* Need to update the P2P Device MAC (only GO, IBSS is single vif) */599if (vif->p2p && mvm->p2p_device_vif)600iwl_mvm_mld_mac_ctxt_changed(mvm, mvm->p2p_device_vif, false);601602iwl_mvm_bt_coex_vif_change(mvm);603604/* we don't support TDLS during DCM */605if (iwl_mvm_phy_ctx_count(mvm) > 1)606iwl_mvm_teardown_tdls_peers(mvm);607608iwl_mvm_ftm_restart_responder(mvm, vif, link_conf);609610return 0;611612out_failed:613iwl_mvm_power_update_mac(mvm);614mvmvif->ap_ibss_active = false;615iwl_mvm_mld_rm_bcast_sta(mvm, vif, link_conf);616out_rm_mcast:617iwl_mvm_mld_rm_mcast_sta(mvm, vif, link_conf);618return ret;619}620621static int iwl_mvm_mld_start_ap(struct ieee80211_hw *hw,622struct ieee80211_vif *vif,623struct ieee80211_bss_conf *link_conf)624{625return iwl_mvm_mld_start_ap_ibss(hw, vif, link_conf);626}627628static int iwl_mvm_mld_start_ibss(struct ieee80211_hw *hw,629struct ieee80211_vif *vif)630{631return iwl_mvm_mld_start_ap_ibss(hw, vif, &vif->bss_conf);632}633634static void iwl_mvm_mld_stop_ap_ibss(struct ieee80211_hw *hw,635struct ieee80211_vif *vif,636struct ieee80211_bss_conf *link_conf)637{638struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);639640guard(mvm)(mvm);641642iwl_mvm_stop_ap_ibss_common(mvm, vif);643644/* Need to update the P2P Device MAC (only GO, IBSS is single vif) */645if (vif->p2p && mvm->p2p_device_vif)646iwl_mvm_mld_mac_ctxt_changed(mvm, mvm->p2p_device_vif, false);647648iwl_mvm_ftm_responder_clear(mvm, vif);649650iwl_mvm_mld_rm_bcast_sta(mvm, vif, link_conf);651iwl_mvm_mld_rm_mcast_sta(mvm, vif, link_conf);652653iwl_mvm_power_update_mac(mvm);654}655656static void iwl_mvm_mld_stop_ap(struct ieee80211_hw *hw,657struct ieee80211_vif *vif,658struct ieee80211_bss_conf *link_conf)659{660iwl_mvm_mld_stop_ap_ibss(hw, vif, link_conf);661}662663static void iwl_mvm_mld_stop_ibss(struct ieee80211_hw *hw,664struct ieee80211_vif *vif)665{666iwl_mvm_mld_stop_ap_ibss(hw, vif, &vif->bss_conf);667}668669static int iwl_mvm_mld_mac_sta_state(struct ieee80211_hw *hw,670struct ieee80211_vif *vif,671struct ieee80211_sta *sta,672enum ieee80211_sta_state old_state,673enum ieee80211_sta_state new_state)674{675static const struct iwl_mvm_sta_state_ops callbacks = {676.add_sta = iwl_mvm_mld_add_sta,677.update_sta = iwl_mvm_mld_update_sta,678.rm_sta = iwl_mvm_mld_rm_sta,679.mac_ctxt_changed = iwl_mvm_mld_mac_ctxt_changed,680};681682return iwl_mvm_mac_sta_state_common(hw, vif, sta, old_state, new_state,683&callbacks);684}685686static bool iwl_mvm_esr_bw_criteria(struct iwl_mvm *mvm,687struct ieee80211_vif *vif,688struct ieee80211_bss_conf *link_conf)689{690struct ieee80211_bss_conf *other_link;691int link_id;692693/* Exit EMLSR if links don't have equal bandwidths */694for_each_vif_active_link(vif, other_link, link_id) {695if (link_id == link_conf->link_id)696continue;697if (link_conf->chanreq.oper.width ==698other_link->chanreq.oper.width)699return true;700}701702return false;703}704705static void706iwl_mvm_mld_link_info_changed_station(struct iwl_mvm *mvm,707struct ieee80211_vif *vif,708struct ieee80211_bss_conf *link_conf,709u64 changes)710{711struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);712bool has_he, has_eht;713u32 link_changes = 0;714int ret;715716if (WARN_ON_ONCE(!mvmvif->link[link_conf->link_id]))717return;718719/* not yet marked active in vif means during link switch */720if (!ieee80211_vif_link_active(vif, link_conf->link_id) &&721vif->cfg.assoc && mvmvif->link[link_conf->link_id]->phy_ctxt)722link_changes |= LINK_CONTEXT_MODIFY_ACTIVE;723724has_he = link_conf->he_support && !iwlwifi_mod_params.disable_11ax;725has_eht = link_conf->eht_support && !iwlwifi_mod_params.disable_11be;726727/* Update EDCA params */728if (changes & BSS_CHANGED_QOS && vif->cfg.assoc && link_conf->qos)729link_changes |= LINK_CONTEXT_MODIFY_QOS_PARAMS;730731if (changes & BSS_CHANGED_ERP_SLOT)732link_changes |= LINK_CONTEXT_MODIFY_RATES_INFO;733734if (vif->cfg.assoc && (has_he || has_eht)) {735IWL_DEBUG_MAC80211(mvm, "Associated in HE mode\n");736link_changes |= LINK_CONTEXT_MODIFY_HE_PARAMS;737}738739if ((changes & BSS_CHANGED_BANDWIDTH) &&740ieee80211_vif_link_active(vif, link_conf->link_id) &&741mvmvif->esr_active &&742!iwl_mvm_esr_bw_criteria(mvm, vif, link_conf))743iwl_mvm_exit_esr(mvm, vif,744IWL_MVM_ESR_EXIT_BANDWIDTH,745iwl_mvm_get_primary_link(vif));746747/* if associated, maybe puncturing changed - we'll check later */748if (vif->cfg.assoc)749link_changes |= LINK_CONTEXT_MODIFY_EHT_PARAMS;750751if (link_changes) {752ret = iwl_mvm_link_changed(mvm, vif, link_conf, link_changes,753true);754if (ret)755IWL_ERR(mvm, "failed to update link\n");756}757758ret = iwl_mvm_mld_mac_ctxt_changed(mvm, vif, false);759if (ret)760IWL_ERR(mvm, "failed to update MAC %pM\n", vif->addr);761762memcpy(mvmvif->link[link_conf->link_id]->bssid, link_conf->bssid,763ETH_ALEN);764765iwl_mvm_bss_info_changed_station_common(mvm, vif, link_conf, changes);766}767768static bool iwl_mvm_mld_vif_have_valid_ap_sta(struct iwl_mvm_vif *mvmvif)769{770int i;771772for_each_mvm_vif_valid_link(mvmvif, i) {773if (mvmvif->link[i]->ap_sta_id != IWL_INVALID_STA)774return true;775}776777return false;778}779780static void iwl_mvm_mld_vif_cfg_changed_station(struct iwl_mvm *mvm,781struct ieee80211_vif *vif,782u64 changes)783{784struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);785struct ieee80211_bss_conf *link_conf;786bool protect = false;787unsigned int i;788int ret;789790/* This might get called without active links during the791* chanctx switch, but we don't care about it anyway.792*/793if (changes == BSS_CHANGED_IDLE)794return;795796ret = iwl_mvm_mld_mac_ctxt_changed(mvm, vif, false);797if (ret)798IWL_ERR(mvm, "failed to update MAC %pM\n", vif->addr);799800mvmvif->associated = vif->cfg.assoc;801802if (changes & BSS_CHANGED_ASSOC) {803if (vif->cfg.assoc) {804mvmvif->session_prot_connection_loss = false;805806/*807* Clear statistics to get clean beacon counter, and ask for808* periodic statistics, as they are needed for link809* selection and RX OMI decisions.810*/811iwl_mvm_request_statistics(mvm, true);812iwl_mvm_request_periodic_system_statistics(mvm, true);813iwl_mvm_sf_update(mvm, vif, false);814iwl_mvm_power_vif_assoc(mvm, vif);815816for_each_mvm_vif_valid_link(mvmvif, i) {817memset(&mvmvif->link[i]->beacon_stats, 0,818sizeof(mvmvif->link[i]->beacon_stats));819820if (vif->p2p) {821iwl_mvm_update_smps(mvm, vif,822IWL_MVM_SMPS_REQ_PROT,823IEEE80211_SMPS_DYNAMIC, i);824}825826rcu_read_lock();827link_conf = rcu_dereference(vif->link_conf[i]);828if (link_conf && !link_conf->dtim_period)829protect = true;830rcu_read_unlock();831}832833if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) &&834protect) {835/* We are in assoc so only one link is active-836* The association link837*/838unsigned int link_id =839ffs(vif->active_links) - 1;840841/* If we're not restarting and still haven't842* heard a beacon (dtim period unknown) then843* make sure we still have enough minimum time844* remaining in the time event, since the auth845* might actually have taken quite a while846* (especially for SAE) and so the remaining847* time could be small without us having heard848* a beacon yet.849*/850iwl_mvm_protect_assoc(mvm, vif, 0, link_id);851}852853iwl_mvm_sf_update(mvm, vif, false);854855/* FIXME: need to decide about misbehaving AP handling */856iwl_mvm_power_vif_assoc(mvm, vif);857} else if (iwl_mvm_mld_vif_have_valid_ap_sta(mvmvif)) {858iwl_mvm_mei_host_disassociated(mvm);859860iwl_mvm_request_periodic_system_statistics(mvm, false);861862/* If update fails - SF might be running in associated863* mode while disassociated - which is forbidden.864*/865ret = iwl_mvm_sf_update(mvm, vif, false);866WARN_ONCE(ret &&867!test_bit(IWL_MVM_STATUS_HW_RESTART_REQUESTED,868&mvm->status),869"Failed to update SF upon disassociation\n");870}871872iwl_mvm_bss_info_changed_station_assoc(mvm, vif, changes);873}874875if (changes & BSS_CHANGED_PS) {876iwl_mvm_smps_workaround(mvm, vif, false);877ret = iwl_mvm_power_update_mac(mvm);878if (ret)879IWL_ERR(mvm, "failed to update power mode\n");880}881882if (changes & (BSS_CHANGED_MLD_VALID_LINKS | BSS_CHANGED_MLD_TTLM) &&883ieee80211_vif_is_mld(vif) && mvmvif->authorized)884wiphy_delayed_work_queue(mvm->hw->wiphy,885&mvmvif->mlo_int_scan_wk, 0);886}887888static void889iwl_mvm_mld_link_info_changed_ap_ibss(struct iwl_mvm *mvm,890struct ieee80211_vif *vif,891struct ieee80211_bss_conf *link_conf,892u64 changes)893{894struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);895u32 link_changes = LINK_CONTEXT_MODIFY_PROTECT_FLAGS |896LINK_CONTEXT_MODIFY_QOS_PARAMS;897898/* Changes will be applied when the AP/IBSS is started */899if (!mvmvif->ap_ibss_active)900return;901902if (link_conf->he_support)903link_changes |= LINK_CONTEXT_MODIFY_HE_PARAMS;904905if (changes & BSS_CHANGED_ERP_SLOT)906link_changes |= LINK_CONTEXT_MODIFY_RATES_INFO;907908if (changes & (BSS_CHANGED_ERP_CTS_PROT | BSS_CHANGED_ERP_SLOT |909BSS_CHANGED_HT |910BSS_CHANGED_BANDWIDTH | BSS_CHANGED_QOS |911BSS_CHANGED_HE_BSS_COLOR) &&912iwl_mvm_link_changed(mvm, vif, link_conf,913link_changes, true))914IWL_ERR(mvm, "failed to update MAC %pM\n", vif->addr);915916/* Need to send a new beacon template to the FW */917if (changes & BSS_CHANGED_BEACON &&918iwl_mvm_mac_ctxt_beacon_changed(mvm, vif, link_conf))919IWL_WARN(mvm, "Failed updating beacon data\n");920921/* FIXME: need to decide if we need FTM responder per link */922if (changes & BSS_CHANGED_FTM_RESPONDER) {923int ret = iwl_mvm_ftm_start_responder(mvm, vif, link_conf);924925if (ret)926IWL_WARN(mvm, "Failed to enable FTM responder (%d)\n",927ret);928}929}930931static void iwl_mvm_mld_link_info_changed(struct ieee80211_hw *hw,932struct ieee80211_vif *vif,933struct ieee80211_bss_conf *link_conf,934u64 changes)935{936struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);937938guard(mvm)(mvm);939940switch (vif->type) {941case NL80211_IFTYPE_STATION:942iwl_mvm_mld_link_info_changed_station(mvm, vif, link_conf,943changes);944break;945case NL80211_IFTYPE_AP:946case NL80211_IFTYPE_ADHOC:947iwl_mvm_mld_link_info_changed_ap_ibss(mvm, vif, link_conf,948changes);949break;950case NL80211_IFTYPE_MONITOR:951if (changes & BSS_CHANGED_MU_GROUPS)952iwl_mvm_update_mu_groups(mvm, vif);953break;954default:955/* shouldn't happen */956WARN_ON_ONCE(1);957}958959if (changes & BSS_CHANGED_TXPOWER) {960IWL_DEBUG_CALIB(mvm, "Changing TX Power to %d dBm\n",961link_conf->txpower);962iwl_mvm_set_tx_power(mvm, link_conf, link_conf->txpower);963}964}965966static void iwl_mvm_mld_vif_cfg_changed(struct ieee80211_hw *hw,967struct ieee80211_vif *vif,968u64 changes)969{970struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);971972guard(mvm)(mvm);973974if (changes & BSS_CHANGED_IDLE && !vif->cfg.idle)975iwl_mvm_scan_stop(mvm, IWL_MVM_SCAN_SCHED, true);976977if (vif->type == NL80211_IFTYPE_STATION)978iwl_mvm_mld_vif_cfg_changed_station(mvm, vif, changes);979}980981static int982iwl_mvm_mld_switch_vif_chanctx(struct ieee80211_hw *hw,983struct ieee80211_vif_chanctx_switch *vifs,984int n_vifs,985enum ieee80211_chanctx_switch_mode mode)986{987static const struct iwl_mvm_switch_vif_chanctx_ops ops = {988.__assign_vif_chanctx = __iwl_mvm_mld_assign_vif_chanctx,989.__unassign_vif_chanctx = __iwl_mvm_mld_unassign_vif_chanctx,990};991992return iwl_mvm_switch_vif_chanctx_common(hw, vifs, n_vifs, mode, &ops);993}994995static void iwl_mvm_mld_config_iface_filter(struct ieee80211_hw *hw,996struct ieee80211_vif *vif,997unsigned int filter_flags,998unsigned int changed_flags)999{1000struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);10011002/* We support only filter for probe requests */1003if (!(changed_flags & FIF_PROBE_REQ))1004return;10051006/* Supported only for p2p client interfaces */1007if (vif->type != NL80211_IFTYPE_STATION || !vif->cfg.assoc ||1008!vif->p2p)1009return;10101011guard(mvm)(mvm);1012iwl_mvm_mld_mac_ctxt_changed(mvm, vif, false);1013}10141015static int1016iwl_mvm_mld_mac_conf_tx(struct ieee80211_hw *hw,1017struct ieee80211_vif *vif,1018unsigned int link_id, u16 ac,1019const struct ieee80211_tx_queue_params *params)1020{1021struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);1022struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);1023struct iwl_mvm_vif_link_info *mvm_link = mvmvif->link[link_id];10241025if (!mvm_link)1026return -EINVAL;10271028mvm_link->queue_params[ac] = *params;10291030/* No need to update right away, we'll get BSS_CHANGED_QOS1031* The exception is P2P_DEVICE interface which needs immediate update.1032*/1033if (vif->type == NL80211_IFTYPE_P2P_DEVICE) {1034guard(mvm)(mvm);1035return iwl_mvm_link_changed(mvm, vif, &vif->bss_conf,1036LINK_CONTEXT_MODIFY_QOS_PARAMS,1037true);1038}1039return 0;1040}10411042static int iwl_mvm_mld_roc_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif)1043{1044int ret;10451046lockdep_assert_held(&mvm->mutex);10471048/* The PHY context ID might have changed so need to set it */1049ret = iwl_mvm_link_changed(mvm, vif, &vif->bss_conf, 0, false);1050if (WARN(ret, "Failed to set PHY context ID\n"))1051return ret;10521053ret = iwl_mvm_link_changed(mvm, vif, &vif->bss_conf,1054LINK_CONTEXT_MODIFY_ACTIVE |1055LINK_CONTEXT_MODIFY_RATES_INFO,1056true);10571058if (WARN(ret, "Failed linking P2P_DEVICE\n"))1059return ret;10601061/* The station and queue allocation must be done only after the linking1062* is done, as otherwise the FW might incorrectly configure its state.1063*/1064return iwl_mvm_mld_add_bcast_sta(mvm, vif, &vif->bss_conf);1065}10661067static int iwl_mvm_mld_roc(struct ieee80211_hw *hw, struct ieee80211_vif *vif,1068struct ieee80211_channel *channel, int duration,1069enum ieee80211_roc_type type)1070{1071static const struct iwl_mvm_roc_ops ops = {1072.add_aux_sta_for_hs20 = iwl_mvm_mld_add_aux_sta,1073.link = iwl_mvm_mld_roc_link,1074};10751076return iwl_mvm_roc_common(hw, vif, channel, duration, type, &ops);1077}10781079static int1080iwl_mvm_mld_change_vif_links(struct ieee80211_hw *hw,1081struct ieee80211_vif *vif,1082u16 old_links, u16 new_links,1083struct ieee80211_bss_conf *old[IEEE80211_MLD_MAX_NUM_LINKS])1084{1085struct iwl_mvm_vif_link_info *new_link[IEEE80211_MLD_MAX_NUM_LINKS] = {};1086struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);1087struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);1088u16 removed = old_links & ~new_links;1089u16 added = new_links & ~old_links;1090int err, i;10911092for (i = 0; i < IEEE80211_MLD_MAX_NUM_LINKS; i++) {1093if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))1094break;10951096if (!(added & BIT(i)))1097continue;1098new_link[i] = kzalloc(sizeof(*new_link[i]), GFP_KERNEL);1099if (!new_link[i]) {1100err = -ENOMEM;1101goto free;1102}11031104new_link[i]->fw_link_id = IWL_MVM_FW_LINK_ID_INVALID;1105iwl_mvm_init_link(new_link[i]);1106}11071108mutex_lock(&mvm->mutex);11091110/* If we're in RESTART flow, the default link wasn't added in1111* drv_add_interface(), and link[0] doesn't point to it.1112*/1113if (old_links == 0 && !test_bit(IWL_MVM_STATUS_IN_HW_RESTART,1114&mvm->status)) {1115err = iwl_mvm_disable_link(mvm, vif, &vif->bss_conf);1116if (err)1117goto out_err;1118mvmvif->link[0] = NULL;1119}11201121for (i = 0; i < IEEE80211_MLD_MAX_NUM_LINKS; i++) {1122if (removed & BIT(i)) {1123struct ieee80211_bss_conf *link_conf = old[i];11241125err = iwl_mvm_disable_link(mvm, vif, link_conf);1126if (err)1127goto out_err;1128kfree(mvmvif->link[i]);1129mvmvif->link[i] = NULL;1130} else if (added & BIT(i)) {1131struct ieee80211_bss_conf *link_conf;11321133link_conf = link_conf_dereference_protected(vif, i);1134if (WARN_ON(!link_conf))1135continue;11361137if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART,1138&mvm->status))1139mvmvif->link[i] = new_link[i];1140new_link[i] = NULL;1141err = iwl_mvm_add_link(mvm, vif, link_conf);1142if (err)1143goto out_err;1144}1145}11461147err = 0;1148if (new_links == 0) {1149mvmvif->link[0] = &mvmvif->deflink;1150err = iwl_mvm_add_link(mvm, vif, &vif->bss_conf);1151if (err == 0)1152mvmvif->primary_link = 0;1153} else if (!(new_links & BIT(mvmvif->primary_link))) {1154/*1155* Ensure we always have a valid primary_link, the real1156* decision happens later when PHY is activated.1157*/1158mvmvif->primary_link = __ffs(new_links);1159}11601161out_err:1162/* we really don't have a good way to roll back here ... */1163mutex_unlock(&mvm->mutex);11641165free:1166for (i = 0; i < IEEE80211_MLD_MAX_NUM_LINKS; i++)1167kfree(new_link[i]);1168return err;1169}11701171static int1172iwl_mvm_mld_change_sta_links(struct ieee80211_hw *hw,1173struct ieee80211_vif *vif,1174struct ieee80211_sta *sta,1175u16 old_links, u16 new_links)1176{1177struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);11781179guard(mvm)(mvm);1180return iwl_mvm_mld_update_sta_links(mvm, vif, sta, old_links, new_links);1181}11821183bool iwl_mvm_vif_has_esr_cap(struct iwl_mvm *mvm, struct ieee80211_vif *vif)1184{1185const struct wiphy_iftype_ext_capab *ext_capa;11861187lockdep_assert_held(&mvm->mutex);11881189if (!ieee80211_vif_is_mld(vif) || !vif->cfg.assoc ||1190hweight16(ieee80211_vif_usable_links(vif)) == 1)1191return false;11921193if (!(vif->cfg.eml_cap & IEEE80211_EML_CAP_EMLSR_SUPP))1194return false;11951196ext_capa = cfg80211_get_iftype_ext_capa(mvm->hw->wiphy,1197ieee80211_vif_type_p2p(vif));1198return (ext_capa &&1199(ext_capa->eml_capabilities & IEEE80211_EML_CAP_EMLSR_SUPP));1200}12011202static bool iwl_mvm_mld_can_activate_links(struct ieee80211_hw *hw,1203struct ieee80211_vif *vif,1204u16 desired_links)1205{1206struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);1207int n_links = hweight16(desired_links);12081209if (n_links <= 1)1210return true;12111212guard(mvm)(mvm);12131214/* Check if HW supports the wanted number of links */1215if (n_links > iwl_mvm_max_active_links(mvm, vif))1216return false;12171218/* If it is an eSR device, check that we can enter eSR */1219return iwl_mvm_is_esr_supported(mvm->fwrt.trans) &&1220iwl_mvm_vif_has_esr_cap(mvm, vif);1221}12221223static enum ieee80211_neg_ttlm_res1224iwl_mvm_mld_can_neg_ttlm(struct ieee80211_hw *hw, struct ieee80211_vif *vif,1225struct ieee80211_neg_ttlm *neg_ttlm)1226{1227u16 map;1228u8 i;12291230/* Verify all TIDs are mapped to the same links set */1231map = neg_ttlm->downlink[0];1232for (i = 0; i < IEEE80211_TTLM_NUM_TIDS; i++) {1233if (neg_ttlm->downlink[i] != neg_ttlm->uplink[i] ||1234neg_ttlm->uplink[i] != map)1235return NEG_TTLM_RES_REJECT;1236}12371238return NEG_TTLM_RES_ACCEPT;1239}12401241static int1242iwl_mvm_mld_mac_pre_channel_switch(struct ieee80211_hw *hw,1243struct ieee80211_vif *vif,1244struct ieee80211_channel_switch *chsw)1245{1246struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);1247struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);1248int ret;12491250mutex_lock(&mvm->mutex);1251if (mvmvif->esr_active) {1252u8 primary = iwl_mvm_get_primary_link(vif);1253int selected;12541255/* prefer primary unless quiet CSA on it */1256if (chsw->link_id == primary && chsw->block_tx)1257selected = iwl_mvm_get_other_link(vif, primary);1258else1259selected = primary;12601261/*1262* remembers to tell the firmware that this link can't tx1263* Note that this logic seems to be unrelated to esr, but it1264* really is needed only when esr is active. When we have a1265* single link, the firmware will handle all this on its own.1266* In multi-link scenarios, we can learn about the CSA from1267* another link and this logic is too complex for the firmware1268* to track.1269* Since we want to de-activate the link that got a CSA, we1270* need to tell the firmware not to send any frame on that link1271* as the firmware may not be aware that link is under a CSA1272* with mode=1 (no Tx allowed).1273*/1274if (chsw->block_tx && mvmvif->link[chsw->link_id])1275mvmvif->link[chsw->link_id]->csa_block_tx = true;12761277iwl_mvm_exit_esr(mvm, vif, IWL_MVM_ESR_EXIT_CSA, selected);1278mutex_unlock(&mvm->mutex);12791280/*1281* If we've not kept the link active that's doing the CSA1282* then we don't need to do anything else, just return.1283*/1284if (selected != chsw->link_id)1285return 0;12861287mutex_lock(&mvm->mutex);1288}12891290ret = iwl_mvm_pre_channel_switch(mvm, vif, chsw);1291mutex_unlock(&mvm->mutex);12921293return ret;1294}12951296#define IWL_MVM_MLD_UNBLOCK_ESR_NON_BSS_TIMEOUT (5 * HZ)12971298static void iwl_mvm_mld_prep_add_interface(struct ieee80211_hw *hw,1299enum nl80211_iftype type)1300{1301struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);1302struct ieee80211_vif *bss_vif = iwl_mvm_get_bss_vif(mvm);1303struct iwl_mvm_vif *mvmvif;1304int ret;13051306IWL_DEBUG_MAC80211(mvm, "prep_add_interface: type=%u\n",1307type);13081309if (IS_ERR_OR_NULL(bss_vif) ||1310!(type == NL80211_IFTYPE_AP ||1311type == NL80211_IFTYPE_P2P_GO ||1312type == NL80211_IFTYPE_P2P_CLIENT))1313return;13141315mvmvif = iwl_mvm_vif_from_mac80211(bss_vif);1316ret = iwl_mvm_block_esr_sync(mvm, bss_vif,1317IWL_MVM_ESR_BLOCKED_TMP_NON_BSS);1318if (ret)1319return;13201321wiphy_delayed_work_queue(mvmvif->mvm->hw->wiphy,1322&mvmvif->unblock_esr_tmp_non_bss_wk,1323IWL_MVM_MLD_UNBLOCK_ESR_NON_BSS_TIMEOUT);1324}13251326const struct ieee80211_ops iwl_mvm_mld_hw_ops = {1327.tx = iwl_mvm_mac_tx,1328.wake_tx_queue = iwl_mvm_mac_wake_tx_queue,1329.ampdu_action = iwl_mvm_mac_ampdu_action,1330.get_antenna = iwl_mvm_op_get_antenna,1331.set_antenna = iwl_mvm_op_set_antenna,1332.start = iwl_mvm_mac_start,1333.reconfig_complete = iwl_mvm_mac_reconfig_complete,1334.stop = iwl_mvm_mac_stop,1335.add_interface = iwl_mvm_mld_mac_add_interface,1336.remove_interface = iwl_mvm_mld_mac_remove_interface,1337.config = iwl_mvm_mac_config,1338.prepare_multicast = iwl_mvm_prepare_multicast,1339.configure_filter = iwl_mvm_configure_filter,1340.config_iface_filter = iwl_mvm_mld_config_iface_filter,1341.link_info_changed = iwl_mvm_mld_link_info_changed,1342.vif_cfg_changed = iwl_mvm_mld_vif_cfg_changed,1343.hw_scan = iwl_mvm_mac_hw_scan,1344.cancel_hw_scan = iwl_mvm_mac_cancel_hw_scan,1345.sta_pre_rcu_remove = iwl_mvm_sta_pre_rcu_remove,1346.sta_state = iwl_mvm_mld_mac_sta_state,1347.sta_notify = iwl_mvm_mac_sta_notify,1348.allow_buffered_frames = iwl_mvm_mac_allow_buffered_frames,1349.release_buffered_frames = iwl_mvm_mac_release_buffered_frames,1350.set_rts_threshold = iwl_mvm_mac_set_rts_threshold,1351.link_sta_rc_update = iwl_mvm_sta_rc_update,1352.conf_tx = iwl_mvm_mld_mac_conf_tx,1353.mgd_prepare_tx = iwl_mvm_mac_mgd_prepare_tx,1354.mgd_complete_tx = iwl_mvm_mac_mgd_complete_tx,1355.mgd_protect_tdls_discover = iwl_mvm_mac_mgd_protect_tdls_discover,1356.flush = iwl_mvm_mac_flush,1357.flush_sta = iwl_mvm_mac_flush_sta,1358.sched_scan_start = iwl_mvm_mac_sched_scan_start,1359.sched_scan_stop = iwl_mvm_mac_sched_scan_stop,1360.set_key = iwl_mvm_mac_set_key,1361.update_tkip_key = iwl_mvm_mac_update_tkip_key,1362.remain_on_channel = iwl_mvm_mld_roc,1363.cancel_remain_on_channel = iwl_mvm_cancel_roc,1364.add_chanctx = iwl_mvm_add_chanctx,1365.remove_chanctx = iwl_mvm_remove_chanctx,1366.change_chanctx = iwl_mvm_change_chanctx,1367.assign_vif_chanctx = iwl_mvm_mld_assign_vif_chanctx,1368.unassign_vif_chanctx = iwl_mvm_mld_unassign_vif_chanctx,1369.switch_vif_chanctx = iwl_mvm_mld_switch_vif_chanctx,13701371.start_ap = iwl_mvm_mld_start_ap,1372.stop_ap = iwl_mvm_mld_stop_ap,1373.join_ibss = iwl_mvm_mld_start_ibss,1374.leave_ibss = iwl_mvm_mld_stop_ibss,13751376.tx_last_beacon = iwl_mvm_tx_last_beacon,13771378.channel_switch = iwl_mvm_channel_switch,1379.pre_channel_switch = iwl_mvm_mld_mac_pre_channel_switch,1380.post_channel_switch = iwl_mvm_post_channel_switch,1381.abort_channel_switch = iwl_mvm_abort_channel_switch,1382.channel_switch_rx_beacon = iwl_mvm_channel_switch_rx_beacon,13831384.tdls_channel_switch = iwl_mvm_tdls_channel_switch,1385.tdls_cancel_channel_switch = iwl_mvm_tdls_cancel_channel_switch,1386.tdls_recv_channel_switch = iwl_mvm_tdls_recv_channel_switch,13871388.event_callback = iwl_mvm_mac_event_callback,13891390.sync_rx_queues = iwl_mvm_sync_rx_queues,13911392#ifdef CONFIG_PM_SLEEP1393/* look at d3.c */1394.suspend = iwl_mvm_suspend,1395.resume = iwl_mvm_resume,1396.set_wakeup = iwl_mvm_set_wakeup,1397.set_rekey_data = iwl_mvm_set_rekey_data,1398#if IS_ENABLED(CONFIG_IPV6)1399.ipv6_addr_change = iwl_mvm_ipv6_addr_change,1400#endif1401.set_default_unicast_key = iwl_mvm_set_default_unicast_key,1402#endif1403.get_survey = iwl_mvm_mac_get_survey,1404.sta_statistics = iwl_mvm_mac_sta_statistics,1405.get_ftm_responder_stats = iwl_mvm_mac_get_ftm_responder_stats,1406.start_pmsr = iwl_mvm_start_pmsr,1407.abort_pmsr = iwl_mvm_abort_pmsr,14081409#ifdef CONFIG_IWLWIFI_DEBUGFS1410.vif_add_debugfs = iwl_mvm_vif_add_debugfs,1411.link_add_debugfs = iwl_mvm_link_add_debugfs,1412.link_sta_add_debugfs = iwl_mvm_link_sta_add_debugfs,1413#endif1414.set_hw_timestamp = iwl_mvm_set_hw_timestamp,14151416.change_vif_links = iwl_mvm_mld_change_vif_links,1417.change_sta_links = iwl_mvm_mld_change_sta_links,1418.can_activate_links = iwl_mvm_mld_can_activate_links,1419.can_neg_ttlm = iwl_mvm_mld_can_neg_ttlm,1420.prep_add_interface = iwl_mvm_mld_prep_add_interface,1421};142214231424