File Index
Files and directories
Sign in
FILE

mld-mac80211.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c C
   1// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
   2/*
   3 * Copyright (C) 2022-2025 Intel Corporation
   4 */
   5#include "mvm.h"
   6
   7static int iwl_mvm_mld_mac_add_interface(struct ieee80211_hw *hw,
   8					 struct ieee80211_vif *vif)
   9{
  10	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
  11	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
  12	int ret;
  13	int i;
  14
  15	guard(mvm)(mvm);
  16
  17	iwl_mvm_mac_init_mvmvif(mvm, mvmvif);
  18
  19	mvmvif->mvm = mvm;
  20
  21	vif->driver_flags |= IEEE80211_VIF_REMOVE_AP_AFTER_DISASSOC;
  22
  23	/* Not much to do here. The stack will not allow interface
  24	 * types or combinations that we didn't advertise, so we
  25	 * don't really have to check the types.
  26	 */
  27
  28	/* make sure that beacon statistics don't go backwards with FW reset */
  29	if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))
  30		for_each_mvm_vif_valid_link(mvmvif, i)
  31			mvmvif->link[i]->beacon_stats.accu_num_beacons +=
  32				mvmvif->link[i]->beacon_stats.num_beacons;
  33
  34	/* Allocate resources for the MAC context, and add it to the fw  */
  35	ret = iwl_mvm_mac_ctxt_init(mvm, vif);
  36	if (ret)
  37		return ret;
  38
  39	rcu_assign_pointer(mvm->vif_id_to_mac[mvmvif->id], vif);
  40
  41	mvmvif->features |= hw->netdev_features;
  42
  43	/* reset deflink MLO parameters */
  44	mvmvif->deflink.fw_link_id = IWL_MVM_FW_LINK_ID_INVALID;
  45	mvmvif->deflink.active = 0;
  46
  47	ret = iwl_mvm_mld_mac_ctxt_add(mvm, vif);
  48	if (ret)
  49		return ret;
  50
  51	/* beacon filtering */
  52	ret = iwl_mvm_disable_beacon_filter(mvm, vif);
  53	if (ret)
  54		goto out_remove_mac;
  55
  56	if (!mvm->bf_allowed_vif &&
  57	    vif->type == NL80211_IFTYPE_STATION && !vif->p2p) {
  58		mvm->bf_allowed_vif = mvmvif;
  59		vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER |
  60				     IEEE80211_VIF_SUPPORTS_CQM_RSSI;
  61	}
  62
  63	/* We want link[0] to point to the default link, unless we have MLO and
  64	 * in this case this will be modified later by .change_vif_links()
  65	 * If we are in the restart flow with an MLD connection, we will wait
  66	 * to .change_vif_links() to setup the links.
  67	 */
  68	if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) ||
  69	    !ieee80211_vif_is_mld(vif)) {
  70		mvmvif->link[0] = &mvmvif->deflink;
  71
  72		ret = iwl_mvm_add_link(mvm, vif, &vif->bss_conf);
  73		if (ret)
  74			goto out_free_bf;
  75	}
  76
  77	/* Save a pointer to p2p device vif, so it can later be used to
  78	 * update the p2p device MAC when a GO is started/stopped
  79	 */
  80	if (vif->type == NL80211_IFTYPE_P2P_DEVICE)
  81		mvm->p2p_device_vif = vif;
  82
  83	ret = iwl_mvm_power_update_mac(mvm);
  84	if (ret)
  85		goto out_free_bf;
  86
  87	iwl_mvm_tcm_add_vif(mvm, vif);
  88
  89	if (vif->type == NL80211_IFTYPE_MONITOR) {
  90		mvm->monitor_on = true;
  91		ieee80211_hw_set(mvm->hw, RX_INCLUDES_FCS);
  92	}
  93
  94	if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))
  95		iwl_mvm_vif_dbgfs_add_link(mvm, vif);
  96
  97	if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) &&
  98	    vif->type == NL80211_IFTYPE_STATION && !vif->p2p &&
  99	    !mvm->csme_vif && mvm->mei_registered) {
 100		iwl_mei_set_nic_info(vif->addr, mvm->nvm_data->hw_addr);
 101		iwl_mei_set_netdev(ieee80211_vif_to_wdev(vif)->netdev);
 102		mvm->csme_vif = vif;
 103	}
 104
 105	return 0;
 106
 107 out_free_bf:
 108	if (mvm->bf_allowed_vif == mvmvif) {
 109		mvm->bf_allowed_vif = NULL;
 110		vif->driver_flags &= ~(IEEE80211_VIF_BEACON_FILTER |
 111				       IEEE80211_VIF_SUPPORTS_CQM_RSSI);
 112	}
 113 out_remove_mac:
 114	mvmvif->link[0] = NULL;
 115	iwl_mvm_mld_mac_ctxt_remove(mvm, vif);
 116	return ret;
 117}
 118
 119static void iwl_mvm_mld_mac_remove_interface(struct ieee80211_hw *hw,
 120					     struct ieee80211_vif *vif)
 121{
 122	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
 123	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
 124	struct iwl_probe_resp_data *probe_data;
 125
 126	iwl_mvm_prepare_mac_removal(mvm, vif);
 127
 128	if (!(vif->type == NL80211_IFTYPE_AP ||
 129	      vif->type == NL80211_IFTYPE_ADHOC))
 130		iwl_mvm_tcm_rm_vif(mvm, vif);
 131
 132	guard(mvm)(mvm);
 133
 134	if (vif == mvm->csme_vif) {
 135		iwl_mei_set_netdev(NULL);
 136		mvm->csme_vif = NULL;
 137	}
 138
 139	if (mvm->bf_allowed_vif == mvmvif) {
 140		mvm->bf_allowed_vif = NULL;
 141		vif->driver_flags &= ~(IEEE80211_VIF_BEACON_FILTER |
 142				       IEEE80211_VIF_SUPPORTS_CQM_RSSI);
 143	}
 144
 145	if (vif->bss_conf.ftm_responder)
 146		memset(&mvm->ftm_resp_stats, 0, sizeof(mvm->ftm_resp_stats));
 147
 148	iwl_mvm_vif_dbgfs_rm_link(mvm, vif);
 149
 150	iwl_mvm_power_update_mac(mvm);
 151
 152	/* Before the interface removal, mac80211 would cancel the ROC, and the
 153	 * ROC worker would be scheduled if needed. The worker would be flushed
 154	 * in iwl_mvm_prepare_mac_removal() and thus at this point the link is
 155	 * not active. So need only to remove the link.
 156	 */
 157	if (vif->type == NL80211_IFTYPE_P2P_DEVICE) {
 158		if (mvmvif->deflink.phy_ctxt) {
 159			iwl_mvm_phy_ctxt_unref(mvm, mvmvif->deflink.phy_ctxt);
 160			mvmvif->deflink.phy_ctxt = NULL;
 161		}
 162		mvm->p2p_device_vif = NULL;
 163		iwl_mvm_remove_link(mvm, vif, &vif->bss_conf);
 164	} else {
 165		iwl_mvm_disable_link(mvm, vif, &vif->bss_conf);
 166	}
 167
 168	iwl_mvm_mld_mac_ctxt_remove(mvm, vif);
 169
 170	RCU_INIT_POINTER(mvm->vif_id_to_mac[mvmvif->id], NULL);
 171
 172	probe_data = rcu_dereference_protected(mvmvif->deflink.probe_resp_data,
 173					       lockdep_is_held(&mvm->mutex));
 174	RCU_INIT_POINTER(mvmvif->deflink.probe_resp_data, NULL);
 175	if (probe_data)
 176		kfree_rcu(probe_data, rcu_head);
 177
 178	if (vif->type == NL80211_IFTYPE_MONITOR) {
 179		mvm->monitor_on = false;
 180		__clear_bit(IEEE80211_HW_RX_INCLUDES_FCS, mvm->hw->flags);
 181	}
 182}
 183
 184static unsigned int iwl_mvm_mld_count_active_links(struct iwl_mvm_vif *mvmvif)
 185{
 186	unsigned int n_active = 0;
 187	int i;
 188
 189	for (i = 0; i < IEEE80211_MLD_MAX_NUM_LINKS; i++) {
 190		if (mvmvif->link[i] && mvmvif->link[i]->phy_ctxt)
 191			n_active++;
 192	}
 193
 194	return n_active;
 195}
 196
 197static int iwl_mvm_esr_mode_active(struct iwl_mvm *mvm,
 198				   struct ieee80211_vif *vif)
 199{
 200	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
 201	int link_id, ret = 0;
 202
 203	mvmvif->esr_active = true;
 204
 205	/* Indicate to mac80211 that EML is enabled */
 206	vif->driver_flags |= IEEE80211_VIF_EML_ACTIVE;
 207
 208	iwl_mvm_update_smps_on_active_links(mvm, vif, IWL_MVM_SMPS_REQ_FW,
 209					    IEEE80211_SMPS_OFF);
 210
 211	for_each_mvm_vif_valid_link(mvmvif, link_id) {
 212		struct iwl_mvm_vif_link_info *link = mvmvif->link[link_id];
 213
 214		if (!link->phy_ctxt)
 215			continue;
 216
 217		ret = iwl_mvm_phy_send_rlc(mvm, link->phy_ctxt, 2, 2);
 218		if (ret)
 219			break;
 220
 221		link->phy_ctxt->rlc_disabled = true;
 222	}
 223
 224	if (vif->active_links == mvmvif->link_selection_res &&
 225	    !WARN_ON(!(vif->active_links & BIT(mvmvif->link_selection_primary))))
 226		mvmvif->primary_link = mvmvif->link_selection_primary;
 227	else
 228		mvmvif->primary_link = __ffs(vif->active_links);
 229
 230	iwl_dbg_tlv_time_point(&mvm->fwrt, IWL_FW_INI_TIME_ESR_LINK_UP,
 231			       NULL);
 232
 233	return ret;
 234}
 235
 236static int
 237__iwl_mvm_mld_assign_vif_chanctx(struct iwl_mvm *mvm,
 238				 struct ieee80211_vif *vif,
 239				 struct ieee80211_bss_conf *link_conf,
 240				 struct ieee80211_chanctx_conf *ctx,
 241				 bool switching_chanctx)
 242{
 243	u16 *phy_ctxt_id = (u16 *)ctx->drv_priv;
 244	struct iwl_mvm_phy_ctxt *phy_ctxt = &mvm->phy_ctxts[*phy_ctxt_id];
 245	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
 246	unsigned int n_active = iwl_mvm_mld_count_active_links(mvmvif);
 247	unsigned int link_id = link_conf->link_id;
 248	int ret;
 249
 250	if (WARN_ON_ONCE(!mvmvif->link[link_id]))
 251		return -EINVAL;
 252
 253	/* if the assigned one was not counted yet, count it now */
 254	if (!mvmvif->link[link_id]->phy_ctxt)
 255		n_active++;
 256
 257	/* mac parameters such as HE support can change at this stage
 258	 * For sta, need first to configure correct state from drv_sta_state
 259	 * and only after that update mac config.
 260	 */
 261	if (vif->type == NL80211_IFTYPE_AP) {
 262		ret = iwl_mvm_mld_mac_ctxt_changed(mvm, vif, false);
 263		if (ret) {
 264			IWL_ERR(mvm, "failed to update MAC %pM\n", vif->addr);
 265			return -EINVAL;
 266		}
 267	}
 268
 269	mvmvif->link[link_id]->phy_ctxt = phy_ctxt;
 270
 271	if (iwl_mvm_is_esr_supported(mvm->fwrt.trans) && n_active > 1) {
 272		mvmvif->link[link_id]->listen_lmac = true;
 273		ret = iwl_mvm_esr_mode_active(mvm, vif);
 274		if (ret) {
 275			IWL_ERR(mvm, "failed to activate ESR mode (%d)\n", ret);
 276			goto out;
 277		}
 278	}
 279
 280	if (switching_chanctx) {
 281		/* reactivate if we turned this off during channel switch */
 282		if (vif->type == NL80211_IFTYPE_AP)
 283			mvmvif->ap_ibss_active = true;
 284	}
 285
 286	/* send it first with phy context ID */
 287	ret = iwl_mvm_link_changed(mvm, vif, link_conf, 0, false);
 288	if (ret)
 289		goto out;
 290
 291	/*
 292	 * if link switching (link not active yet) we'll activate it in
 293	 * firmware later on link-info change, which mac80211 guarantees
 294	 * for link switch after the stations are set up
 295	 */
 296	if (ieee80211_vif_link_active(vif, link_conf->link_id)) {
 297		ret = iwl_mvm_link_changed(mvm, vif, link_conf,
 298					   LINK_CONTEXT_MODIFY_ACTIVE |
 299					   LINK_CONTEXT_MODIFY_RATES_INFO,
 300					   true);
 301		if (ret)
 302			goto out;
 303	}
 304
 305	if (vif->type == NL80211_IFTYPE_STATION)
 306		iwl_mvm_send_ap_tx_power_constraint_cmd(mvm, vif,
 307							link_conf,
 308							false);
 309
 310	/*
 311	 * Power state must be updated before quotas,
 312	 * otherwise fw will complain.
 313	 */
 314	iwl_mvm_power_update_mac(mvm);
 315
 316	if (vif->type == NL80211_IFTYPE_MONITOR) {
 317		ret = iwl_mvm_mld_add_snif_sta(mvm, vif, link_conf);
 318		if (ret)
 319			goto deactivate;
 320	}
 321
 322	return 0;
 323
 324deactivate:
 325	iwl_mvm_link_changed(mvm, vif, link_conf, LINK_CONTEXT_MODIFY_ACTIVE,
 326			     false);
 327out:
 328	mvmvif->link[link_id]->phy_ctxt = NULL;
 329	iwl_mvm_power_update_mac(mvm);
 330	return ret;
 331}
 332
 333static int iwl_mvm_mld_assign_vif_chanctx(struct ieee80211_hw *hw,
 334					  struct ieee80211_vif *vif,
 335					  struct ieee80211_bss_conf *link_conf,
 336					  struct ieee80211_chanctx_conf *ctx)
 337{
 338	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
 339
 340	guard(mvm)(mvm);
 341	return __iwl_mvm_mld_assign_vif_chanctx(mvm, vif, link_conf, ctx, false);
 342}
 343
 344static int iwl_mvm_esr_mode_inactive(struct iwl_mvm *mvm,
 345				     struct ieee80211_vif *vif)
 346{
 347	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
 348	struct ieee80211_bss_conf *link_conf;
 349	int link_id, ret = 0;
 350
 351	mvmvif->esr_active = false;
 352
 353	vif->driver_flags &= ~IEEE80211_VIF_EML_ACTIVE;
 354
 355	iwl_mvm_update_smps_on_active_links(mvm, vif, IWL_MVM_SMPS_REQ_FW,
 356					    IEEE80211_SMPS_AUTOMATIC);
 357
 358	for_each_vif_active_link(vif, link_conf, link_id) {
 359		struct ieee80211_chanctx_conf *chanctx_conf;
 360		struct iwl_mvm_phy_ctxt *phy_ctxt;
 361		u8 static_chains, dynamic_chains;
 362
 363		mvmvif->link[link_id]->listen_lmac = false;
 364
 365		rcu_read_lock();
 366
 367		chanctx_conf = rcu_dereference(link_conf->chanctx_conf);
 368		phy_ctxt = mvmvif->link[link_id]->phy_ctxt;
 369
 370		if (!chanctx_conf || !phy_ctxt) {
 371			rcu_read_unlock();
 372			continue;
 373		}
 374
 375		phy_ctxt->rlc_disabled = false;
 376		static_chains = chanctx_conf->rx_chains_static;
 377		dynamic_chains = chanctx_conf->rx_chains_dynamic;
 378
 379		rcu_read_unlock();
 380
 381		ret = iwl_mvm_phy_send_rlc(mvm, phy_ctxt, static_chains,
 382					   dynamic_chains);
 383		if (ret)
 384			break;
 385	}
 386
 387	iwl_dbg_tlv_time_point(&mvm->fwrt, IWL_FW_INI_TIME_ESR_LINK_DOWN,
 388			       NULL);
 389
 390	return ret;
 391}
 392
 393static void
 394__iwl_mvm_mld_unassign_vif_chanctx(struct iwl_mvm *mvm,
 395				   struct ieee80211_vif *vif,
 396				   struct ieee80211_bss_conf *link_conf,
 397				   struct ieee80211_chanctx_conf *ctx,
 398				   bool switching_chanctx)
 399
 400{
 401	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
 402	unsigned int n_active = iwl_mvm_mld_count_active_links(mvmvif);
 403	unsigned int link_id = link_conf->link_id;
 404
 405	/* shouldn't happen, but verify link_id is valid before accessing */
 406	if (WARN_ON_ONCE(!mvmvif->link[link_id]))
 407		return;
 408
 409	if (vif->type == NL80211_IFTYPE_AP && switching_chanctx) {
 410		mvmvif->csa_countdown = false;
 411
 412		/* Set CS bit on all the stations */
 413		iwl_mvm_modify_all_sta_disable_tx(mvm, mvmvif, true);
 414
 415		/* Save blocked iface, the timeout is set on the next beacon */
 416		rcu_assign_pointer(mvm->csa_tx_blocked_vif, vif);
 417
 418		mvmvif->ap_ibss_active = false;
 419	}
 420
 421	iwl_mvm_link_changed(mvm, vif, link_conf,
 422			     LINK_CONTEXT_MODIFY_ACTIVE, false);
 423
 424	if (iwl_mvm_is_esr_supported(mvm->fwrt.trans) && n_active > 1) {
 425		int ret = iwl_mvm_esr_mode_inactive(mvm, vif);
 426
 427		if (ret)
 428			IWL_ERR(mvm, "failed to deactivate ESR mode (%d)\n",
 429				ret);
 430	}
 431
 432	if (vif->type == NL80211_IFTYPE_MONITOR)
 433		iwl_mvm_mld_rm_snif_sta(mvm, vif);
 434
 435	if (switching_chanctx)
 436		return;
 437	mvmvif->link[link_id]->phy_ctxt = NULL;
 438	iwl_mvm_power_update_mac(mvm);
 439}
 440
 441static void iwl_mvm_mld_unassign_vif_chanctx(struct ieee80211_hw *hw,
 442					     struct ieee80211_vif *vif,
 443					     struct ieee80211_bss_conf *link_conf,
 444					     struct ieee80211_chanctx_conf *ctx)
 445{
 446	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
 447	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
 448
 449	mutex_lock(&mvm->mutex);
 450	__iwl_mvm_mld_unassign_vif_chanctx(mvm, vif, link_conf, ctx, false);
 451	/* in the non-MLD case, remove/re-add the link to clean up FW state */
 452	if (!ieee80211_vif_is_mld(vif) && !mvmvif->ap_sta &&
 453	    !WARN_ON_ONCE(vif->cfg.assoc)) {
 454		iwl_mvm_remove_link(mvm, vif, link_conf);
 455		iwl_mvm_add_link(mvm, vif, link_conf);
 456	}
 457	mutex_unlock(&mvm->mutex);
 458}
 459
 460static void
 461iwl_mvm_tpe_sta_cmd_data(struct iwl_txpower_constraints_cmd *cmd,
 462			 const struct ieee80211_bss_conf *bss_info)
 463{
 464	u8 i;
 465
 466	/*
 467	 * NOTE: the 0 here is IEEE80211_TPE_CAT_6GHZ_DEFAULT,
 468	 * we fully ignore IEEE80211_TPE_CAT_6GHZ_SUBORDINATE
 469	 */
 470
 471	BUILD_BUG_ON(ARRAY_SIZE(cmd->psd_pwr) !=
 472		     ARRAY_SIZE(bss_info->tpe.psd_local[0].power));
 473
 474	/* if not valid, mac80211 puts default (max value) */
 475	for (i = 0; i < ARRAY_SIZE(cmd->psd_pwr); i++)
 476		cmd->psd_pwr[i] = min(bss_info->tpe.psd_local[0].power[i],
 477				      bss_info->tpe.psd_reg_client[0].power[i]);
 478
 479	BUILD_BUG_ON(ARRAY_SIZE(cmd->eirp_pwr) !=
 480		     ARRAY_SIZE(bss_info->tpe.max_local[0].power));
 481
 482	for (i = 0; i < ARRAY_SIZE(cmd->eirp_pwr); i++)
 483		cmd->eirp_pwr[i] = min(bss_info->tpe.max_local[0].power[i],
 484				       bss_info->tpe.max_reg_client[0].power[i]);
 485}
 486
 487void
 488iwl_mvm_send_ap_tx_power_constraint_cmd(struct iwl_mvm *mvm,
 489					struct ieee80211_vif *vif,
 490					struct ieee80211_bss_conf *bss_conf,
 491					bool is_ap)
 492{
 493	struct iwl_txpower_constraints_cmd cmd = {};
 494	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
 495	struct iwl_mvm_vif_link_info *link_info =
 496			mvmvif->link[bss_conf->link_id];
 497	u32 cmd_id = WIDE_ID(PHY_OPS_GROUP, AP_TX_POWER_CONSTRAINTS_CMD);
 498	u32 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, cmd_id,
 499					    IWL_FW_CMD_VER_UNKNOWN);
 500	int ret;
 501
 502	lockdep_assert_held(&mvm->mutex);
 503
 504	if (cmd_ver == IWL_FW_CMD_VER_UNKNOWN)
 505		return;
 506
 507	if (!link_info->active ||
 508	    link_info->fw_link_id == IWL_MVM_FW_LINK_ID_INVALID)
 509		return;
 510
 511	if (bss_conf->chanreq.oper.chan->band != NL80211_BAND_6GHZ)
 512		return;
 513
 514	cmd.link_id = cpu_to_le16(link_info->fw_link_id);
 515	memset(cmd.psd_pwr, DEFAULT_TPE_TX_POWER, sizeof(cmd.psd_pwr));
 516	memset(cmd.eirp_pwr, DEFAULT_TPE_TX_POWER, sizeof(cmd.eirp_pwr));
 517
 518	if (is_ap) {
 519		cmd.ap_type = cpu_to_le16(IWL_6GHZ_AP_TYPE_VLP);
 520	} else if (bss_conf->power_type == IEEE80211_REG_UNSET_AP) {
 521		return;
 522	} else {
 523		cmd.ap_type = cpu_to_le16(bss_conf->power_type - 1);
 524		iwl_mvm_tpe_sta_cmd_data(&cmd, bss_conf);
 525	}
 526
 527	ret = iwl_mvm_send_cmd_pdu(mvm,
 528				   WIDE_ID(PHY_OPS_GROUP,
 529					   AP_TX_POWER_CONSTRAINTS_CMD),
 530				   0, sizeof(cmd), &cmd);
 531	if (ret)
 532		IWL_ERR(mvm,
 533			"failed to send AP_TX_POWER_CONSTRAINTS_CMD (%d)\n",
 534			ret);
 535}
 536
 537static int iwl_mvm_mld_start_ap_ibss(struct ieee80211_hw *hw,
 538				     struct ieee80211_vif *vif,
 539				     struct ieee80211_bss_conf *link_conf)
 540{
 541	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
 542	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
 543	int ret;
 544
 545	guard(mvm)(mvm);
 546
 547	if (vif->type == NL80211_IFTYPE_AP)
 548		iwl_mvm_send_ap_tx_power_constraint_cmd(mvm, vif,
 549							link_conf, true);
 550
 551	/* Send the beacon template */
 552	ret = iwl_mvm_mac_ctxt_beacon_changed(mvm, vif, link_conf);
 553	if (ret)
 554		return ret;
 555
 556	/* the link should be already activated when assigning chan context */
 557	ret = iwl_mvm_link_changed(mvm, vif, link_conf,
 558				   LINK_CONTEXT_MODIFY_ALL &
 559				   ~LINK_CONTEXT_MODIFY_ACTIVE,
 560				   true);
 561	if (ret)
 562		return ret;
 563
 564	ret = iwl_mvm_mld_add_mcast_sta(mvm, vif, link_conf);
 565	if (ret)
 566		return ret;
 567
 568	/* Send the bcast station. At this stage the TBTT and DTIM time
 569	 * events are added and applied to the scheduler
 570	 */
 571	ret = iwl_mvm_mld_add_bcast_sta(mvm, vif, link_conf);
 572	if (ret)
 573		goto out_rm_mcast;
 574
 575	if (iwl_mvm_start_ap_ibss_common(hw, vif, &ret))
 576		goto out_failed;
 577
 578	/* Need to update the P2P Device MAC (only GO, IBSS is single vif) */
 579	if (vif->p2p && mvm->p2p_device_vif)
 580		iwl_mvm_mld_mac_ctxt_changed(mvm, mvm->p2p_device_vif, false);
 581
 582	iwl_mvm_bt_coex_vif_change(mvm);
 583
 584	/* we don't support TDLS during DCM */
 585	if (iwl_mvm_phy_ctx_count(mvm) > 1)
 586		iwl_mvm_teardown_tdls_peers(mvm);
 587
 588	iwl_mvm_ftm_restart_responder(mvm, vif, link_conf);
 589
 590	return 0;
 591
 592out_failed:
 593	iwl_mvm_power_update_mac(mvm);
 594	mvmvif->ap_ibss_active = false;
 595	iwl_mvm_mld_rm_bcast_sta(mvm, vif, link_conf);
 596out_rm_mcast:
 597	iwl_mvm_mld_rm_mcast_sta(mvm, vif, link_conf);
 598	return ret;
 599}
 600
 601static int iwl_mvm_mld_start_ap(struct ieee80211_hw *hw,
 602				struct ieee80211_vif *vif,
 603				struct ieee80211_bss_conf *link_conf)
 604{
 605	return iwl_mvm_mld_start_ap_ibss(hw, vif, link_conf);
 606}
 607
 608static int iwl_mvm_mld_start_ibss(struct ieee80211_hw *hw,
 609				  struct ieee80211_vif *vif)
 610{
 611	return iwl_mvm_mld_start_ap_ibss(hw, vif, &vif->bss_conf);
 612}
 613
 614static void iwl_mvm_mld_stop_ap_ibss(struct ieee80211_hw *hw,
 615				     struct ieee80211_vif *vif,
 616				     struct ieee80211_bss_conf *link_conf)
 617{
 618	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
 619
 620	guard(mvm)(mvm);
 621
 622	iwl_mvm_stop_ap_ibss_common(mvm, vif);
 623
 624	/* Need to update the P2P Device MAC (only GO, IBSS is single vif) */
 625	if (vif->p2p && mvm->p2p_device_vif)
 626		iwl_mvm_mld_mac_ctxt_changed(mvm, mvm->p2p_device_vif, false);
 627
 628	iwl_mvm_ftm_responder_clear(mvm, vif);
 629
 630	iwl_mvm_mld_rm_bcast_sta(mvm, vif, link_conf);
 631	iwl_mvm_mld_rm_mcast_sta(mvm, vif, link_conf);
 632
 633	iwl_mvm_power_update_mac(mvm);
 634}
 635
 636static void iwl_mvm_mld_stop_ap(struct ieee80211_hw *hw,
 637				struct ieee80211_vif *vif,
 638				struct ieee80211_bss_conf *link_conf)
 639{
 640	iwl_mvm_mld_stop_ap_ibss(hw, vif, link_conf);
 641}
 642
 643static void iwl_mvm_mld_stop_ibss(struct ieee80211_hw *hw,
 644				  struct ieee80211_vif *vif)
 645{
 646	iwl_mvm_mld_stop_ap_ibss(hw, vif, &vif->bss_conf);
 647}
 648
 649static int iwl_mvm_mld_mac_sta_state(struct ieee80211_hw *hw,
 650				     struct ieee80211_vif *vif,
 651				     struct ieee80211_sta *sta,
 652				     enum ieee80211_sta_state old_state,
 653				     enum ieee80211_sta_state new_state)
 654{
 655	static const struct iwl_mvm_sta_state_ops callbacks = {
 656		.add_sta = iwl_mvm_mld_add_sta,
 657		.update_sta = iwl_mvm_mld_update_sta,
 658		.rm_sta = iwl_mvm_mld_rm_sta,
 659		.mac_ctxt_changed = iwl_mvm_mld_mac_ctxt_changed,
 660	};
 661
 662	return iwl_mvm_mac_sta_state_common(hw, vif, sta, old_state, new_state,
 663					    &callbacks);
 664}
 665
 666static void
 667iwl_mvm_mld_link_info_changed_station(struct iwl_mvm *mvm,
 668				      struct ieee80211_vif *vif,
 669				      struct ieee80211_bss_conf *link_conf,
 670				      u64 changes)
 671{
 672	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
 673	bool has_he, has_eht;
 674	u32 link_changes = 0;
 675	int ret;
 676
 677	if (WARN_ON_ONCE(!mvmvif->link[link_conf->link_id]))
 678		return;
 679
 680	/* not yet marked active in vif means during link switch */
 681	if (!ieee80211_vif_link_active(vif, link_conf->link_id) &&
 682	    vif->cfg.assoc && mvmvif->link[link_conf->link_id]->phy_ctxt)
 683		link_changes |= LINK_CONTEXT_MODIFY_ACTIVE;
 684
 685	has_he = link_conf->he_support && !iwlwifi_mod_params.disable_11ax;
 686	has_eht = link_conf->eht_support && !iwlwifi_mod_params.disable_11be;
 687
 688	/* Update EDCA params */
 689	if (changes & BSS_CHANGED_QOS && vif->cfg.assoc && link_conf->qos)
 690		link_changes |= LINK_CONTEXT_MODIFY_QOS_PARAMS;
 691
 692	if (changes & BSS_CHANGED_ERP_SLOT)
 693		link_changes |= LINK_CONTEXT_MODIFY_RATES_INFO;
 694
 695	if (vif->cfg.assoc && (has_he || has_eht)) {
 696		IWL_DEBUG_MAC80211(mvm, "Associated in HE mode\n");
 697		link_changes |= LINK_CONTEXT_MODIFY_HE_PARAMS;
 698	}
 699
 700	/* if associated, maybe puncturing changed - we'll check later */
 701	if (vif->cfg.assoc)
 702		link_changes |= LINK_CONTEXT_MODIFY_EHT_PARAMS;
 703
 704	if (link_changes) {
 705		ret = iwl_mvm_link_changed(mvm, vif, link_conf, link_changes,
 706					   true);
 707		if (ret)
 708			IWL_ERR(mvm, "failed to update link\n");
 709	}
 710
 711	ret = iwl_mvm_mld_mac_ctxt_changed(mvm, vif, false);
 712	if (ret)
 713		IWL_ERR(mvm, "failed to update MAC %pM\n", vif->addr);
 714
 715	memcpy(mvmvif->link[link_conf->link_id]->bssid, link_conf->bssid,
 716	       ETH_ALEN);
 717
 718	iwl_mvm_bss_info_changed_station_common(mvm, vif, link_conf, changes);
 719}
 720
 721static bool iwl_mvm_mld_vif_have_valid_ap_sta(struct iwl_mvm_vif *mvmvif)
 722{
 723	int i;
 724
 725	for_each_mvm_vif_valid_link(mvmvif, i) {
 726		if (mvmvif->link[i]->ap_sta_id != IWL_INVALID_STA)
 727			return true;
 728	}
 729
 730	return false;
 731}
 732
 733static void iwl_mvm_mld_vif_cfg_changed_station(struct iwl_mvm *mvm,
 734						struct ieee80211_vif *vif,
 735						u64 changes)
 736{
 737	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
 738	struct ieee80211_bss_conf *link_conf;
 739	bool protect = false;
 740	unsigned int i;
 741	int ret;
 742
 743	/* This might get called without active links during the
 744	 * chanctx switch, but we don't care about it anyway.
 745	 */
 746	if (changes == BSS_CHANGED_IDLE)
 747		return;
 748
 749	ret = iwl_mvm_mld_mac_ctxt_changed(mvm, vif, false);
 750	if (ret)
 751		IWL_ERR(mvm, "failed to update MAC %pM\n", vif->addr);
 752
 753	mvmvif->associated = vif->cfg.assoc;
 754
 755	if (changes & BSS_CHANGED_ASSOC) {
 756		if (vif->cfg.assoc) {
 757			mvmvif->session_prot_connection_loss = false;
 758
 759			/*
 760			 * Clear statistics to get clean beacon counter, and ask for
 761			 * periodic statistics, as they are needed for link
 762			 * selection and RX OMI decisions.
 763			 */
 764			iwl_mvm_request_statistics(mvm, true);
 765			iwl_mvm_request_periodic_system_statistics(mvm, true);
 766			iwl_mvm_sf_update(mvm, vif, false);
 767			iwl_mvm_power_vif_assoc(mvm, vif);
 768
 769			for_each_mvm_vif_valid_link(mvmvif, i) {
 770				memset(&mvmvif->link[i]->beacon_stats, 0,
 771				       sizeof(mvmvif->link[i]->beacon_stats));
 772
 773				if (vif->p2p) {
 774					iwl_mvm_update_smps(mvm, vif,
 775							    IWL_MVM_SMPS_REQ_PROT,
 776							    IEEE80211_SMPS_DYNAMIC, i);
 777				}
 778
 779				rcu_read_lock();
 780				link_conf = rcu_dereference(vif->link_conf[i]);
 781				if (link_conf && !link_conf->dtim_period)
 782					protect = true;
 783				rcu_read_unlock();
 784			}
 785
 786			if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) &&
 787			    protect) {
 788				/* We are in assoc so only one link is active-
 789				 * The association link
 790				 */
 791				unsigned int link_id =
 792					ffs(vif->active_links) - 1;
 793
 794				/* If we're not restarting and still haven't
 795				 * heard a beacon (dtim period unknown) then
 796				 * make sure we still have enough minimum time
 797				 * remaining in the time event, since the auth
 798				 * might actually have taken quite a while
 799				 * (especially for SAE) and so the remaining
 800				 * time could be small without us having heard
 801				 * a beacon yet.
 802				 */
 803				iwl_mvm_protect_assoc(mvm, vif, 0, link_id);
 804			}
 805
 806			iwl_mvm_sf_update(mvm, vif, false);
 807
 808			/* FIXME: need to decide about misbehaving AP handling */
 809			iwl_mvm_power_vif_assoc(mvm, vif);
 810		} else if (iwl_mvm_mld_vif_have_valid_ap_sta(mvmvif)) {
 811			iwl_mvm_mei_host_disassociated(mvm);
 812
 813			iwl_mvm_request_periodic_system_statistics(mvm, false);
 814
 815			/* If update fails - SF might be running in associated
 816			 * mode while disassociated - which is forbidden.
 817			 */
 818			ret = iwl_mvm_sf_update(mvm, vif, false);
 819			WARN_ONCE(ret &&
 820				  !test_bit(IWL_MVM_STATUS_HW_RESTART_REQUESTED,
 821					    &mvm->status),
 822				  "Failed to update SF upon disassociation\n");
 823		}
 824
 825		iwl_mvm_bss_info_changed_station_assoc(mvm, vif, changes);
 826	}
 827
 828	if (changes & BSS_CHANGED_PS) {
 829		iwl_mvm_smps_workaround(mvm, vif, false);
 830		ret = iwl_mvm_power_update_mac(mvm);
 831		if (ret)
 832			IWL_ERR(mvm, "failed to update power mode\n");
 833	}
 834}
 835
 836static void
 837iwl_mvm_mld_link_info_changed_ap_ibss(struct iwl_mvm *mvm,
 838				      struct ieee80211_vif *vif,
 839				      struct ieee80211_bss_conf *link_conf,
 840				      u64 changes)
 841{
 842	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
 843	u32 link_changes = LINK_CONTEXT_MODIFY_PROTECT_FLAGS |
 844			   LINK_CONTEXT_MODIFY_QOS_PARAMS;
 845
 846	/* Changes will be applied when the AP/IBSS is started */
 847	if (!mvmvif->ap_ibss_active)
 848		return;
 849
 850	if (link_conf->he_support)
 851		link_changes |= LINK_CONTEXT_MODIFY_HE_PARAMS;
 852
 853	if (changes & BSS_CHANGED_ERP_SLOT)
 854		link_changes |= LINK_CONTEXT_MODIFY_RATES_INFO;
 855
 856	if (changes & (BSS_CHANGED_ERP_CTS_PROT | BSS_CHANGED_ERP_SLOT |
 857		       BSS_CHANGED_HT |
 858		       BSS_CHANGED_BANDWIDTH | BSS_CHANGED_QOS |
 859		       BSS_CHANGED_HE_BSS_COLOR) &&
 860		       iwl_mvm_link_changed(mvm, vif, link_conf,
 861					    link_changes, true))
 862		IWL_ERR(mvm, "failed to update MAC %pM\n", vif->addr);
 863
 864	/* Need to send a new beacon template to the FW */
 865	if (changes & BSS_CHANGED_BEACON &&
 866	    iwl_mvm_mac_ctxt_beacon_changed(mvm, vif, link_conf))
 867		IWL_WARN(mvm, "Failed updating beacon data\n");
 868
 869	/* FIXME: need to decide if we need FTM responder per link */
 870	if (changes & BSS_CHANGED_FTM_RESPONDER) {
 871		int ret = iwl_mvm_ftm_start_responder(mvm, vif, link_conf);
 872
 873		if (ret)
 874			IWL_WARN(mvm, "Failed to enable FTM responder (%d)\n",
 875				 ret);
 876	}
 877}
 878
 879static void iwl_mvm_mld_link_info_changed(struct ieee80211_hw *hw,
 880					  struct ieee80211_vif *vif,
 881					  struct ieee80211_bss_conf *link_conf,
 882					  u64 changes)
 883{
 884	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
 885
 886	guard(mvm)(mvm);
 887
 888	switch (vif->type) {
 889	case NL80211_IFTYPE_STATION:
 890		iwl_mvm_mld_link_info_changed_station(mvm, vif, link_conf,
 891						      changes);
 892		break;
 893	case NL80211_IFTYPE_AP:
 894	case NL80211_IFTYPE_ADHOC:
 895		iwl_mvm_mld_link_info_changed_ap_ibss(mvm, vif, link_conf,
 896						      changes);
 897		break;
 898	case NL80211_IFTYPE_MONITOR:
 899		if (changes & BSS_CHANGED_MU_GROUPS)
 900			iwl_mvm_update_mu_groups(mvm, vif);
 901		break;
 902	default:
 903		/* shouldn't happen */
 904		WARN_ON_ONCE(1);
 905	}
 906
 907	if (changes & BSS_CHANGED_TXPOWER) {
 908		IWL_DEBUG_CALIB(mvm, "Changing TX Power to %d dBm\n",
 909				link_conf->txpower);
 910		iwl_mvm_set_tx_power(mvm, link_conf, link_conf->txpower);
 911	}
 912}
 913
 914static void iwl_mvm_mld_vif_cfg_changed(struct ieee80211_hw *hw,
 915					struct ieee80211_vif *vif,
 916					u64 changes)
 917{
 918	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
 919
 920	guard(mvm)(mvm);
 921
 922	if (changes & BSS_CHANGED_IDLE && !vif->cfg.idle)
 923		iwl_mvm_scan_stop(mvm, IWL_MVM_SCAN_SCHED, true);
 924
 925	if (vif->type == NL80211_IFTYPE_STATION)
 926		iwl_mvm_mld_vif_cfg_changed_station(mvm, vif, changes);
 927}
 928
 929static int
 930iwl_mvm_mld_switch_vif_chanctx(struct ieee80211_hw *hw,
 931			       struct ieee80211_vif_chanctx_switch *vifs,
 932			       int n_vifs,
 933			       enum ieee80211_chanctx_switch_mode mode)
 934{
 935	static const struct iwl_mvm_switch_vif_chanctx_ops ops = {
 936		.__assign_vif_chanctx = __iwl_mvm_mld_assign_vif_chanctx,
 937		.__unassign_vif_chanctx = __iwl_mvm_mld_unassign_vif_chanctx,
 938	};
 939
 940	return iwl_mvm_switch_vif_chanctx_common(hw, vifs, n_vifs, mode, &ops);
 941}
 942
 943static void iwl_mvm_mld_config_iface_filter(struct ieee80211_hw *hw,
 944					    struct ieee80211_vif *vif,
 945					    unsigned int filter_flags,
 946					    unsigned int changed_flags)
 947{
 948	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
 949
 950	/* We support only filter for probe requests */
 951	if (!(changed_flags & FIF_PROBE_REQ))
 952		return;
 953
 954	/* Supported only for p2p client interfaces */
 955	if (vif->type != NL80211_IFTYPE_STATION || !vif->cfg.assoc ||
 956	    !vif->p2p)
 957		return;
 958
 959	guard(mvm)(mvm);
 960	iwl_mvm_mld_mac_ctxt_changed(mvm, vif, false);
 961}
 962
 963static int
 964iwl_mvm_mld_mac_conf_tx(struct ieee80211_hw *hw,
 965			struct ieee80211_vif *vif,
 966			unsigned int link_id, u16 ac,
 967			const struct ieee80211_tx_queue_params *params)
 968{
 969	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
 970	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
 971	struct iwl_mvm_vif_link_info *mvm_link = mvmvif->link[link_id];
 972
 973	if (!mvm_link)
 974		return -EINVAL;
 975
 976	mvm_link->queue_params[ac] = *params;
 977
 978	/* No need to update right away, we'll get BSS_CHANGED_QOS
 979	 * The exception is P2P_DEVICE interface which needs immediate update.
 980	 */
 981	if (vif->type == NL80211_IFTYPE_P2P_DEVICE) {
 982		guard(mvm)(mvm);
 983		return iwl_mvm_link_changed(mvm, vif, &vif->bss_conf,
 984					    LINK_CONTEXT_MODIFY_QOS_PARAMS,
 985					    true);
 986	}
 987	return 0;
 988}
 989
 990static int iwl_mvm_mld_roc_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
 991{
 992	int ret;
 993
 994	lockdep_assert_held(&mvm->mutex);
 995
 996	/* The PHY context ID might have changed so need to set it */
 997	ret = iwl_mvm_link_changed(mvm, vif, &vif->bss_conf, 0, false);
 998	if (WARN(ret, "Failed to set PHY context ID\n"))
 999		return ret;
1000
1001	ret = iwl_mvm_link_changed(mvm, vif, &vif->bss_conf,
1002				   LINK_CONTEXT_MODIFY_ACTIVE |
1003				   LINK_CONTEXT_MODIFY_RATES_INFO,
1004				   true);
1005
1006	if (WARN(ret, "Failed linking P2P_DEVICE\n"))
1007		return ret;
1008
1009	/* The station and queue allocation must be done only after the linking
1010	 * is done, as otherwise the FW might incorrectly configure its state.
1011	 */
1012	return iwl_mvm_mld_add_bcast_sta(mvm, vif, &vif->bss_conf);
1013}
1014
1015static int iwl_mvm_mld_roc(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
1016			   struct ieee80211_channel *channel, int duration,
1017			   enum ieee80211_roc_type type)
1018{
1019	static const struct iwl_mvm_roc_ops ops = {
1020		.add_aux_sta_for_hs20 = iwl_mvm_mld_add_aux_sta,
1021		.link = iwl_mvm_mld_roc_link,
1022	};
1023
1024	return iwl_mvm_roc_common(hw, vif, channel, duration, type, &ops);
1025}
1026
1027static int
1028iwl_mvm_mld_change_vif_links(struct ieee80211_hw *hw,
1029			     struct ieee80211_vif *vif,
1030			     u16 old_links, u16 new_links,
1031			     struct ieee80211_bss_conf *old[IEEE80211_MLD_MAX_NUM_LINKS])
1032{
1033	struct iwl_mvm_vif_link_info *new_link[IEEE80211_MLD_MAX_NUM_LINKS] = {};
1034	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1035	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
1036	u16 removed = old_links & ~new_links;
1037	u16 added = new_links & ~old_links;
1038	int err, i;
1039
1040	for (i = 0; i < IEEE80211_MLD_MAX_NUM_LINKS; i++) {
1041		if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))
1042			break;
1043
1044		if (!(added & BIT(i)))
1045			continue;
1046		new_link[i] = kzalloc(sizeof(*new_link[i]), GFP_KERNEL);
1047		if (!new_link[i]) {
1048			err = -ENOMEM;
1049			goto free;
1050		}
1051
1052		new_link[i]->fw_link_id = IWL_MVM_FW_LINK_ID_INVALID;
1053		iwl_mvm_init_link(new_link[i]);
1054	}
1055
1056	mutex_lock(&mvm->mutex);
1057
1058	/* If we're in RESTART flow, the default link wasn't added in
1059         * drv_add_interface(), and link[0] doesn't point to it.
1060	 */
1061	if (old_links == 0 && !test_bit(IWL_MVM_STATUS_IN_HW_RESTART,
1062					&mvm->status)) {
1063		err = iwl_mvm_disable_link(mvm, vif, &vif->bss_conf);
1064		if (err)
1065			goto out_err;
1066		mvmvif->link[0] = NULL;
1067	}
1068
1069	for (i = 0; i < IEEE80211_MLD_MAX_NUM_LINKS; i++) {
1070		if (removed & BIT(i)) {
1071			struct ieee80211_bss_conf *link_conf = old[i];
1072
1073			err = iwl_mvm_disable_link(mvm, vif, link_conf);
1074			if (err)
1075				goto out_err;
1076			kfree(mvmvif->link[i]);
1077			mvmvif->link[i] = NULL;
1078		} else if (added & BIT(i)) {
1079			struct ieee80211_bss_conf *link_conf;
1080
1081			link_conf = link_conf_dereference_protected(vif, i);
1082			if (WARN_ON(!link_conf))
1083				continue;
1084
1085			if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART,
1086				      &mvm->status))
1087				mvmvif->link[i] = new_link[i];
1088			new_link[i] = NULL;
1089			err = iwl_mvm_add_link(mvm, vif, link_conf);
1090			if (err)
1091				goto out_err;
1092		}
1093	}
1094
1095	err = 0;
1096	if (new_links == 0) {
1097		mvmvif->link[0] = &mvmvif->deflink;
1098		err = iwl_mvm_add_link(mvm, vif, &vif->bss_conf);
1099		if (err == 0)
1100			mvmvif->primary_link = 0;
1101	} else if (!(new_links & BIT(mvmvif->primary_link))) {
1102		/*
1103		 * Ensure we always have a valid primary_link, the real
1104		 * decision happens later when PHY is activated.
1105		 */
1106		mvmvif->primary_link = __ffs(new_links);
1107	}
1108
1109out_err:
1110	/* we really don't have a good way to roll back here ... */
1111	mutex_unlock(&mvm->mutex);
1112
1113free:
1114	for (i = 0; i < IEEE80211_MLD_MAX_NUM_LINKS; i++)
1115		kfree(new_link[i]);
1116	return err;
1117}
1118
1119static int
1120iwl_mvm_mld_change_sta_links(struct ieee80211_hw *hw,
1121			     struct ieee80211_vif *vif,
1122			     struct ieee80211_sta *sta,
1123			     u16 old_links, u16 new_links)
1124{
1125	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
1126
1127	guard(mvm)(mvm);
1128	return iwl_mvm_mld_update_sta_links(mvm, vif, sta, old_links, new_links);
1129}
1130
1131bool iwl_mvm_vif_has_esr_cap(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
1132{
1133	const struct wiphy_iftype_ext_capab *ext_capa;
1134
1135	lockdep_assert_held(&mvm->mutex);
1136
1137	if (!ieee80211_vif_is_mld(vif) || !vif->cfg.assoc ||
1138	    hweight16(ieee80211_vif_usable_links(vif)) == 1)
1139		return false;
1140
1141	if (!(vif->cfg.eml_cap & IEEE80211_EML_CAP_EMLSR_SUPP))
1142		return false;
1143
1144	ext_capa = cfg80211_get_iftype_ext_capa(mvm->hw->wiphy,
1145						ieee80211_vif_type_p2p(vif));
1146	return (ext_capa &&
1147		(ext_capa->eml_capabilities & IEEE80211_EML_CAP_EMLSR_SUPP));
1148}
1149
1150static bool iwl_mvm_mld_can_activate_links(struct ieee80211_hw *hw,
1151					   struct ieee80211_vif *vif,
1152					   u16 desired_links)
1153{
1154	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
1155	int n_links = hweight16(desired_links);
1156
1157	if (n_links <= 1)
1158		return true;
1159
1160	guard(mvm)(mvm);
1161
1162	/* Check if HW supports the wanted number of links */
1163	if (n_links > iwl_mvm_max_active_links(mvm, vif))
1164		return false;
1165
1166	/* If it is an eSR device, check that we can enter eSR */
1167	return iwl_mvm_is_esr_supported(mvm->fwrt.trans) &&
1168	       iwl_mvm_vif_has_esr_cap(mvm, vif);
1169}
1170
1171static enum ieee80211_neg_ttlm_res
1172iwl_mvm_mld_can_neg_ttlm(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
1173			 struct ieee80211_neg_ttlm *neg_ttlm)
1174{
1175	u16 map;
1176	u8 i;
1177
1178	/* Verify all TIDs are mapped to the same links set */
1179	map = neg_ttlm->downlink[0];
1180	for (i = 0; i < IEEE80211_TTLM_NUM_TIDS; i++) {
1181		if (neg_ttlm->downlink[i] != neg_ttlm->uplink[i] ||
1182		    neg_ttlm->uplink[i] != map)
1183			return NEG_TTLM_RES_REJECT;
1184	}
1185
1186	return NEG_TTLM_RES_ACCEPT;
1187}
1188
1189const struct ieee80211_ops iwl_mvm_mld_hw_ops = {
1190	.tx = iwl_mvm_mac_tx,
1191	.wake_tx_queue = iwl_mvm_mac_wake_tx_queue,
1192	.ampdu_action = iwl_mvm_mac_ampdu_action,
1193	.get_antenna = iwl_mvm_op_get_antenna,
1194	.set_antenna = iwl_mvm_op_set_antenna,
1195	.start = iwl_mvm_mac_start,
1196	.reconfig_complete = iwl_mvm_mac_reconfig_complete,
1197	.stop = iwl_mvm_mac_stop,
1198	.add_interface = iwl_mvm_mld_mac_add_interface,
1199	.remove_interface = iwl_mvm_mld_mac_remove_interface,
1200	.config = iwl_mvm_mac_config,
1201	.prepare_multicast = iwl_mvm_prepare_multicast,
1202	.configure_filter = iwl_mvm_configure_filter,
1203	.config_iface_filter = iwl_mvm_mld_config_iface_filter,
1204	.link_info_changed = iwl_mvm_mld_link_info_changed,
1205	.vif_cfg_changed = iwl_mvm_mld_vif_cfg_changed,
1206	.hw_scan = iwl_mvm_mac_hw_scan,
1207	.cancel_hw_scan = iwl_mvm_mac_cancel_hw_scan,
1208	.sta_pre_rcu_remove = iwl_mvm_sta_pre_rcu_remove,
1209	.sta_state = iwl_mvm_mld_mac_sta_state,
1210	.sta_notify = iwl_mvm_mac_sta_notify,
1211	.allow_buffered_frames = iwl_mvm_mac_allow_buffered_frames,
1212	.release_buffered_frames = iwl_mvm_mac_release_buffered_frames,
1213	.set_rts_threshold = iwl_mvm_mac_set_rts_threshold,
1214	.link_sta_rc_update = iwl_mvm_sta_rc_update,
1215	.conf_tx = iwl_mvm_mld_mac_conf_tx,
1216	.mgd_prepare_tx = iwl_mvm_mac_mgd_prepare_tx,
1217	.mgd_complete_tx = iwl_mvm_mac_mgd_complete_tx,
1218	.mgd_protect_tdls_discover = iwl_mvm_mac_mgd_protect_tdls_discover,
1219	.flush = iwl_mvm_mac_flush,
1220	.flush_sta = iwl_mvm_mac_flush_sta,
1221	.sched_scan_start = iwl_mvm_mac_sched_scan_start,
1222	.sched_scan_stop = iwl_mvm_mac_sched_scan_stop,
1223	.set_key = iwl_mvm_mac_set_key,
1224	.update_tkip_key = iwl_mvm_mac_update_tkip_key,
1225	.remain_on_channel = iwl_mvm_mld_roc,
1226	.cancel_remain_on_channel = iwl_mvm_cancel_roc,
1227	.add_chanctx = iwl_mvm_add_chanctx,
1228	.remove_chanctx = iwl_mvm_remove_chanctx,
1229	.change_chanctx = iwl_mvm_change_chanctx,
1230	.assign_vif_chanctx = iwl_mvm_mld_assign_vif_chanctx,
1231	.unassign_vif_chanctx = iwl_mvm_mld_unassign_vif_chanctx,
1232	.switch_vif_chanctx = iwl_mvm_mld_switch_vif_chanctx,
1233
1234	.start_ap = iwl_mvm_mld_start_ap,
1235	.stop_ap = iwl_mvm_mld_stop_ap,
1236	.join_ibss = iwl_mvm_mld_start_ibss,
1237	.leave_ibss = iwl_mvm_mld_stop_ibss,
1238
1239	.tx_last_beacon = iwl_mvm_tx_last_beacon,
1240
1241	.channel_switch = iwl_mvm_channel_switch,
1242	.pre_channel_switch = iwl_mvm_mac_pre_channel_switch,
1243	.post_channel_switch = iwl_mvm_post_channel_switch,
1244	.abort_channel_switch = iwl_mvm_abort_channel_switch,
1245	.channel_switch_rx_beacon = iwl_mvm_channel_switch_rx_beacon,
1246
1247	.tdls_channel_switch = iwl_mvm_tdls_channel_switch,
1248	.tdls_cancel_channel_switch = iwl_mvm_tdls_cancel_channel_switch,
1249	.tdls_recv_channel_switch = iwl_mvm_tdls_recv_channel_switch,
1250
1251	.event_callback = iwl_mvm_mac_event_callback,
1252
1253	.sync_rx_queues = iwl_mvm_sync_rx_queues,
1254
1255#ifdef CONFIG_PM_SLEEP
1256	/* look at d3.c */
1257	.suspend = iwl_mvm_suspend,
1258	.resume = iwl_mvm_resume,
1259	.set_wakeup = iwl_mvm_set_wakeup,
1260	.set_rekey_data = iwl_mvm_set_rekey_data,
1261#if IS_ENABLED(CONFIG_IPV6)
1262	.ipv6_addr_change = iwl_mvm_ipv6_addr_change,
1263#endif
1264	.set_default_unicast_key = iwl_mvm_set_default_unicast_key,
1265#endif
1266	.get_survey = iwl_mvm_mac_get_survey,
1267	.sta_statistics = iwl_mvm_mac_sta_statistics,
1268	.get_ftm_responder_stats = iwl_mvm_mac_get_ftm_responder_stats,
1269	.start_pmsr = iwl_mvm_start_pmsr,
1270	.abort_pmsr = iwl_mvm_abort_pmsr,
1271
1272#ifdef CONFIG_IWLWIFI_DEBUGFS
1273	.vif_add_debugfs = iwl_mvm_vif_add_debugfs,
1274	.link_add_debugfs = iwl_mvm_link_add_debugfs,
1275	.link_sta_add_debugfs = iwl_mvm_link_sta_add_debugfs,
1276#endif
1277	.set_hw_timestamp = iwl_mvm_set_hw_timestamp,
1278
1279	.change_vif_links = iwl_mvm_mld_change_vif_links,
1280	.change_sta_links = iwl_mvm_mld_change_sta_links,
1281	.can_activate_links = iwl_mvm_mld_can_activate_links,
1282	.can_neg_ttlm = iwl_mvm_mld_can_neg_ttlm,
1283};
~/ Read-only file preview.