diff options
Diffstat (limited to 'sys/contrib/dev/iwlwifi/mvm')
38 files changed, 2443 insertions, 2830 deletions
| diff --git a/sys/contrib/dev/iwlwifi/mvm/binding.c b/sys/contrib/dev/iwlwifi/mvm/binding.c index 458b97930059..58e9a940024d 100644 --- a/sys/contrib/dev/iwlwifi/mvm/binding.c +++ b/sys/contrib/dev/iwlwifi/mvm/binding.c @@ -2,7 +2,7 @@  /*   * Copyright (C) 2012-2014, 2020 Intel Corporation   * Copyright (C) 2016 Intel Deutschland GmbH - * Copyright (C) 2022 Intel Corporation + * Copyright (C) 2022, 2024 Intel Corporation   */  #include <net/mac80211.h>  #include "fw-api.h" @@ -158,9 +158,8 @@ int iwl_mvm_binding_remove_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif)  	ret = iwl_mvm_binding_update(mvm, vif, mvmvif->deflink.phy_ctxt,  				     false); -	if (!ret) -		if (iwl_mvm_sf_update(mvm, vif, true)) -			IWL_ERR(mvm, "Failed to update SF state\n"); +	if (!ret && iwl_mvm_sf_update(mvm, vif, true)) +		IWL_ERR(mvm, "Failed to update SF state\n");  	return ret;  } diff --git a/sys/contrib/dev/iwlwifi/mvm/coex.c b/sys/contrib/dev/iwlwifi/mvm/coex.c index ad3e14a0d043..13cdc077d8d3 100644 --- a/sys/contrib/dev/iwlwifi/mvm/coex.c +++ b/sys/contrib/dev/iwlwifi/mvm/coex.c @@ -1,6 +1,6 @@  // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause  /* - * Copyright (C) 2013-2014, 2018-2020, 2022-2024 Intel Corporation + * Copyright (C) 2013-2014, 2018-2020, 2022-2025 Intel Corporation   * Copyright (C) 2013-2015 Intel Mobile Communications GmbH   */  #include <linux/ieee80211.h> @@ -181,7 +181,7 @@ static int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id,  	struct iwl_mvm_sta *mvmsta;  	u32 value; -	if (mvm->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) +	if (mvm->trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_AX210)  		return 0;  	mvmsta = iwl_mvm_sta_from_staid_protected(mvm, sta_id); @@ -208,7 +208,7 @@ static int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id,  }  struct iwl_bt_iterator_data { -	struct iwl_bt_coex_profile_notif *notif; +	struct iwl_bt_coex_prof_old_notif *notif;  	struct iwl_mvm *mvm;  	struct ieee80211_chanctx_conf *primary;  	struct ieee80211_chanctx_conf *secondary; @@ -266,10 +266,26 @@ iwl_mvm_bt_coex_calculate_esr_mode(struct iwl_mvm *mvm,  	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);  	bool have_wifi_loss_rate =  		iwl_fw_lookup_notif_ver(mvm->fw, LEGACY_GROUP, -					BT_PROFILE_NOTIFICATION, 0) > 4; +					BT_PROFILE_NOTIFICATION, 0) > 4 || +		iwl_fw_lookup_notif_ver(mvm->fw, BT_COEX_GROUP, +					PROFILE_NOTIF, 0) >= 1; +	u8 wifi_loss_mid_high_rssi; +	u8 wifi_loss_low_rssi;  	u8 wifi_loss_rate; -	if (mvm->last_bt_notif.wifi_loss_low_rssi == BT_OFF) +	if (iwl_fw_lookup_notif_ver(mvm->fw, BT_COEX_GROUP, +				    PROFILE_NOTIF, 0) >= 1) { +		/* For now, we consider 2.4 GHz band / ANT_A only */ +		wifi_loss_mid_high_rssi = +			mvm->last_bt_wifi_loss.wifi_loss_mid_high_rssi[PHY_BAND_24][0]; +		wifi_loss_low_rssi = +			mvm->last_bt_wifi_loss.wifi_loss_low_rssi[PHY_BAND_24][0]; +	} else { +		wifi_loss_mid_high_rssi = mvm->last_bt_notif.wifi_loss_mid_high_rssi; +		wifi_loss_low_rssi = mvm->last_bt_notif.wifi_loss_low_rssi; +	} + +	if (wifi_loss_low_rssi == BT_OFF)  		return true;  	if (primary) @@ -286,20 +302,20 @@ iwl_mvm_bt_coex_calculate_esr_mode(struct iwl_mvm *mvm,  	 * we will get an update on this and exit eSR.  	 */  	if (!link_rssi) -		wifi_loss_rate = mvm->last_bt_notif.wifi_loss_mid_high_rssi; +		wifi_loss_rate = wifi_loss_mid_high_rssi;  	else if (mvmvif->esr_active)  		 /* RSSI needs to get really low to disable eSR... */  		wifi_loss_rate =  			link_rssi <= -IWL_MVM_BT_COEX_DISABLE_ESR_THRESH ? -				mvm->last_bt_notif.wifi_loss_low_rssi : -				mvm->last_bt_notif.wifi_loss_mid_high_rssi; +				wifi_loss_low_rssi : +				wifi_loss_mid_high_rssi;  	else  		/* ...And really high before we enable it back */  		wifi_loss_rate =  			link_rssi <= -IWL_MVM_BT_COEX_ENABLE_ESR_THRESH ? -				mvm->last_bt_notif.wifi_loss_low_rssi : -				mvm->last_bt_notif.wifi_loss_mid_high_rssi; +				wifi_loss_low_rssi : +				wifi_loss_mid_high_rssi;  	return wifi_loss_rate <= IWL_MVM_BT_COEX_WIFI_LOSS_THRESH;  } @@ -509,6 +525,32 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,  		iwl_mvm_bt_notif_per_link(mvm, vif, data, link_id);  } +/* must be called under rcu_read_lock */ +static void iwl_mvm_bt_coex_notif_iterator(void *_data, u8 *mac, +					   struct ieee80211_vif *vif) +{ +	struct iwl_mvm *mvm = _data; +	struct ieee80211_bss_conf *link_conf; +	unsigned int link_id; + +	lockdep_assert_held(&mvm->mutex); + +	if (vif->type != NL80211_IFTYPE_STATION) +		return; + +	for_each_vif_active_link(vif, link_conf, link_id) { +		struct ieee80211_chanctx_conf *chanctx_conf = +			rcu_dereference_check(link_conf->chanctx_conf, +					      lockdep_is_held(&mvm->mutex)); + +		if ((!chanctx_conf || +		     chanctx_conf->def.chan->band != NL80211_BAND_2GHZ)) +			continue; + +		iwl_mvm_bt_coex_update_link_esr(mvm, vif, link_id); +	} +} +  static void iwl_mvm_bt_coex_notif_handle(struct iwl_mvm *mvm)  {  	struct iwl_bt_iterator_data data = { @@ -527,7 +569,7 @@ static void iwl_mvm_bt_coex_notif_handle(struct iwl_mvm *mvm)  					mvm->hw, IEEE80211_IFACE_ITER_NORMAL,  					iwl_mvm_bt_notif_iterator, &data); -	if (mvm->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) { +	if (mvm->trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) {  		rcu_read_unlock();  		return;  	} @@ -591,11 +633,11 @@ static void iwl_mvm_bt_coex_notif_handle(struct iwl_mvm *mvm)  	}  } -void iwl_mvm_rx_bt_coex_notif(struct iwl_mvm *mvm, -			      struct iwl_rx_cmd_buffer *rxb) +void iwl_mvm_rx_bt_coex_old_notif(struct iwl_mvm *mvm, +				  struct iwl_rx_cmd_buffer *rxb)  {  	struct iwl_rx_packet *pkt = rxb_addr(rxb); -	struct iwl_bt_coex_profile_notif *notif = (void *)pkt->data; +	struct iwl_bt_coex_prof_old_notif *notif = (void *)pkt->data;  	IWL_DEBUG_COEX(mvm, "BT Coex Notification received\n");  	IWL_DEBUG_COEX(mvm, "\tBT ci compliance %d\n", notif->bt_ci_compliance); @@ -612,6 +654,22 @@ void iwl_mvm_rx_bt_coex_notif(struct iwl_mvm *mvm,  	iwl_mvm_bt_coex_notif_handle(mvm);  } +void iwl_mvm_rx_bt_coex_notif(struct iwl_mvm *mvm, +			      struct iwl_rx_cmd_buffer *rxb) +{ +	const struct iwl_rx_packet *pkt = rxb_addr(rxb); +	const struct iwl_bt_coex_profile_notif *notif = (const void *)pkt->data; + +	lockdep_assert_held(&mvm->mutex); + +	mvm->last_bt_wifi_loss = *notif; + +	ieee80211_iterate_active_interfaces(mvm->hw, +					    IEEE80211_IFACE_ITER_NORMAL, +					    iwl_mvm_bt_coex_notif_iterator, +					    mvm); +} +  void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif,  			   enum ieee80211_rssi_event_data rssi_event)  { @@ -628,7 +686,7 @@ void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif,  	 * Rssi update while not associated - can happen since the statistics  	 * are handled asynchronously  	 */ -	if (mvmvif->deflink.ap_sta_id == IWL_MVM_INVALID_STA) +	if (mvmvif->deflink.ap_sta_id == IWL_INVALID_STA)  		return;  	/* No BT - reports should be disabled */ diff --git a/sys/contrib/dev/iwlwifi/mvm/constants.h b/sys/contrib/dev/iwlwifi/mvm/constants.h index c4c1e67b9ac7..776600ddaea6 100644 --- a/sys/contrib/dev/iwlwifi/mvm/constants.h +++ b/sys/contrib/dev/iwlwifi/mvm/constants.h @@ -16,6 +16,10 @@  #define IWL_MVM_BT_COEX_WIFI_LOSS_THRESH	0  #define IWL_MVM_TRIGGER_LINK_SEL_TIME_SEC	30  #define IWL_MVM_TPT_COUNT_WINDOW_SEC		5 +#define IWL_MVM_BCN_LOSS_EXIT_ESR_THRESH_2_LINKS	5 +#define IWL_MVM_BCN_LOSS_EXIT_ESR_THRESH	15 +#define IWL_MVM_BCN_LOSS_EXIT_ESR_THRESH_BSS_PARAM_CHANGED	11 +#define IWL_MVM_LOW_RSSI_MLO_SCAN_THRESH	-72  #define IWL_MVM_DEFAULT_PS_TX_DATA_TIMEOUT	(100 * USEC_PER_MSEC)  #define IWL_MVM_DEFAULT_PS_RX_DATA_TIMEOUT	(100 * USEC_PER_MSEC) @@ -55,7 +59,6 @@  #define IWL_MVM_RS_RSSI_BASED_INIT_RATE         0  #define IWL_MVM_RS_80_20_FAR_RANGE_TWEAK	1  #define IWL_MVM_TOF_IS_RESPONDER		0 -#define IWL_MVM_HW_CSUM_DISABLE			0  #define IWL_MVM_ADWELL_ENABLE			1  #define IWL_MVM_ADWELL_MAX_BUDGET		0  #define IWL_MVM_TCM_LOAD_MEDIUM_THRESH		10 /* percentage */ @@ -109,7 +112,7 @@  #define IWL_MVM_FTM_INITIATOR_SECURE_LTF	false  #define IWL_MVM_FTM_RESP_NDP_SUPPORT		true  #define IWL_MVM_FTM_RESP_LMR_FEEDBACK_SUPPORT	true -#define IWL_MVM_FTM_NON_TB_MIN_TIME_BETWEEN_MSR	5 +#define IWL_MVM_FTM_NON_TB_MIN_TIME_BETWEEN_MSR	7  #define IWL_MVM_FTM_NON_TB_MAX_TIME_BETWEEN_MSR	1000  #define IWL_MVM_D3_DEBUG			false  #define IWL_MVM_USE_TWT				true @@ -125,7 +128,6 @@  #define IWL_MVM_6GHZ_PASSIVE_SCAN_ASSOC_TIMEOUT 60   /* in seconds */  #define IWL_MVM_MIN_BEACON_INTERVAL_TU		16  #define IWL_MVM_AUTO_EML_ENABLE                 true -#define IWL_MVM_MISSED_BEACONS_EXIT_ESR_THRESH	7  #define IWL_MVM_HIGH_RSSI_THRESH_20MHZ		-67  #define IWL_MVM_LOW_RSSI_THRESH_20MHZ		-71 diff --git a/sys/contrib/dev/iwlwifi/mvm/d3.c b/sys/contrib/dev/iwlwifi/mvm/d3.c index 11d9911eabb1..c7d298294ec1 100644 --- a/sys/contrib/dev/iwlwifi/mvm/d3.c +++ b/sys/contrib/dev/iwlwifi/mvm/d3.c @@ -1,6 +1,6 @@  // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause  /* - * Copyright (C) 2012-2014, 2018-2024 Intel Corporation + * Copyright (C) 2012-2014, 2018-2025 Intel Corporation   * Copyright (C) 2013-2015 Intel Mobile Communications GmbH   * Copyright (C) 2016-2017 Intel Deutschland GmbH   */ @@ -124,19 +124,17 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw,  	switch (key->cipher) {  	case WLAN_CIPHER_SUITE_WEP40:  	case WLAN_CIPHER_SUITE_WEP104: { /* hack it for now */ -		struct { -			struct iwl_mvm_wep_key_cmd wep_key_cmd; -			struct iwl_mvm_wep_key wep_key; -		} __packed wkc = { -			.wep_key_cmd.mac_id_n_color = -				cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, -								mvmvif->color)), -			.wep_key_cmd.num_keys = 1, -			/* firmware sets STA_KEY_FLG_WEP_13BYTES */ -			.wep_key_cmd.decryption_type = STA_KEY_FLG_WEP, -			.wep_key.key_index = key->keyidx, -			.wep_key.key_size = key->keylen, -		}; +		DEFINE_RAW_FLEX(struct iwl_mvm_wep_key_cmd, wkc, wep_key, 1); +		struct iwl_mvm_wep_key *wep_key = wkc->wep_key; + +		wkc->mac_id_n_color = +			cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, +							mvmvif->color)); +		wkc->num_keys = 1; +		/* firmware sets STA_KEY_FLG_WEP_13BYTES */ +		wkc->decryption_type = STA_KEY_FLG_WEP; +		wep_key->key_index = key->keyidx; +		wep_key->key_size = key->keylen;  		/*  		 * This will fail -- the key functions don't set support @@ -146,18 +144,19 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw,  		if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE)  			break; -		memcpy(&wkc.wep_key.key[3], key->key, key->keylen); +		memcpy(&wep_key->key[3], key->key, key->keylen);  		if (key->keyidx == mvmvif->tx_key_idx) {  			/* TX key must be at offset 0 */ -			wkc.wep_key.key_offset = 0; +			wep_key->key_offset = 0;  		} else {  			/* others start at 1 */  			data->wep_key_idx++; -			wkc.wep_key.key_offset = data->wep_key_idx; +			wep_key->key_offset = data->wep_key_idx;  		}  		mutex_lock(&mvm->mutex); -		ret = iwl_mvm_send_cmd_pdu(mvm, WEP_KEY, 0, sizeof(wkc), &wkc); +		ret = iwl_mvm_send_cmd_pdu(mvm, WEP_KEY, 0, +					   __struct_size(wkc), wkc);  		data->error = ret != 0;  		mvm->ptk_ivlen = key->iv_len; @@ -216,7 +215,7 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw,  }  struct wowlan_key_rsc_tsc_data { -	struct iwl_wowlan_rsc_tsc_params_cmd_v4 *rsc_tsc; +	struct iwl_wowlan_rsc_tsc_params_cmd_ver_2 *rsc_tsc;  	bool have_rsc_tsc;  }; @@ -241,21 +240,21 @@ static void iwl_mvm_wowlan_get_rsc_tsc_data(struct ieee80211_hw *hw,  			u64 pn64;  			tkip_sc = -			   data->rsc_tsc->params.all_tsc_rsc.tkip.unicast_rsc; +			   data->rsc_tsc->all_tsc_rsc.tkip.unicast_rsc;  			tkip_tx_sc = -				&data->rsc_tsc->params.all_tsc_rsc.tkip.tsc; +				&data->rsc_tsc->all_tsc_rsc.tkip.tsc;  			pn64 = atomic64_read(&key->tx_pn);  			tkip_tx_sc->iv16 = cpu_to_le16(TKIP_PN_TO_IV16(pn64));  			tkip_tx_sc->iv32 = cpu_to_le32(TKIP_PN_TO_IV32(pn64));  		} else {  			tkip_sc = -			  data->rsc_tsc->params.all_tsc_rsc.tkip.multicast_rsc; +			  data->rsc_tsc->all_tsc_rsc.tkip.multicast_rsc;  		}  		/*  		 * For non-QoS this relies on the fact that both the uCode and -		 * mac80211 use TID 0 (as they need to to avoid replay attacks) +		 * mac80211 use TID 0 (as they need to avoid replay attacks)  		 * for checking the IV in the frames.  		 */  		for (i = 0; i < IWL_NUM_RSC; i++) { @@ -274,15 +273,15 @@ static void iwl_mvm_wowlan_get_rsc_tsc_data(struct ieee80211_hw *hw,  			u64 pn64;  			aes_sc = -			   data->rsc_tsc->params.all_tsc_rsc.aes.unicast_rsc; +			   data->rsc_tsc->all_tsc_rsc.aes.unicast_rsc;  			aes_tx_sc = -				&data->rsc_tsc->params.all_tsc_rsc.aes.tsc; +				&data->rsc_tsc->all_tsc_rsc.aes.tsc;  			pn64 = atomic64_read(&key->tx_pn);  			aes_tx_sc->pn = cpu_to_le64(pn64);  		} else {  			aes_sc = -			   data->rsc_tsc->params.all_tsc_rsc.aes.multicast_rsc; +			   data->rsc_tsc->all_tsc_rsc.aes.multicast_rsc;  		}  		/* @@ -304,7 +303,7 @@ static void iwl_mvm_wowlan_get_rsc_tsc_data(struct ieee80211_hw *hw,  			for (i = 0; i < IWL_MAX_TID_COUNT; i++) {  				pn = iwl_mvm_find_max_pn(key, ptk_pn, &seq, i, -						mvm->trans->num_rx_queues); +						mvm->trans->info.num_rxqs);  				aes_sc[i].pn = cpu_to_le64((u64)pn[5] |  							   ((u64)pn[4] << 8) |  							   ((u64)pn[3] << 16) | @@ -391,7 +390,7 @@ static void iwl_mvm_wowlan_get_rsc_v5_data(struct ieee80211_hw *hw,  		/*  		 * For non-QoS this relies on the fact that both the uCode and -		 * mac80211 use TID 0 (as they need to to avoid replay attacks) +		 * mac80211 use TID 0 (as they need to avoid replay attacks)  		 * for checking the IV in the frames.  		 */  		for (i = 0; i < IWL_MAX_TID_COUNT; i++) { @@ -425,7 +424,7 @@ static void iwl_mvm_wowlan_get_rsc_v5_data(struct ieee80211_hw *hw,  			for (i = 0; i < IWL_MAX_TID_COUNT; i++) {  				pn = iwl_mvm_find_max_pn(key, ptk_pn, &seq, i, -						mvm->trans->num_rx_queues); +						mvm->trans->info.num_rxqs);  				rsc[i] = cpu_to_le64((u64)pn[5] |  						     ((u64)pn[4] << 8) |  						     ((u64)pn[3] << 16) | @@ -485,30 +484,21 @@ static int iwl_mvm_wowlan_config_rsc_tsc(struct iwl_mvm *mvm,  		else  			ret = 0;  		kfree(data.rsc); -	} else if (ver == 4 || ver == 2 || ver == IWL_FW_CMD_VER_UNKNOWN) { +	} else if (ver == 2 || ver == IWL_FW_CMD_VER_UNKNOWN) {  		struct wowlan_key_rsc_tsc_data data = {}; -		int size;  		data.rsc_tsc = kzalloc(sizeof(*data.rsc_tsc), GFP_KERNEL);  		if (!data.rsc_tsc)  			return -ENOMEM; -		if (ver == 4) { -			size = sizeof(*data.rsc_tsc); -			data.rsc_tsc->sta_id = -				cpu_to_le32(mvm_link->ap_sta_id); -		} else { -			/* ver == 2 || ver == IWL_FW_CMD_VER_UNKNOWN */ -			size = sizeof(data.rsc_tsc->params); -		} -  		ieee80211_iter_keys(mvm->hw, vif,  				    iwl_mvm_wowlan_get_rsc_tsc_data,  				    &data);  		if (data.have_rsc_tsc)  			ret = iwl_mvm_send_cmd_pdu(mvm, WOWLAN_TSC_RSC_PARAM, -						   CMD_ASYNC, size, +						   CMD_ASYNC, +						   sizeof(*data.rsc_tsc),  						   data.rsc_tsc);  		else  			ret = 0; @@ -926,7 +916,7 @@ static int iwl_mvm_switch_to_d3(struct iwl_mvm *mvm)  static int  iwl_mvm_get_wowlan_config(struct iwl_mvm *mvm,  			  struct cfg80211_wowlan *wowlan, -			  struct iwl_wowlan_config_cmd *wowlan_config_cmd, +			  struct iwl_wowlan_config_cmd_v6 *wowlan_config_cmd,  			  struct ieee80211_vif *vif, struct iwl_mvm_vif *mvmvif,  			  struct ieee80211_sta *ap_sta)  { @@ -952,7 +942,8 @@ iwl_mvm_get_wowlan_config(struct iwl_mvm *mvm,  		wowlan_config_cmd->non_qos_seq = cpu_to_le16(ret);  	} -	iwl_mvm_set_wowlan_qos_seq(mvm_ap_sta, wowlan_config_cmd); +	if (iwl_fw_lookup_cmd_ver(mvm->fw, WOWLAN_CONFIGURATION, 0) < 7) +		iwl_mvm_set_wowlan_qos_seq(mvm_ap_sta, wowlan_config_cmd);  	if (wowlan->disconnect)  		wowlan_config_cmd->wakeup_filter |= @@ -1126,7 +1117,7 @@ static int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm,  static int  iwl_mvm_wowlan_config(struct iwl_mvm *mvm,  		      struct cfg80211_wowlan *wowlan, -		      struct iwl_wowlan_config_cmd *wowlan_config_cmd, +		      struct iwl_wowlan_config_cmd_v6 *wowlan_config_cmd_v6,  		      struct ieee80211_vif *vif, struct iwl_mvm_vif *mvmvif,  		      struct iwl_mvm_vif_link_info *mvm_link,  		      struct ieee80211_sta *ap_sta) @@ -1135,7 +1126,7 @@ iwl_mvm_wowlan_config(struct iwl_mvm *mvm,  	bool unified_image = fw_has_capa(&mvm->fw->ucode_capa,  					 IWL_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG); -	mvm->offload_tid = wowlan_config_cmd->offloading_tid; +	mvm->offload_tid = wowlan_config_cmd_v6->offloading_tid;  	if (!unified_image) {  		ret = iwl_mvm_switch_to_d3(mvm); @@ -1151,9 +1142,26 @@ iwl_mvm_wowlan_config(struct iwl_mvm *mvm,  	if (ret)  		return ret; -	ret = iwl_mvm_send_cmd_pdu(mvm, WOWLAN_CONFIGURATION, 0, -				   sizeof(*wowlan_config_cmd), -				   wowlan_config_cmd); +	if (iwl_fw_lookup_cmd_ver(mvm->fw, WOWLAN_CONFIGURATION, 0) > 6) { +		struct iwl_wowlan_config_cmd wowlan_config_cmd = { +			.wakeup_filter = wowlan_config_cmd_v6->wakeup_filter, +			.wowlan_ba_teardown_tids = +				wowlan_config_cmd_v6->wowlan_ba_teardown_tids, +			.is_11n_connection = +				wowlan_config_cmd_v6->is_11n_connection, +			.offloading_tid = wowlan_config_cmd_v6->offloading_tid, +			.flags = wowlan_config_cmd_v6->flags, +			.sta_id = wowlan_config_cmd_v6->sta_id, +		}; + +		ret = iwl_mvm_send_cmd_pdu(mvm, WOWLAN_CONFIGURATION, 0, +					   sizeof(wowlan_config_cmd), +					   &wowlan_config_cmd); +	} else { +		ret = iwl_mvm_send_cmd_pdu(mvm, WOWLAN_CONFIGURATION, 0, +					   sizeof(*wowlan_config_cmd_v6), +					   wowlan_config_cmd_v6); +	}  	if (ret)  		return ret; @@ -1252,7 +1260,7 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,  	};  	struct iwl_host_cmd d3_cfg_cmd = {  		.id = D3_CONFIG_CMD, -		.flags = CMD_WANT_SKB | CMD_SEND_IN_D3, +		.flags = CMD_WANT_SKB,  		.data[0] = &d3_cfg_cmd_data,  		.len[0] = sizeof(d3_cfg_cmd_data),  	}; @@ -1292,7 +1300,7 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,  		goto out_noreset;  	} -	if (mvm_link->ap_sta_id == IWL_MVM_INVALID_STA) { +	if (mvm_link->ap_sta_id == IWL_INVALID_STA) {  		/* if we're not associated, this must be netdetect */  		if (!wowlan->nd_config) {  			ret = 1; @@ -1306,7 +1314,7 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,  		mvm->net_detect = true;  	} else { -		struct iwl_wowlan_config_cmd wowlan_config_cmd = { +		struct iwl_wowlan_config_cmd_v6 wowlan_config_cmd = {  			.offloading_tid = 0,  		}; @@ -1356,11 +1364,9 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,  	 * recording before entering D3. In later devices the FW stops the  	 * recording automatically.  	 */ -	if (mvm->trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_9000) +	if (mvm->trans->mac_cfg->device_family < IWL_DEVICE_FAMILY_9000)  		iwl_fw_dbg_stop_restart_recording(&mvm->fwrt, NULL, true); -	mvm->trans->system_pm_mode = IWL_PLAT_PM_MODE_D3; -  	/* must be last -- this switches firmware state */  	ret = iwl_mvm_send_cmd(mvm, &d3_cfg_cmd);  	if (ret) @@ -1381,13 +1387,6 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,  	if (ret < 0) {  		iwl_mvm_free_nd(mvm); -		if (!unified_image) { -			if (mvm->fw_restart > 0) { -				mvm->fw_restart--; -				ieee80211_restart_hw(mvm->hw); -			} -		} -  		clear_bit(IWL_MVM_STATUS_IN_D3, &mvm->status);  	}   out_noreset: @@ -1402,7 +1401,9 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)  	iwl_mvm_pause_tcm(mvm, true); +	mutex_lock(&mvm->mutex);  	iwl_fw_runtime_suspend(&mvm->fwrt); +	mutex_unlock(&mvm->mutex);  	return __iwl_mvm_suspend(hw, wowlan, false);  } @@ -1427,6 +1428,7 @@ struct iwl_wowlan_status_data {  	u16 non_qos_seq_ctr;  	u16 qos_seq_ctr[8];  	u8 tid_tear_down; +	u8 tid_offloaded_tx;  	struct {  		/* including RX MIC key for TKIP */ @@ -1467,9 +1469,6 @@ struct iwl_wowlan_status_data {  	struct iwl_multicast_key_data igtk;  	struct iwl_multicast_key_data bigtk[WOWLAN_BIGTK_KEYS_NUM]; -	int num_mlo_keys; -	struct iwl_wowlan_mlo_gtk mlo_keys[WOWLAN_MAX_MLO_KEYS]; -  	u8 *wake_packet;  }; @@ -1676,7 +1675,7 @@ static void iwl_mvm_set_aes_ptk_rx_seq(struct iwl_mvm *mvm,  	for (tid = 0; tid < IWL_MAX_TID_COUNT; tid++) {  		int i; -		for (i = 1; i < mvm->trans->num_rx_queues; i++) +		for (i = 1; i < mvm->trans->info.num_rxqs; i++)  			memcpy(ptk_pn->q[i].pn[tid],  			       status->ptk.aes.seq[tid].ccmp.pn,  			       IEEE80211_CCMP_PN_LEN); @@ -1685,7 +1684,7 @@ static void iwl_mvm_set_aes_ptk_rx_seq(struct iwl_mvm *mvm,  }  static void iwl_mvm_convert_key_counters(struct iwl_wowlan_status_data *status, -					 union iwl_all_tsc_rsc *sc) +					 union iwl_all_tsc_rsc *sc, u8 key_idx)  {  	int i; @@ -1700,7 +1699,7 @@ static void iwl_mvm_convert_key_counters(struct iwl_wowlan_status_data *status,  				      &status->gtk_seq[0].aes.seq[i]);  	}  	status->gtk_seq[0].valid = true; -	status->gtk_seq[0].key_id = -1; +	status->gtk_seq[0].key_id = key_idx;  	/* PTK TX counter */  	status->ptk.tkip.tx_pn = (u64)le16_to_cpu(sc->tkip.tsc.iv16) | @@ -1783,8 +1782,7 @@ static void iwl_mvm_set_key_rx_seq_idx(struct ieee80211_key_conf *key,  }  static void iwl_mvm_set_key_rx_seq(struct ieee80211_key_conf *key, -				   struct iwl_wowlan_status_data *status, -				   bool installed) +				   struct iwl_wowlan_status_data *status)  {  	int i; @@ -1792,23 +1790,7 @@ static void iwl_mvm_set_key_rx_seq(struct ieee80211_key_conf *key,  		if (!status->gtk_seq[i].valid)  			continue; -		/* Handle the case where we know the key ID */ -		if (status->gtk_seq[i].key_id == key->keyidx) { -			s8 new_key_id = -1; - -			if (status->num_of_gtk_rekeys) -				new_key_id = status->gtk[0].flags & -						IWL_WOWLAN_GTK_IDX_MASK; - -			/* Don't install a new key's value to an old key */ -			if (new_key_id != key->keyidx) -				iwl_mvm_set_key_rx_seq_idx(key, status, i); -			continue; -		} - -		/* handle the case where we didn't, last key only */ -		if (status->gtk_seq[i].key_id == -1 && -		    (!status->num_of_gtk_rekeys || installed)) +		if (status->gtk_seq[i].key_id == key->keyidx)  			iwl_mvm_set_key_rx_seq_idx(key, status, i);  	}  } @@ -1898,17 +1880,10 @@ iwl_mvm_d3_update_igtk_bigtk(struct iwl_wowlan_status_data *status,  			     struct ieee80211_key_conf *key,  			     struct iwl_multicast_key_data *key_data)  { -	if (status->num_of_gtk_rekeys && key_data->len) { -		/* remove rekeyed key */ -		ieee80211_remove_key(key); -	} else { -		struct ieee80211_key_seq seq; +	struct ieee80211_key_seq seq; -		iwl_mvm_d3_set_igtk_bigtk_ipn(key_data, -					      &seq, -					      key->cipher); -		ieee80211_set_key_rx_seq(key, 0, &seq); -	} +	iwl_mvm_d3_set_igtk_bigtk_ipn(key_data, &seq, key->cipher); +	ieee80211_set_key_rx_seq(key, 0, &seq);  }  static void iwl_mvm_d3_update_keys(struct ieee80211_hw *hw, @@ -1949,18 +1924,13 @@ static void iwl_mvm_d3_update_keys(struct ieee80211_hw *hw,  			return;  		}  		keyidx = key->keyidx; -		/* The current key is always sent by the FW, even if it wasn't -		 * rekeyed during D3. -		 * We remove an existing key if it has the same index as -		 * a new key +		/* +		 * Update the seq even if there was a rekey. If there was a +		 * rekey, we will update again after replacing the key  		 */ -		if (status->num_of_gtk_rekeys && -		    ((status->gtk[0].len && keyidx == status->gtk[0].id) || -		     (status->gtk[1].len && keyidx == status->gtk[1].id))) { -			ieee80211_remove_key(key); -		} else { -			iwl_mvm_set_key_rx_seq(key, data->status, false); -		} +		if ((status->gtk[0].len && keyidx == status->gtk[0].id) || +		    (status->gtk[1].len && keyidx == status->gtk[1].id)) +			iwl_mvm_set_key_rx_seq(key, status);  		break;  	case WLAN_CIPHER_SUITE_BIP_GMAC_128:  	case WLAN_CIPHER_SUITE_BIP_GMAC_256: @@ -1979,199 +1949,35 @@ static void iwl_mvm_d3_update_keys(struct ieee80211_hw *hw,  	}  } -struct iwl_mvm_d3_mlo_old_keys { -	u32 cipher[IEEE80211_MLD_MAX_NUM_LINKS][WOWLAN_MLO_GTK_KEY_NUM_TYPES]; -	struct ieee80211_key_conf *key[IEEE80211_MLD_MAX_NUM_LINKS][8]; -}; - -static void iwl_mvm_mlo_key_ciphers(struct ieee80211_hw *hw, -				    struct ieee80211_vif *vif, -				    struct ieee80211_sta *sta, -				    struct ieee80211_key_conf *key, -				    void *data) -{ -	struct iwl_mvm_d3_mlo_old_keys *old_keys = data; -	enum iwl_wowlan_mlo_gtk_type key_type; - -	if (key->link_id < 0) -		return; - -	if (WARN_ON(key->link_id >= IEEE80211_MLD_MAX_NUM_LINKS || -		    key->keyidx >= 8)) -		return; - -	if (WARN_ON(old_keys->key[key->link_id][key->keyidx])) -		return; - -	switch (key->cipher) { -	case WLAN_CIPHER_SUITE_CCMP: -	case WLAN_CIPHER_SUITE_GCMP: -	case WLAN_CIPHER_SUITE_GCMP_256: -		key_type = WOWLAN_MLO_GTK_KEY_TYPE_GTK; -		break; -	case WLAN_CIPHER_SUITE_BIP_GMAC_128: -	case WLAN_CIPHER_SUITE_BIP_GMAC_256: -	case WLAN_CIPHER_SUITE_BIP_CMAC_256: -	case WLAN_CIPHER_SUITE_AES_CMAC: -		if (key->keyidx == 4 || key->keyidx == 5) { -			key_type = WOWLAN_MLO_GTK_KEY_TYPE_IGTK; -			break; -		} else if (key->keyidx == 6 || key->keyidx == 7) { -			key_type = WOWLAN_MLO_GTK_KEY_TYPE_BIGTK; -			break; -		} -		return; -	default: -		/* ignore WEP/TKIP or unknown ciphers */ -		return; -	} - -	old_keys->cipher[key->link_id][key_type] = key->cipher; -	old_keys->key[key->link_id][key->keyidx] = key; -} - -static bool iwl_mvm_mlo_gtk_rekey(struct iwl_wowlan_status_data *status, -				  struct ieee80211_vif *vif, -				  struct iwl_mvm *mvm) -{ -	int i; -	struct iwl_mvm_d3_mlo_old_keys *old_keys; -	bool ret = true; - -	IWL_DEBUG_WOWLAN(mvm, "Num of MLO Keys: %d\n", status->num_mlo_keys); -	if (!status->num_mlo_keys) -		return true; - -	old_keys = kzalloc(sizeof(*old_keys), GFP_KERNEL); -	if (!old_keys) -		return false; - -	/* find the cipher for each mlo key */ -	ieee80211_iter_keys(mvm->hw, vif, iwl_mvm_mlo_key_ciphers, old_keys); - -	for (i = 0; i < status->num_mlo_keys; i++) { -		struct iwl_wowlan_mlo_gtk *mlo_key = &status->mlo_keys[i]; -		struct ieee80211_key_conf *key, *old_key; -		struct ieee80211_key_seq seq; -		struct { -			struct ieee80211_key_conf conf; -			u8 key[32]; -		} conf = {}; -		u16 flags = le16_to_cpu(mlo_key->flags); -		int j, link_id, key_id, key_type; - -		link_id = u16_get_bits(flags, WOWLAN_MLO_GTK_FLAG_LINK_ID_MSK); -		key_id = u16_get_bits(flags, WOWLAN_MLO_GTK_FLAG_KEY_ID_MSK); -		key_type = u16_get_bits(flags, -					WOWLAN_MLO_GTK_FLAG_KEY_TYPE_MSK); - -		if (!(vif->valid_links & BIT(link_id))) -			continue; - -		if (WARN_ON(link_id >= IEEE80211_MLD_MAX_NUM_LINKS || -			    key_id >= 8 || -			    key_type >= WOWLAN_MLO_GTK_KEY_NUM_TYPES)) -			continue; - -		conf.conf.cipher = old_keys->cipher[link_id][key_type]; -		/* WARN_ON? */ -		if (!conf.conf.cipher) -			continue; - -		conf.conf.keylen = 0; -		switch (conf.conf.cipher) { -		case WLAN_CIPHER_SUITE_CCMP: -		case WLAN_CIPHER_SUITE_GCMP: -			conf.conf.keylen = WLAN_KEY_LEN_CCMP; -			break; -		case WLAN_CIPHER_SUITE_GCMP_256: -			conf.conf.keylen = WLAN_KEY_LEN_GCMP_256; -			break; -		case WLAN_CIPHER_SUITE_BIP_GMAC_128: -			conf.conf.keylen = WLAN_KEY_LEN_BIP_GMAC_128; -			break; -		case WLAN_CIPHER_SUITE_BIP_GMAC_256: -			conf.conf.keylen = WLAN_KEY_LEN_BIP_GMAC_256; -			break; -		case WLAN_CIPHER_SUITE_AES_CMAC: -			conf.conf.keylen = WLAN_KEY_LEN_AES_CMAC; -			break; -		case WLAN_CIPHER_SUITE_BIP_CMAC_256: -			conf.conf.keylen = WLAN_KEY_LEN_BIP_CMAC_256; -			break; -		} - -		if (WARN_ON(!conf.conf.keylen || -			    conf.conf.keylen > sizeof(conf.key))) -			continue; - -		memcpy(conf.conf.key, mlo_key->key, conf.conf.keylen); -		conf.conf.keyidx = key_id; - -		old_key = old_keys->key[link_id][key_id]; -		if (old_key) { -			IWL_DEBUG_WOWLAN(mvm, -					 "Remove MLO key id %d, link id %d\n", -					 key_id, link_id); -			ieee80211_remove_key(old_key); -		} - -		IWL_DEBUG_WOWLAN(mvm, "Add MLO key id %d, link id %d\n", -				 key_id, link_id); -		key = ieee80211_gtk_rekey_add(vif, &conf.conf, link_id); -		if (WARN_ON(IS_ERR(key))) { -			ret = false; -			goto out; -		} - -		/* -		 * mac80211 expects the pn in big-endian -		 * also note that seq is a union of all cipher types -		 * (ccmp, gcmp, cmac, gmac), and they all have the same -		 * pn field (of length 6) so just copy it to ccmp.pn. -		 */ -		for (j = 5; j >= 0; j--) -			seq.ccmp.pn[5 - j] = mlo_key->pn[j]; - -		/* group keys are non-QoS and use TID 0 */ -		ieee80211_set_key_rx_seq(key, 0, &seq); -	} - -out: -	kfree(old_keys); -	return ret; -} -  static bool iwl_mvm_gtk_rekey(struct iwl_wowlan_status_data *status,  			      struct ieee80211_vif *vif,  			      struct iwl_mvm *mvm, u32 gtk_cipher)  {  	int i, j;  	struct ieee80211_key_conf *key; -	struct { -		struct ieee80211_key_conf conf; -		u8 key[32]; -	} conf = { -		.conf.cipher = gtk_cipher, -	}; +	DEFINE_RAW_FLEX(struct ieee80211_key_conf, conf, key, +			WOWLAN_KEY_MAX_SIZE);  	int link_id = vif->active_links ? __ffs(vif->active_links) : -1; +	u8 key_data[WOWLAN_KEY_MAX_SIZE]; + +	conf->cipher = gtk_cipher;  	BUILD_BUG_ON(WLAN_KEY_LEN_CCMP != WLAN_KEY_LEN_GCMP); -	BUILD_BUG_ON(sizeof(conf.key) < WLAN_KEY_LEN_CCMP); -	BUILD_BUG_ON(sizeof(conf.key) < WLAN_KEY_LEN_GCMP_256); -	BUILD_BUG_ON(sizeof(conf.key) < WLAN_KEY_LEN_TKIP); -	BUILD_BUG_ON(sizeof(conf.key) < sizeof(status->gtk[0].key)); +	BUILD_BUG_ON(WOWLAN_KEY_MAX_SIZE < WLAN_KEY_LEN_CCMP); +	BUILD_BUG_ON(WOWLAN_KEY_MAX_SIZE < WLAN_KEY_LEN_GCMP_256); +	BUILD_BUG_ON(WOWLAN_KEY_MAX_SIZE < WLAN_KEY_LEN_TKIP); +	BUILD_BUG_ON(WOWLAN_KEY_MAX_SIZE < sizeof(status->gtk[0].key));  	switch (gtk_cipher) {  	case WLAN_CIPHER_SUITE_CCMP:  	case WLAN_CIPHER_SUITE_GCMP: -		conf.conf.keylen = WLAN_KEY_LEN_CCMP; +		conf->keylen = WLAN_KEY_LEN_CCMP;  		break;  	case WLAN_CIPHER_SUITE_GCMP_256: -		conf.conf.keylen = WLAN_KEY_LEN_GCMP_256; +		conf->keylen = WLAN_KEY_LEN_GCMP_256;  		break;  	case WLAN_CIPHER_SUITE_TKIP: -		conf.conf.keylen = WLAN_KEY_LEN_TKIP; +		conf->keylen = WLAN_KEY_LEN_TKIP;  		break;  	default:  		WARN_ON(1); @@ -2181,16 +1987,22 @@ static bool iwl_mvm_gtk_rekey(struct iwl_wowlan_status_data *status,  		if (!status->gtk[i].len)  			continue; -		conf.conf.keyidx = status->gtk[i].id; +		conf->keyidx = status->gtk[i].id;  		IWL_DEBUG_WOWLAN(mvm,  				 "Received from FW GTK cipher %d, key index %d\n", -				 conf.conf.cipher, conf.conf.keyidx); -		memcpy(conf.conf.key, status->gtk[i].key, +				 conf->cipher, conf->keyidx); +		memcpy(conf->key, status->gtk[i].key,  		       sizeof(status->gtk[i].key)); +		memcpy(key_data, status->gtk[i].key, sizeof(status->gtk[i].key)); -		key = ieee80211_gtk_rekey_add(vif, &conf.conf, link_id); -		if (IS_ERR(key)) +		key = ieee80211_gtk_rekey_add(vif, status->gtk[i].id, key_data, +					      sizeof(key_data), link_id); +		if (IS_ERR(key)) { +			/* FW may send also the old keys */ +			if (PTR_ERR(key) == -EALREADY) +				continue;  			return false; +		}  		for (j = 0; j < ARRAY_SIZE(status->gtk_seq); j++) {  			if (!status->gtk_seq[j].valid || @@ -2210,55 +2022,66 @@ iwl_mvm_d3_igtk_bigtk_rekey_add(struct iwl_wowlan_status_data *status,  				struct ieee80211_vif *vif, u32 cipher,  				struct iwl_multicast_key_data *key_data)  { +	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); +	DEFINE_RAW_FLEX(struct ieee80211_key_conf, conf, key, +			WOWLAN_KEY_MAX_SIZE);  	struct ieee80211_key_conf *key_config; -	struct { -		struct ieee80211_key_conf conf; -		u8 key[WOWLAN_KEY_MAX_SIZE]; -	} conf = { -		.conf.cipher = cipher, -		.conf.keyidx = key_data->id, -	};  	struct ieee80211_key_seq seq;  	int link_id = vif->active_links ? __ffs(vif->active_links) : -1; +	u8 key[WOWLAN_KEY_MAX_SIZE]; +	s8 keyidx = key_data->id; + +	conf->cipher = cipher; +	conf->keyidx = keyidx;  	if (!key_data->len)  		return true; -	iwl_mvm_d3_set_igtk_bigtk_ipn(key_data, &seq, conf.conf.cipher); +	iwl_mvm_d3_set_igtk_bigtk_ipn(key_data, &seq, conf->cipher);  	switch (cipher) {  	case WLAN_CIPHER_SUITE_BIP_GMAC_128: -		conf.conf.keylen = WLAN_KEY_LEN_BIP_GMAC_128; +		conf->keylen = WLAN_KEY_LEN_BIP_GMAC_128;  		break;  	case WLAN_CIPHER_SUITE_BIP_GMAC_256: -		conf.conf.keylen = WLAN_KEY_LEN_BIP_GMAC_256; +		conf->keylen = WLAN_KEY_LEN_BIP_GMAC_256;  		break;  	case WLAN_CIPHER_SUITE_AES_CMAC: -		conf.conf.keylen = WLAN_KEY_LEN_AES_CMAC; +		conf->keylen = WLAN_KEY_LEN_AES_CMAC;  		break;  	case WLAN_CIPHER_SUITE_BIP_CMAC_256: -		conf.conf.keylen = WLAN_KEY_LEN_BIP_CMAC_256; +		conf->keylen = WLAN_KEY_LEN_BIP_CMAC_256;  		break;  	default:  		WARN_ON(1);  	} -	BUILD_BUG_ON(sizeof(conf.key) < sizeof(key_data->key)); -	memcpy(conf.conf.key, key_data->key, conf.conf.keylen); +	BUILD_BUG_ON(WOWLAN_KEY_MAX_SIZE < sizeof(key_data->key)); +	memcpy(conf->key, key_data->key, conf->keylen); -	key_config = ieee80211_gtk_rekey_add(vif, &conf.conf, link_id); -	if (IS_ERR(key_config)) -		return false; +	memcpy(key, key_data->key, sizeof(key_data->key)); + +	key_config = ieee80211_gtk_rekey_add(vif, keyidx, key, sizeof(key), +					     link_id); +	if (IS_ERR(key_config)) { +		/* FW may send also the old keys */ +		return PTR_ERR(key_config) == -EALREADY; +	}  	ieee80211_set_key_rx_seq(key_config, 0, &seq); -	if (key_config->keyidx == 4 || key_config->keyidx == 5) { -		struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); +	if (keyidx == 4 || keyidx == 5) {  		struct iwl_mvm_vif_link_info *mvm_link;  		link_id = link_id < 0 ? 0 : link_id;  		mvm_link = mvmvif->link[link_id]; +		if (mvm_link->igtk) +			mvm_link->igtk->hw_key_idx = STA_KEY_IDX_INVALID;  		mvm_link->igtk = key_config;  	} +	if (vif->type == NL80211_IFTYPE_STATION && (keyidx == 6 || keyidx == 7)) +		rcu_assign_pointer(mvmvif->bcn_prot.keys[keyidx - 6], +				   key_config); +  	return true;  } @@ -2345,9 +2168,6 @@ static bool iwl_mvm_setup_connection_keep(struct iwl_mvm *mvm,  				return false;  		} -		if (!iwl_mvm_mlo_gtk_rekey(status, vif, mvm)) -			return false; -  		ieee80211_gtk_rekey_notify(vif, vif->bss_conf.bssid,  					   (void *)&replay_ctr, GFP_KERNEL);  	} @@ -2377,6 +2197,7 @@ static void iwl_mvm_convert_gtk_v2(struct iwl_wowlan_status_data *status,  	status->gtk[0].len = data->key_len;  	status->gtk[0].flags = data->key_flags; +	status->gtk[0].id = status->gtk[0].flags & IWL_WOWLAN_GTK_IDX_MASK;  	memcpy(status->gtk[0].key, data->key, sizeof(data->key)); @@ -2476,22 +2297,52 @@ static void iwl_mvm_convert_bigtk(struct iwl_wowlan_status_data *status,  static void iwl_mvm_parse_wowlan_info_notif(struct iwl_mvm *mvm,  					    struct iwl_wowlan_info_notif *data,  					    struct iwl_wowlan_status_data *status, -					    u32 len, bool has_mlo_keys) +					    u32 len)  { -	u32 i; -	u32 expected_len = sizeof(*data); +	if (IWL_FW_CHECK(mvm, data->num_mlo_link_keys, +			 "MLO is not supported, shouldn't receive MLO keys\n")) +		return; -	if (!data) { -		IWL_ERR(mvm, "iwl_wowlan_info_notif data is NULL\n"); +	if (len < sizeof(*data)) { +		IWL_ERR(mvm, "Invalid WoWLAN info notification!\n");  		status = NULL;  		return;  	} -	if (has_mlo_keys) -		expected_len += (data->num_mlo_link_keys * -				 sizeof(status->mlo_keys[0])); +	if (mvm->fast_resume) +		return; -	if (len < expected_len) { +	iwl_mvm_convert_key_counters_v5(status, &data->gtk[0].sc); +	iwl_mvm_convert_gtk_v3(status, data->gtk); +	iwl_mvm_convert_igtk(status, &data->igtk[0]); +	iwl_mvm_convert_bigtk(status, data->bigtk); +	status->replay_ctr = le64_to_cpu(data->replay_ctr); +	status->pattern_number = le16_to_cpu(data->pattern_number); +	status->tid_offloaded_tx = data->tid_offloaded_tx; +	if (IWL_FW_CHECK(mvm, +			 data->tid_offloaded_tx >= +			 ARRAY_SIZE(status->qos_seq_ctr), +			 "tid_offloaded_tx is out of bound %d\n", +			 data->tid_offloaded_tx)) +		data->tid_offloaded_tx = 0; +	status->qos_seq_ctr[data->tid_offloaded_tx] = +		le16_to_cpu(data->qos_seq_ctr); +	status->wakeup_reasons = le32_to_cpu(data->wakeup_reasons); +	status->num_of_gtk_rekeys = +		le32_to_cpu(data->num_of_gtk_rekeys); +	status->received_beacons = le32_to_cpu(data->received_beacons); +	status->tid_tear_down = data->tid_tear_down; +} + +static void +iwl_mvm_parse_wowlan_info_notif_v3(struct iwl_mvm *mvm, +				   struct iwl_wowlan_info_notif_v3 *data, +				   struct iwl_wowlan_status_data *status, +				   u32 len) +{ +	u32 i; + +	if (len < sizeof(*data)) {  		IWL_ERR(mvm, "Invalid WoWLAN info notification!\n");  		status = NULL;  		return; @@ -2514,33 +2365,16 @@ static void iwl_mvm_parse_wowlan_info_notif(struct iwl_mvm *mvm,  		le32_to_cpu(data->num_of_gtk_rekeys);  	status->received_beacons = le32_to_cpu(data->received_beacons);  	status->tid_tear_down = data->tid_tear_down; - -	if (has_mlo_keys && data->num_mlo_link_keys) { -		status->num_mlo_keys = data->num_mlo_link_keys; -		if (IWL_FW_CHECK(mvm, -				 status->num_mlo_keys > WOWLAN_MAX_MLO_KEYS, -				 "Too many mlo keys: %d, max %d\n", -				 status->num_mlo_keys, WOWLAN_MAX_MLO_KEYS)) -			status->num_mlo_keys = WOWLAN_MAX_MLO_KEYS; -		memcpy(status->mlo_keys, data->mlo_gtks, -		       status->num_mlo_keys * sizeof(status->mlo_keys[0])); -	}  }  static void -iwl_mvm_parse_wowlan_info_notif_v2(struct iwl_mvm *mvm, -				   struct iwl_wowlan_info_notif_v2 *data, +iwl_mvm_parse_wowlan_info_notif_v1(struct iwl_mvm *mvm, +				   struct iwl_wowlan_info_notif_v1 *data,  				   struct iwl_wowlan_status_data *status,  				   u32 len)  {  	u32 i; -	if (!data) { -		IWL_ERR(mvm, "iwl_wowlan_info_notif data is NULL\n"); -		status = NULL; -		return; -	} -  	if (len < sizeof(*data)) {  		IWL_ERR(mvm, "Invalid WoWLAN info notification!\n");  		status = NULL; @@ -2620,8 +2454,6 @@ iwl_mvm_parse_wowlan_status_common_ ## _ver(struct iwl_mvm *mvm,	\  iwl_mvm_parse_wowlan_status_common(v6)  iwl_mvm_parse_wowlan_status_common(v7) -iwl_mvm_parse_wowlan_status_common(v9) -iwl_mvm_parse_wowlan_status_common(v12)  static struct iwl_wowlan_status_data *  iwl_mvm_send_wowlan_get_status(struct iwl_mvm *mvm, u8 sta_id) @@ -2677,7 +2509,8 @@ iwl_mvm_send_wowlan_get_status(struct iwl_mvm *mvm, u8 sta_id)  		       v6->gtk.tkip_mic_key,  		       sizeof(v6->gtk.tkip_mic_key)); -		iwl_mvm_convert_key_counters(status, &v6->gtk.rsc.all_tsc_rsc); +		iwl_mvm_convert_key_counters(status, &v6->gtk.rsc.all_tsc_rsc, +					     v6->gtk.key_index);  		/* hardcode the key length to 16 since v6 only supports 16 */  		status->gtk[0].len = 16; @@ -2688,6 +2521,7 @@ iwl_mvm_send_wowlan_get_status(struct iwl_mvm *mvm, u8 sta_id)  		 * currently used key.  		 */  		status->gtk[0].flags = v6->gtk.key_index | BIT(7); +		status->gtk[0].id = v6->gtk.key_index;  	} else if (notif_ver == 7) {  		struct iwl_wowlan_status_v7 *v7 = (void *)cmd.resp_pkt->data; @@ -2695,36 +2529,10 @@ iwl_mvm_send_wowlan_get_status(struct iwl_mvm *mvm, u8 sta_id)  		if (!status)  			goto out_free_resp; -		iwl_mvm_convert_key_counters(status, &v7->gtk[0].rsc.all_tsc_rsc); +		iwl_mvm_convert_key_counters(status, &v7->gtk[0].rsc.all_tsc_rsc, +					     v7->gtk[0].key_flags & IWL_WOWLAN_GTK_IDX_MASK);  		iwl_mvm_convert_gtk_v2(status, &v7->gtk[0]);  		iwl_mvm_convert_igtk(status, &v7->igtk[0]); -	} else if (notif_ver == 9 || notif_ver == 10 || notif_ver == 11) { -		struct iwl_wowlan_status_v9 *v9 = (void *)cmd.resp_pkt->data; - -		/* these three command versions have same layout and size, the -		 * difference is only in a few not used (reserved) fields. -		 */ -		status = iwl_mvm_parse_wowlan_status_common_v9(mvm, v9, len); -		if (!status) -			goto out_free_resp; - -		iwl_mvm_convert_key_counters(status, &v9->gtk[0].rsc.all_tsc_rsc); -		iwl_mvm_convert_gtk_v2(status, &v9->gtk[0]); -		iwl_mvm_convert_igtk(status, &v9->igtk[0]); - -		status->tid_tear_down = v9->tid_tear_down; -	} else if (notif_ver == 12) { -		struct iwl_wowlan_status_v12 *v12 = (void *)cmd.resp_pkt->data; - -		status = iwl_mvm_parse_wowlan_status_common_v12(mvm, v12, len); -		if (!status) -			goto out_free_resp; - -		iwl_mvm_convert_key_counters_v5(status, &v12->gtk[0].sc); -		iwl_mvm_convert_gtk_v3(status, v12->gtk); -		iwl_mvm_convert_igtk(status, &v12->igtk[0]); - -		status->tid_tear_down = v12->tid_tear_down;  	} else {  		IWL_ERR(mvm,  			"Firmware advertises unknown WoWLAN status response %d!\n", @@ -2748,6 +2556,10 @@ static bool iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm,  	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);  	int link_id = vif->active_links ? __ffs(vif->active_links) : 0;  	struct iwl_mvm_vif_link_info *mvm_link = mvmvif->link[link_id]; +	int wowlan_info_ver = iwl_fw_lookup_notif_ver(mvm->fw, +						      PROT_OFFLOAD_GROUP, +						      WOWLAN_INFO_NOTIFICATION, +						      IWL_FW_CMD_VER_UNKNOWN);  	if (WARN_ON(!mvm_link))  		goto out_unlock; @@ -2762,14 +2574,17 @@ static bool iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm,  	if (!mvm_ap_sta)  		goto out_unlock; -	for (i = 0; i < IWL_MAX_TID_COUNT; i++) { -		u16 seq = status->qos_seq_ctr[i]; -		/* firmware stores last-used value, we store next value */ -		seq += 0x10; -		mvm_ap_sta->tid_data[i].seq_number = seq; +	/* firmware stores last-used value, we store next value */ +	if (wowlan_info_ver >= 5) { +		mvm_ap_sta->tid_data[status->tid_offloaded_tx].seq_number = +			status->qos_seq_ctr[status->tid_offloaded_tx] + 0x10; +	} else { +		for (i = 0; i < IWL_MAX_TID_COUNT; i++) +			mvm_ap_sta->tid_data[i].seq_number = +				status->qos_seq_ctr[i] + 0x10;  	} -	if (mvm->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_22000) { +	if (mvm->trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_22000) {  		i = mvm->offload_tid;  		iwl_trans_set_q_ptrs(mvm->trans,  				     mvm_ap_sta->tid_data[i].txq_id, @@ -2873,6 +2688,7 @@ static void iwl_mvm_query_set_freqs(struct iwl_mvm *mvm,  				    int idx)  {  	int i; +	int n_channels = 0;  	if (fw_has_api(&mvm->fw->ucode_capa,  		       IWL_UCODE_TLV_API_SCAN_OFFLOAD_CHANS)) { @@ -2881,7 +2697,7 @@ static void iwl_mvm_query_set_freqs(struct iwl_mvm *mvm,  		for (i = 0; i < SCAN_OFFLOAD_MATCHING_CHANNELS_LEN * 8; i++)  			if (matches[idx].matching_channels[i / 8] & (BIT(i % 8))) -				match->channels[match->n_channels++] = +				match->channels[n_channels++] =  					mvm->nd_channels[i]->center_freq;  	} else {  		struct iwl_scan_offload_profile_match_v1 *matches = @@ -2889,9 +2705,11 @@ static void iwl_mvm_query_set_freqs(struct iwl_mvm *mvm,  		for (i = 0; i < SCAN_OFFLOAD_MATCHING_CHANNELS_LEN_V1 * 8; i++)  			if (matches[idx].matching_channels[i / 8] & (BIT(i % 8))) -				match->channels[match->n_channels++] = +				match->channels[n_channels++] =  					mvm->nd_channels[i]->center_freq;  	} +	/* We may have ended up with fewer channels than we allocated. */ +	match->n_channels = n_channels;  }  /** @@ -2972,6 +2790,8 @@ static void iwl_mvm_query_netdetect_reasons(struct iwl_mvm *mvm,  			     GFP_KERNEL);  	if (!net_detect || !n_matches)  		goto out_report_nd; +	net_detect->n_matches = n_matches; +	n_matches = 0;  	for_each_set_bit(i, &matched_profiles, mvm->n_nd_match_sets) {  		struct cfg80211_wowlan_nd_match *match; @@ -2985,8 +2805,9 @@ static void iwl_mvm_query_netdetect_reasons(struct iwl_mvm *mvm,  				GFP_KERNEL);  		if (!match)  			goto out_report_nd; +		match->n_channels = n_channels; -		net_detect->matches[net_detect->n_matches++] = match; +		net_detect->matches[n_matches++] = match;  		/* We inverted the order of the SSIDs in the scan  		 * request, so invert the index here. @@ -3001,6 +2822,8 @@ static void iwl_mvm_query_netdetect_reasons(struct iwl_mvm *mvm,  		iwl_mvm_query_set_freqs(mvm, d3_data->nd_results, match, i);  	} +	/* We may have fewer matches than we allocated. */ +	net_detect->n_matches = n_matches;  out_report_nd:  	wakeup.net_detect = net_detect; @@ -3028,55 +2851,50 @@ static void iwl_mvm_d3_disconnect_iter(void *data, u8 *mac,  		ieee80211_resume_disconnect(vif);  } -static bool iwl_mvm_rt_status(struct iwl_trans *trans, u32 base, u32 *err_id) -{ -	struct error_table_start { -		/* cf. struct iwl_error_event_table */ -		u32 valid; -		__le32 err_id; -	} err_info; - -	if (!base) -		return false; - -	iwl_trans_read_mem_bytes(trans, base, -				 &err_info, sizeof(err_info)); -	if (err_info.valid && err_id) -		*err_id = le32_to_cpu(err_info.err_id); - -	return !!err_info.valid; -} +enum rt_status { +	FW_ALIVE, +	FW_NEEDS_RESET, +	FW_ERROR, +}; -static bool iwl_mvm_check_rt_status(struct iwl_mvm *mvm, -				   struct ieee80211_vif *vif) +static enum rt_status iwl_mvm_check_rt_status(struct iwl_mvm *mvm, +					      struct ieee80211_vif *vif)  {  	u32 err_id;  	/* check for lmac1 error */ -	if (iwl_mvm_rt_status(mvm->trans, -			      mvm->trans->dbg.lmac_error_event_table[0], -			      &err_id)) { -		if (err_id == RF_KILL_INDICATOR_FOR_WOWLAN && vif) { -			struct cfg80211_wowlan_wakeup wakeup = { -				.rfkill_release = true, -			}; -			ieee80211_report_wowlan_wakeup(vif, &wakeup, -						       GFP_KERNEL); +	if (iwl_fwrt_read_err_table(mvm->trans, +				    mvm->trans->dbg.lmac_error_event_table[0], +				    &err_id)) { +		if (err_id == RF_KILL_INDICATOR_FOR_WOWLAN) { +			IWL_WARN(mvm, "Rfkill was toggled during suspend\n"); +			if (vif) { +				struct cfg80211_wowlan_wakeup wakeup = { +					.rfkill_release = true, +				}; + +				ieee80211_report_wowlan_wakeup(vif, &wakeup, +							       GFP_KERNEL); +			} + +			return FW_NEEDS_RESET;  		} -		return true; +		return FW_ERROR;  	}  	/* check if we have lmac2 set and check for error */ -	if (iwl_mvm_rt_status(mvm->trans, -			      mvm->trans->dbg.lmac_error_event_table[1], NULL)) -		return true; +	if (iwl_fwrt_read_err_table(mvm->trans, +				    mvm->trans->dbg.lmac_error_event_table[1], +				    NULL)) +		return FW_ERROR;  	/* check for umac error */ -	if (iwl_mvm_rt_status(mvm->trans, -			      mvm->trans->dbg.umac_error_event_table, NULL)) -		return true; +	if (iwl_fwrt_read_err_table(mvm->trans, +				    mvm->trans->dbg.umac_error_event_table, +				    NULL)) +		return FW_ERROR; -	return false; +	return FW_ALIVE;  }  /* @@ -3094,7 +2912,7 @@ iwl_mvm_choose_query_wakeup_reasons(struct iwl_mvm *mvm,  	/* if FW uses status notification, status shouldn't be NULL here */  	if (!d3_data->status) {  		struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); -		u8 sta_id = mvm->net_detect ? IWL_MVM_INVALID_STA : +		u8 sta_id = mvm->net_detect ? IWL_INVALID_STA :  					      mvmvif->deflink.ap_sta_id;  		/* bug - FW with MLO has status notification */ @@ -3241,38 +3059,30 @@ static bool iwl_mvm_wait_d3_notif(struct iwl_notif_wait_data *notif_wait,  			break;  		} -		if (wowlan_info_ver < 2) { +		if (wowlan_info_ver == 1) {  			struct iwl_wowlan_info_notif_v1 *notif_v1 =  				(void *)pkt->data; -			struct iwl_wowlan_info_notif_v2 *notif_v2; - -			notif_v2 = kmemdup(notif_v1, sizeof(*notif_v2), GFP_ATOMIC); - -			if (!notif_v2) -				return false; -			notif_v2->tid_tear_down = notif_v1->tid_tear_down; -			notif_v2->station_id = notif_v1->station_id; -			memset_after(notif_v2, 0, station_id); -			iwl_mvm_parse_wowlan_info_notif_v2(mvm, notif_v2, +			iwl_mvm_parse_wowlan_info_notif_v1(mvm, notif_v1,  							   d3_data->status,  							   len); -			kfree(notif_v2); - -		} else if (wowlan_info_ver == 2) { -			struct iwl_wowlan_info_notif_v2 *notif_v2 = +		} else if (wowlan_info_ver == 3) { +			struct iwl_wowlan_info_notif_v3 *notif =  				(void *)pkt->data; -			iwl_mvm_parse_wowlan_info_notif_v2(mvm, notif_v2, -							   d3_data->status, -							   len); -		} else { +			iwl_mvm_parse_wowlan_info_notif_v3(mvm, notif, +							   d3_data->status, len); +		} else if (wowlan_info_ver == 5) {  			struct iwl_wowlan_info_notif *notif =  				(void *)pkt->data;  			iwl_mvm_parse_wowlan_info_notif(mvm, notif, -							d3_data->status, len, -							wowlan_info_ver > 3); +							d3_data->status, len); +		} else { +			IWL_FW_CHECK(mvm, 1, +				     "Firmware advertises unknown WoWLAN info notification %d!\n", +				     wowlan_info_ver); +			return false;  		}  		d3_data->notif_received |= IWL_D3_NOTIF_WOWLAN_INFO; @@ -3323,7 +3133,7 @@ static bool iwl_mvm_wait_d3_notif(struct iwl_notif_wait_data *notif_wait,  		break;  	}  	case WIDE_ID(PROT_OFFLOAD_GROUP, D3_END_NOTIFICATION): { -		struct iwl_mvm_d3_end_notif *notif = (void *)pkt->data; +		struct iwl_d3_end_notif *notif = (void *)pkt->data;  		d3_data->d3_end_flags = __le32_to_cpu(notif->flags);  		d3_data->notif_received |= IWL_D3_NOTIF_D3_END_NOTIF; @@ -3342,9 +3152,9 @@ static int iwl_mvm_resume_firmware(struct iwl_mvm *mvm, bool test)  	int ret;  	enum iwl_d3_status d3_status;  	struct iwl_host_cmd cmd = { -			.id = D0I3_END_CMD, -			.flags = CMD_WANT_SKB | CMD_SEND_IN_D3, -		}; +		.id = D0I3_END_CMD, +		.flags = CMD_WANT_SKB, +	};  	bool reset = fw_has_capa(&mvm->fw->ucode_capa,  				 IWL_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG); @@ -3362,7 +3172,7 @@ static int iwl_mvm_resume_firmware(struct iwl_mvm *mvm, bool test)  	 * AX210 and above don't need the command since they have  	 * the doorbell interrupt.  	 */ -	if (mvm->trans->trans_cfg->device_family <= IWL_DEVICE_FAMILY_22000 && +	if (mvm->trans->mac_cfg->device_family <= IWL_DEVICE_FAMILY_22000 &&  	    fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_D0I3_END_FIRST)) {  		ret = iwl_mvm_send_cmd(mvm, &cmd);  		if (ret < 0) @@ -3439,6 +3249,7 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test)  	bool d0i3_first = fw_has_capa(&mvm->fw->ucode_capa,  				      IWL_UCODE_TLV_CAPA_D0I3_END_FIRST);  	bool resume_notif_based = iwl_mvm_d3_resume_notif_based(mvm); +	enum rt_status rt_status;  	bool keep = false;  	mutex_lock(&mvm->mutex); @@ -3462,13 +3273,19 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test)  	iwl_fw_dbg_read_d3_debug_data(&mvm->fwrt); -	if (iwl_mvm_check_rt_status(mvm, vif)) { +	rt_status = iwl_mvm_check_rt_status(mvm, vif); +	if (rt_status != FW_ALIVE) {  		set_bit(STATUS_FW_ERROR, &mvm->trans->status); -		iwl_mvm_dump_nic_error_log(mvm); -		iwl_dbg_tlv_time_point(&mvm->fwrt, -				       IWL_FW_INI_TIME_POINT_FW_ASSERT, NULL); -		iwl_fw_dbg_collect_desc(&mvm->fwrt, &iwl_dump_desc_assert, -					false, 0); +		if (rt_status == FW_ERROR) { +			IWL_ERR(mvm, "FW Error occurred during suspend. Restarting.\n"); +			iwl_mvm_dump_nic_error_log(mvm); +			iwl_dbg_tlv_time_point(&mvm->fwrt, +					       IWL_FW_INI_TIME_POINT_FW_ASSERT, +					       NULL); +			iwl_fw_dbg_collect_desc(&mvm->fwrt, +						&iwl_dump_desc_assert, +						false, 0); +		}  		ret = 1;  		goto err;  	} @@ -3492,9 +3309,6 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test)  	iwl_mvm_unblock_esr(mvm, vif, IWL_MVM_ESR_BLOCKED_WOWLAN); -	/* after the successful handshake, we're out of D3 */ -	mvm->trans->system_pm_mode = IWL_PLAT_PM_MODE_DISABLED; -  	/* when reset is required we can't send these following commands */  	if (d3_data.d3_end_flags & IWL_D0I3_RESET_REQUIRE)  		goto query_wakeup_reasons; @@ -3567,9 +3381,6 @@ out:  	 */  	set_bit(IWL_MVM_STATUS_HW_RESTART_REQUESTED, &mvm->status); -	/* regardless of what happened, we're now out of D3 */ -	mvm->trans->system_pm_mode = IWL_PLAT_PM_MODE_DISABLED; -  	return 1;  } @@ -3607,15 +3418,12 @@ void iwl_mvm_fast_suspend(struct iwl_mvm *mvm)  	set_bit(IWL_MVM_STATUS_IN_D3, &mvm->status);  	WARN_ON(iwl_mvm_power_update_device(mvm)); -	mvm->trans->system_pm_mode = IWL_PLAT_PM_MODE_D3; -	ret = iwl_mvm_send_cmd_pdu(mvm, D3_CONFIG_CMD, CMD_SEND_IN_D3, +	ret = iwl_mvm_send_cmd_pdu(mvm, D3_CONFIG_CMD, 0,  				   sizeof(d3_cfg_cmd_data), &d3_cfg_cmd_data);  	if (ret)  		IWL_ERR(mvm,  			"fast suspend: couldn't send D3_CONFIG_CMD %d\n", ret); -	WARN_ON(iwl_mvm_power_update_mac(mvm)); -  	ret = iwl_trans_d3_suspend(mvm->trans, false, false);  	if (ret)  		IWL_ERR(mvm, "fast suspend: trans_d3_suspend failed %d\n", ret); @@ -3627,6 +3435,7 @@ int iwl_mvm_fast_resume(struct iwl_mvm *mvm)  		.notif_expected =  			IWL_D3_NOTIF_D3_END_NOTIF,  	}; +	enum rt_status rt_status;  	int ret;  	lockdep_assert_held(&mvm->mutex); @@ -3636,22 +3445,35 @@ int iwl_mvm_fast_resume(struct iwl_mvm *mvm)  	mvm->last_reset_or_resume_time_jiffies = jiffies;  	iwl_fw_dbg_read_d3_debug_data(&mvm->fwrt); -	if (iwl_mvm_check_rt_status(mvm, NULL)) { +	rt_status = iwl_mvm_check_rt_status(mvm, NULL); +	if (rt_status != FW_ALIVE) {  		set_bit(STATUS_FW_ERROR, &mvm->trans->status); -		iwl_mvm_dump_nic_error_log(mvm); -		iwl_dbg_tlv_time_point(&mvm->fwrt, -				       IWL_FW_INI_TIME_POINT_FW_ASSERT, NULL); -		iwl_fw_dbg_collect_desc(&mvm->fwrt, &iwl_dump_desc_assert, -					false, 0); -		return -ENODEV; +		if (rt_status == FW_ERROR) { +			IWL_ERR(mvm, +				"iwl_mvm_check_rt_status failed, device is gone during suspend\n"); +			iwl_mvm_dump_nic_error_log(mvm); +			iwl_dbg_tlv_time_point(&mvm->fwrt, +					       IWL_FW_INI_TIME_POINT_FW_ASSERT, +					       NULL); +			iwl_fw_dbg_collect_desc(&mvm->fwrt, +						&iwl_dump_desc_assert, +						false, 0); +		} +		mvm->trans->state = IWL_TRANS_NO_FW; +		ret = -ENODEV; + +		goto out;  	}  	ret = iwl_mvm_d3_notif_wait(mvm, &d3_data); -	clear_bit(IWL_MVM_STATUS_IN_D3, &mvm->status); -	mvm->trans->system_pm_mode = IWL_PLAT_PM_MODE_DISABLED; -	mvm->fast_resume = false; -	if (ret) +	if (ret) {  		IWL_ERR(mvm, "Couldn't get the d3 notif %d\n", ret); +		mvm->trans->state = IWL_TRANS_NO_FW; +	} + +out: +	clear_bit(IWL_MVM_STATUS_IN_D3, &mvm->status); +	mvm->fast_resume = false;  	return ret;  } @@ -3780,7 +3602,6 @@ static int iwl_mvm_d3_test_release(struct inode *inode, struct file *file)  }  const struct file_operations iwl_dbgfs_d3_test_ops = { -	.llseek = no_llseek,  	.open = iwl_mvm_d3_test_open,  	.read = iwl_mvm_d3_test_read,  	.release = iwl_mvm_d3_test_release, diff --git a/sys/contrib/dev/iwlwifi/mvm/debugfs-vif.c b/sys/contrib/dev/iwlwifi/mvm/debugfs-vif.c index 0b3bc62f39a7..f1303440d3dd 100644 --- a/sys/contrib/dev/iwlwifi/mvm/debugfs-vif.c +++ b/sys/contrib/dev/iwlwifi/mvm/debugfs-vif.c @@ -224,7 +224,7 @@ static ssize_t iwl_dbgfs_mac_params_read(struct file *file,  				 mvmvif->deflink.queue_params[i].uapsd);  	if (vif->type == NL80211_IFTYPE_STATION && -	    ap_sta_id != IWL_MVM_INVALID_STA) { +	    ap_sta_id != IWL_INVALID_STA) {  		struct iwl_mvm_sta *mvm_sta;  		mvm_sta = iwl_mvm_sta_from_staid_protected(mvm, ap_sta_id); @@ -466,11 +466,13 @@ static ssize_t iwl_dbgfs_os_device_timediff_read(struct file *file,  	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);  } -static ssize_t iwl_dbgfs_low_latency_write(struct ieee80211_vif *vif, char *buf, -					   size_t count, loff_t *ppos) +static ssize_t +iwl_dbgfs_low_latency_write_handle(struct wiphy *wiphy, struct file *file, +				   char *buf, size_t count, void *data)  { -	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); -	struct iwl_mvm *mvm = mvmvif->mvm; +	struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); +	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); +	struct ieee80211_vif *vif = data;  	u8 value;  	int ret; @@ -487,12 +489,28 @@ static ssize_t iwl_dbgfs_low_latency_write(struct ieee80211_vif *vif, char *buf,  	return count;  } -static ssize_t -iwl_dbgfs_low_latency_force_write(struct ieee80211_vif *vif, char *buf, -				  size_t count, loff_t *ppos) +static ssize_t iwl_dbgfs_low_latency_write(struct file *file, +					   const char __user *user_buf, +					   size_t count, loff_t *ppos)  { +	struct ieee80211_vif *vif = file->private_data;  	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);  	struct iwl_mvm *mvm = mvmvif->mvm; +	char buf[10] = {}; + +	return wiphy_locked_debugfs_write(mvm->hw->wiphy, file, +					  buf, sizeof(buf), user_buf, count, +					  iwl_dbgfs_low_latency_write_handle, +					  vif); +} + +static ssize_t +iwl_dbgfs_low_latency_force_write_handle(struct wiphy *wiphy, struct file *file, +					 char *buf, size_t count, void *data) +{ +	struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); +	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); +	struct ieee80211_vif *vif = data;  	u8 value;  	int ret; @@ -520,6 +538,22 @@ iwl_dbgfs_low_latency_force_write(struct ieee80211_vif *vif, char *buf,  	return count;  } +static ssize_t +iwl_dbgfs_low_latency_force_write(struct file *file, +				  const char __user *user_buf, +				  size_t count, loff_t *ppos) +{ +	struct ieee80211_vif *vif = file->private_data; +	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); +	struct iwl_mvm *mvm = mvmvif->mvm; +	char buf[10] = {}; + +	return wiphy_locked_debugfs_write(mvm->hw->wiphy, file, +					  buf, sizeof(buf), user_buf, count, +					  iwl_dbgfs_low_latency_force_write_handle, +					  vif); +} +  static ssize_t iwl_dbgfs_low_latency_read(struct file *file,  					  char __user *user_buf,  					  size_t count, loff_t *ppos) @@ -838,8 +872,20 @@ MVM_DEBUGFS_READ_FILE_OPS(mac_params);  MVM_DEBUGFS_READ_FILE_OPS(tx_pwr_lmt);  MVM_DEBUGFS_READ_WRITE_FILE_OPS(pm_params, 32);  MVM_DEBUGFS_READ_WRITE_FILE_OPS(bf_params, 256); -MVM_DEBUGFS_READ_WRITE_FILE_OPS(low_latency, 10); -MVM_DEBUGFS_WRITE_FILE_OPS(low_latency_force, 10); + +static const struct file_operations iwl_dbgfs_low_latency_ops = { +	.write = iwl_dbgfs_low_latency_write, +	.read = iwl_dbgfs_low_latency_read, +	.open = simple_open, +	.llseek = generic_file_llseek, +}; + +static const struct file_operations iwl_dbgfs_low_latency_force_ops = { +	.write = iwl_dbgfs_low_latency_force_write, +	.open = simple_open, +	.llseek = generic_file_llseek, +}; +  MVM_DEBUGFS_READ_WRITE_FILE_OPS(uapsd_misbehaving, 20);  MVM_DEBUGFS_READ_WRITE_FILE_OPS(rx_phyinfo, 10);  MVM_DEBUGFS_READ_WRITE_FILE_OPS(quota_min, 32); diff --git a/sys/contrib/dev/iwlwifi/mvm/debugfs.c b/sys/contrib/dev/iwlwifi/mvm/debugfs.c index 24bcffe67235..eb8ae6d574fa 100644 --- a/sys/contrib/dev/iwlwifi/mvm/debugfs.c +++ b/sys/contrib/dev/iwlwifi/mvm/debugfs.c @@ -1,6 +1,6 @@  // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause  /* - * Copyright (C) 2012-2014, 2018-2023 Intel Corporation + * Copyright (C) 2012-2014, 2018-2023, 2025 Intel Corporation   * Copyright (C) 2013-2015 Intel Mobile Communications GmbH   * Copyright (C) 2016-2017 Intel Deutschland GmbH   */ @@ -16,6 +16,7 @@  #include "debugfs.h"  #include "iwl-modparams.h"  #include "iwl-drv.h" +#include "iwl-utils.h"  #include "fw/error-dump.h"  #include "fw/api/phy-ctxt.h" @@ -462,7 +463,6 @@ static ssize_t iwl_dbgfs_amsdu_len_write(struct ieee80211_link_sta *link_sta,  	if (amsdu_len) {  		mvm_link_sta->orig_amsdu_len = link_sta->agg.max_amsdu_len;  		link_sta->agg.max_amsdu_len = amsdu_len; -		link_sta->agg.max_amsdu_len = amsdu_len;  		for (i = 0; i < ARRAY_SIZE(link_sta->agg.max_tid_amsdu_len); i++)  			link_sta->agg.max_tid_amsdu_len[i] = amsdu_len;  	} else { @@ -537,47 +537,12 @@ static ssize_t iwl_dbgfs_disable_power_off_write(struct iwl_mvm *mvm, char *buf,  	return ret ?: count;  } -static ssize_t iwl_dbgfs_fw_ver_read(struct file *file, char __user *user_buf, -				     size_t count, loff_t *ppos) -{ -	struct iwl_mvm *mvm = file->private_data; -	char *buff, *pos, *endpos; -	static const size_t bufsz = 1024; -	int ret; - -	buff = kmalloc(bufsz, GFP_KERNEL); -	if (!buff) -		return -ENOMEM; - -	pos = buff; -	endpos = pos + bufsz; - -	pos += scnprintf(pos, endpos - pos, "FW id: %s\n", -			 mvm->fwrt.fw->fw_version); -	pos += scnprintf(pos, endpos - pos, "FW: %s\n", -			 mvm->fwrt.fw->human_readable); -	pos += scnprintf(pos, endpos - pos, "Device: %s\n", -			 mvm->fwrt.trans->name); -	pos += scnprintf(pos, endpos - pos, "Bus: %s\n", -#if defined(__linux__) -			 mvm->fwrt.dev->bus->name); -#elif defined(__FreeBSD__) -			"<bus>"); -#endif - -	ret = simple_read_from_buffer(user_buf, count, ppos, buff, pos - buff); -	kfree(buff); - -	return ret; -} -  static ssize_t iwl_dbgfs_tas_get_status_read(struct file *file,  					     char __user *user_buf,  					     size_t count, loff_t *ppos)  {  	struct iwl_mvm *mvm = file->private_data; -	struct iwl_mvm_tas_status_resp tas_rsp; -	struct iwl_mvm_tas_status_resp *rsp = &tas_rsp; +	struct iwl_tas_status_resp *rsp = NULL;  	static const size_t bufsz = 1024;  	char *buff, *pos, *endpos;  	const char * const tas_dis_reason[TAS_DISABLED_REASON_MAX] = { @@ -587,6 +552,8 @@ static ssize_t iwl_dbgfs_tas_get_status_read(struct file *file,  			"Due To SAR Limit Less Than 6 dBm",  		[TAS_DISABLED_REASON_INVALID] =  			"N/A", +		[TAS_DISABLED_DUE_TO_TABLE_SOURCE_INVALID] = +			"Due to table source invalid",  	};  	const char * const tas_current_status[TAS_DYNA_STATUS_MAX] = {  		[TAS_DYNA_INACTIVE] = "INACTIVE", @@ -613,6 +580,10 @@ static ssize_t iwl_dbgfs_tas_get_status_read(struct file *file,  	if (!iwl_mvm_firmware_running(mvm))  		return -ENODEV; +	if (iwl_fw_lookup_notif_ver(mvm->fw, DEBUG_GROUP, GET_TAS_STATUS, +				    0) != 3) +		return -EOPNOTSUPP; +  	mutex_lock(&mvm->mutex);  	ret = iwl_mvm_send_cmd(mvm, &hcmd);  	mutex_unlock(&mvm->mutex); @@ -629,23 +600,19 @@ static ssize_t iwl_dbgfs_tas_get_status_read(struct file *file,  	pos += scnprintf(pos, endpos - pos, "TAS Conclusion:\n");  	for (i = 0; i < rsp->in_dual_radio + 1; i++) { -		if (rsp->tas_status_mac[i].band != TAS_LMAC_BAND_INVALID && -		    rsp->tas_status_mac[i].dynamic_status & BIT(TAS_DYNA_ACTIVE)) { +		if (rsp->tas_status_mac[i].dynamic_status & +		    BIT(TAS_DYNA_ACTIVE)) {  			pos += scnprintf(pos, endpos - pos, "\tON for ");  			switch (rsp->tas_status_mac[i].band) { -			case TAS_LMAC_BAND_HB: +			case PHY_BAND_5:  				pos += scnprintf(pos, endpos - pos, "HB\n");  				break; -			case TAS_LMAC_BAND_LB: +			case PHY_BAND_24:  				pos += scnprintf(pos, endpos - pos, "LB\n");  				break; -			case TAS_LMAC_BAND_UHB: +			case PHY_BAND_6:  				pos += scnprintf(pos, endpos - pos, "UHB\n");  				break; -			case TAS_LMAC_BAND_INVALID: -				pos += scnprintf(pos, endpos - pos, -						 "INVALID BAND\n"); -				break;  			default:  				pos += scnprintf(pos, endpos - pos,  						 "Unsupported band (%d)\n", @@ -663,6 +630,14 @@ static ssize_t iwl_dbgfs_tas_get_status_read(struct file *file,  			 rsp->tas_fw_version);  	pos += scnprintf(pos, endpos - pos, "Is UHB enabled for USA?: %s\n",  			 rsp->is_uhb_for_usa_enable ? "True" : "False"); + +	if (fw_has_capa(&mvm->fw->ucode_capa, +			IWL_UCODE_TLV_CAPA_UHB_CANADA_TAS_SUPPORT)) +		pos += scnprintf(pos, endpos - pos, +				 "Is UHB enabled for CANADA?: %s\n", +				 rsp->uhb_allowed_flags & +				 TAS_UHB_ALLOWED_CANADA ? "True" : "False"); +  	pos += scnprintf(pos, endpos - pos, "Current MCC: 0x%x\n",  			 le16_to_cpu(rsp->curr_mcc)); @@ -691,20 +666,16 @@ static ssize_t iwl_dbgfs_tas_get_status_read(struct file *file,  		pos += scnprintf(pos, endpos - pos, "TAS status for ");  		switch (rsp->tas_status_mac[i].band) { -		case TAS_LMAC_BAND_HB: +		case PHY_BAND_5:  			pos += scnprintf(pos, endpos - pos, "High band\n");  			break; -		case TAS_LMAC_BAND_LB: +		case PHY_BAND_24:  			pos += scnprintf(pos, endpos - pos, "Low band\n");  			break; -		case TAS_LMAC_BAND_UHB: +		case PHY_BAND_6:  			pos += scnprintf(pos, endpos - pos,  					 "Ultra high band\n");  			break; -		case TAS_LMAC_BAND_INVALID: -			pos += scnprintf(pos, endpos - pos, -					 "INVALID band\n"); -			break;  		default:  			pos += scnprintf(pos, endpos - pos,  					 "Unsupported band (%d)\n", @@ -727,11 +698,9 @@ static ssize_t iwl_dbgfs_tas_get_status_read(struct file *file,  		pos += scnprintf(pos, endpos - pos, "Dynamic status:\n");  		dyn_status = (rsp->tas_status_mac[i].dynamic_status); -		for_each_set_bit(tmp, &dyn_status, sizeof(dyn_status)) { -			if (tmp >= 0 && tmp < TAS_DYNA_STATUS_MAX) -				pos += scnprintf(pos, endpos - pos, -						 "\t%s (%d)\n", -						 tas_current_status[tmp], tmp); +		for_each_set_bit(tmp, &dyn_status, TAS_DYNA_STATUS_MAX) { +			pos += scnprintf(pos, endpos - pos, "\t%s (%d)\n", +					 tas_current_status[tmp], tmp);  		}  		pos += scnprintf(pos, endpos - pos, @@ -1163,13 +1132,9 @@ static ssize_t iwl_dbgfs_fw_restart_write(struct iwl_mvm *mvm, char *buf,  	mutex_lock(&mvm->mutex); -	/* allow one more restart that we're provoking here */ -	if (mvm->fw_restart >= 0) -		mvm->fw_restart++; -  	if (count == 6 && !strcmp(buf, "nolog\n")) {  		set_bit(IWL_MVM_STATUS_SUPPRESS_ERROR_LOG_ONCE, &mvm->status); -		set_bit(STATUS_SUPPRESS_CMD_ERROR_ONCE, &mvm->trans->status); +		iwl_trans_suppress_cmd_error_once(mvm->trans);  	}  	/* take the return value to make compiler happy - it will fail anyway */ @@ -1312,7 +1277,7 @@ static ssize_t iwl_dbgfs_inject_packet_write(struct iwl_mvm *mvm,  		return -EIO;  	/* supporting only MQ RX */ -	if (!mvm->trans->trans_cfg->mq_rx_supported) +	if (!mvm->trans->mac_cfg->mq_rx_supported)  		return -EOPNOTSUPP;  	rxb._page = alloc_pages(GFP_ATOMIC, 0); @@ -1413,9 +1378,9 @@ static int _iwl_dbgfs_inject_beacon_ie(struct iwl_mvm *mvm, char *bin, int len)  		if (iwl_fw_lookup_cmd_ver(mvm->fw,  					  BEACON_TEMPLATE_CMD, 0) >= 14) { -			u32 offset = iwl_mvm_find_ie_offset(beacon->data, -							    WLAN_EID_S1G_TWT, -							    beacon->len); +			u32 offset = iwl_find_ie_offset(beacon->data, +							WLAN_EID_S1G_TWT, +							beacon->len);  			beacon_cmd.btwt_offset = cpu_to_le32(offset);  		} @@ -1499,29 +1464,20 @@ static ssize_t iwl_dbgfs_fw_dbg_conf_write(struct iwl_mvm *mvm,  	return ret ?: count;  } -static ssize_t iwl_dbgfs_fw_dbg_collect_write(struct iwl_mvm *mvm, -					      char *buf, size_t count, -					      loff_t *ppos) -{ -	if (count == 0) -		return 0; - -	iwl_dbg_tlv_time_point(&mvm->fwrt, IWL_FW_INI_TIME_POINT_USER_TRIGGER, -			       NULL); - -	iwl_fw_dbg_collect(&mvm->fwrt, FW_DBG_TRIGGER_USER, buf, -			   (count - 1), NULL); - -	return count; -} -  static ssize_t iwl_dbgfs_fw_dbg_clear_write(struct iwl_mvm *mvm,  					    char *buf, size_t count,  					    loff_t *ppos)  { -	if (mvm->trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_9000) +	if (mvm->trans->mac_cfg->device_family < IWL_DEVICE_FAMILY_9000)  		return -EOPNOTSUPP; +	/* +	 * If the firmware is not running, silently succeed since there is +	 * no data to clear. +	 */ +	if (!iwl_mvm_firmware_running(mvm)) +		return count; +  	mutex_lock(&mvm->mutex);  	iwl_fw_dbg_clear_monitor_buf(&mvm->fwrt);  	mutex_unlock(&mvm->mutex); @@ -1968,14 +1924,12 @@ MVM_DEBUGFS_READ_WRITE_FILE_OPS(disable_power_off, 64);  MVM_DEBUGFS_READ_FILE_OPS(fw_rx_stats);  MVM_DEBUGFS_READ_FILE_OPS(drv_rx_stats);  MVM_DEBUGFS_READ_FILE_OPS(fw_system_stats); -MVM_DEBUGFS_READ_FILE_OPS(fw_ver);  MVM_DEBUGFS_READ_FILE_OPS(phy_integration_ver);  MVM_DEBUGFS_READ_FILE_OPS(tas_get_status);  MVM_DEBUGFS_WRITE_FILE_OPS(fw_restart, 10);  MVM_DEBUGFS_WRITE_FILE_OPS(fw_nmi, 10);  MVM_DEBUGFS_READ_WRITE_FILE_OPS(scan_ant_rxchain, 8);  MVM_DEBUGFS_READ_WRITE_FILE_OPS(fw_dbg_conf, 8); -MVM_DEBUGFS_WRITE_FILE_OPS(fw_dbg_collect, 64);  MVM_DEBUGFS_WRITE_FILE_OPS(fw_dbg_clear, 64);  MVM_DEBUGFS_WRITE_FILE_OPS(dbg_time_point, 64);  MVM_DEBUGFS_WRITE_FILE_OPS(indirection_tbl, @@ -2168,7 +2122,6 @@ void iwl_mvm_dbgfs_register(struct iwl_mvm *mvm)  	MVM_DEBUGFS_ADD_FILE(force_ctkill, mvm->debugfs_dir, 0200);  	MVM_DEBUGFS_ADD_FILE(stations, mvm->debugfs_dir, 0400);  	MVM_DEBUGFS_ADD_FILE(disable_power_off, mvm->debugfs_dir, 0600); -	MVM_DEBUGFS_ADD_FILE(fw_ver, mvm->debugfs_dir, 0400);  	MVM_DEBUGFS_ADD_FILE(fw_rx_stats, mvm->debugfs_dir, 0400);  	MVM_DEBUGFS_ADD_FILE(drv_rx_stats, mvm->debugfs_dir, 0400);  	MVM_DEBUGFS_ADD_FILE(fw_system_stats, mvm->debugfs_dir, 0400); @@ -2177,7 +2130,6 @@ void iwl_mvm_dbgfs_register(struct iwl_mvm *mvm)  	MVM_DEBUGFS_ADD_FILE(scan_ant_rxchain, mvm->debugfs_dir, 0600);  	MVM_DEBUGFS_ADD_FILE(prph_reg, mvm->debugfs_dir, 0600);  	MVM_DEBUGFS_ADD_FILE(fw_dbg_conf, mvm->debugfs_dir, 0600); -	MVM_DEBUGFS_ADD_FILE(fw_dbg_collect, mvm->debugfs_dir, 0200);  	MVM_DEBUGFS_ADD_FILE(fw_dbg_clear, mvm->debugfs_dir, 0200);  	MVM_DEBUGFS_ADD_FILE(dbg_time_point, mvm->debugfs_dir, 0200);  	MVM_DEBUGFS_ADD_FILE(send_echo_cmd, mvm->debugfs_dir, 0200); diff --git a/sys/contrib/dev/iwlwifi/mvm/ftm-initiator.c b/sys/contrib/dev/iwlwifi/mvm/ftm-initiator.c index b0371acb98ca..83ae969db0da 100644 --- a/sys/contrib/dev/iwlwifi/mvm/ftm-initiator.c +++ b/sys/contrib/dev/iwlwifi/mvm/ftm-initiator.c @@ -1,7 +1,7 @@  // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause  /*   * Copyright (C) 2015-2017 Intel Deutschland GmbH - * Copyright (C) 2018-2024 Intel Corporation + * Copyright (C) 2018-2025 Intel Corporation   */  #include <linux/etherdevice.h>  #include <linux/math64.h> @@ -46,107 +46,6 @@ struct iwl_mvm_ftm_iter_data {  	u8 *tk;  }; -int iwl_mvm_ftm_add_pasn_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif, -			     u8 *addr, u32 cipher, u8 *tk, u32 tk_len, -			     u8 *hltk, u32 hltk_len) -{ -	struct iwl_mvm_ftm_pasn_entry *pasn = kzalloc(sizeof(*pasn), -						      GFP_KERNEL); -	u32 expected_tk_len; - -	lockdep_assert_held(&mvm->mutex); - -	if (!pasn) -		return -ENOBUFS; - -	iwl_mvm_ftm_remove_pasn_sta(mvm, addr); - -	pasn->cipher = iwl_mvm_cipher_to_location_cipher(cipher); - -	switch (pasn->cipher) { -	case IWL_LOCATION_CIPHER_CCMP_128: -	case IWL_LOCATION_CIPHER_GCMP_128: -		expected_tk_len = WLAN_KEY_LEN_CCMP; -		break; -	case IWL_LOCATION_CIPHER_GCMP_256: -		expected_tk_len = WLAN_KEY_LEN_GCMP_256; -		break; -	default: -		goto out; -	} - -	/* -	 * If associated to this AP and already have security context, -	 * the TK is already configured for this station, so it -	 * shouldn't be set again here. -	 */ -	if (vif->cfg.assoc) { -		struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); -		struct ieee80211_bss_conf *link_conf; -		unsigned int link_id; -		struct ieee80211_sta *sta; -		u8 sta_id; - -		rcu_read_lock(); -		for_each_vif_active_link(vif, link_conf, link_id) { -			if (memcmp(addr, link_conf->bssid, ETH_ALEN)) -				continue; - -			sta_id = mvmvif->link[link_id]->ap_sta_id; -			sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]); -			if (!IS_ERR_OR_NULL(sta) && sta->mfp) -				expected_tk_len = 0; -			break; -		} -		rcu_read_unlock(); -	} - -	if (tk_len != expected_tk_len || -	    (hltk_len && hltk_len != sizeof(pasn->hltk))) { -		IWL_ERR(mvm, "Invalid key length: tk_len=%u hltk_len=%u\n", -			tk_len, hltk_len); -		goto out; -	} - -	if (!expected_tk_len && !hltk_len) { -		IWL_ERR(mvm, "TK and HLTK not set\n"); -		goto out; -	} - -	memcpy(pasn->addr, addr, sizeof(pasn->addr)); - -	if (hltk_len) { -		memcpy(pasn->hltk, hltk, sizeof(pasn->hltk)); -		pasn->flags |= IWL_MVM_PASN_FLAG_HAS_HLTK; -	} - -	if (tk && tk_len) -		memcpy(pasn->tk, tk, sizeof(pasn->tk)); - -	list_add_tail(&pasn->list, &mvm->ftm_initiator.pasn_list); -	return 0; -out: -	kfree(pasn); -	return -EINVAL; -} - -void iwl_mvm_ftm_remove_pasn_sta(struct iwl_mvm *mvm, u8 *addr) -{ -	struct iwl_mvm_ftm_pasn_entry *entry, *prev; - -	lockdep_assert_held(&mvm->mutex); - -	list_for_each_entry_safe(entry, prev, &mvm->ftm_initiator.pasn_list, -				 list) { -		if (memcmp(entry->addr, addr, sizeof(entry->addr))) -			continue; - -		list_del(&entry->list); -		kfree(entry); -		return; -	} -} -  static void iwl_mvm_ftm_reset(struct iwl_mvm *mvm)  {  	struct iwl_mvm_loc_entry *e, *t; @@ -563,12 +462,12 @@ static int iwl_mvm_ftm_set_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,  #ifdef CONFIG_IWLWIFI_DEBUGFS  		if (mvmvif->ftm_unprotected) { -			*sta_id = IWL_MVM_INVALID_STA; +			*sta_id = IWL_INVALID_STA;  			*flags &= ~cpu_to_le32(IWL_INITIATOR_AP_FLAGS_PMF);  		}  #endif  	} else { -		*sta_id = IWL_MVM_INVALID_STA; +		*sta_id = IWL_INVALID_STA;  	}  	return 0; @@ -776,7 +675,12 @@ iwl_mvm_ftm_set_secured_ranging(struct iwl_mvm *mvm, struct ieee80211_vif *vif,  			struct iwl_mvm_ftm_iter_data target;  			target.bssid = bssid; +			target.cipher = cipher; +			target.tk = NULL;  			ieee80211_iter_keys(mvm->hw, vif, iter, &target); + +			if (!WARN_ON(!target.tk)) +				memcpy(tk, target.tk, TK_11AZ_LEN);  		} else {  			memcpy(tk, entry->tk, sizeof(entry->tk));  		} @@ -952,7 +856,7 @@ static int iwl_mvm_ftm_start_v13(struct iwl_mvm *mvm,  static int  iwl_mvm_ftm_put_target_v10(struct iwl_mvm *mvm, struct ieee80211_vif *vif,  			   struct cfg80211_pmsr_request_peer *peer, -			   struct iwl_tof_range_req_ap_entry_v10 *target) +			   struct iwl_tof_range_req_ap_entry *target)  {  	u32 i2r_max_sts, flags;  	int ret; @@ -1024,7 +928,7 @@ static int iwl_mvm_ftm_start_v14(struct iwl_mvm *mvm,  				 struct ieee80211_vif *vif,  				 struct cfg80211_pmsr_request *req)  { -	struct iwl_tof_range_req_cmd_v14 cmd; +	struct iwl_tof_range_req_cmd cmd;  	struct iwl_host_cmd hcmd = {  		.id = WIDE_ID(LOCATION_GROUP, TOF_RANGE_REQ_CMD),  		.dataflags[0] = IWL_HCMD_DFL_DUP, @@ -1038,7 +942,7 @@ static int iwl_mvm_ftm_start_v14(struct iwl_mvm *mvm,  	for (i = 0; i < cmd.num_of_ap; i++) {  		struct cfg80211_pmsr_request_peer *peer = &req->peers[i]; -		struct iwl_tof_range_req_ap_entry_v10 *target = &cmd.ap[i]; +		struct iwl_tof_range_req_ap_entry *target = &cmd.ap[i];  		err = iwl_mvm_ftm_put_target_v10(mvm, vif, peer, target);  		if (err) @@ -1066,6 +970,8 @@ int iwl_mvm_ftm_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif,  						   IWL_FW_CMD_VER_UNKNOWN);  		switch (cmd_ver) { +		case 15: +			/* Version 15 has the same struct as 14 */  		case 14:  			err = iwl_mvm_ftm_start_v14(mvm, vif, req);  			break; @@ -1302,7 +1208,7 @@ static void iwl_mvm_debug_range_resp(struct iwl_mvm *mvm, u8 index,  static void  iwl_mvm_ftm_pasn_update_pn(struct iwl_mvm *mvm, -			   struct iwl_tof_range_rsp_ap_entry_ntfy_v6 *fw_ap) +			   struct iwl_tof_range_rsp_ap_entry_ntfy *fw_ap)  {  	struct iwl_mvm_ftm_pasn_entry *entry; @@ -1340,7 +1246,7 @@ static bool iwl_mvm_ftm_resp_size_validation(u8 ver, unsigned int pkt_len)  	switch (ver) {  	case 9:  	case 8: -		return pkt_len == sizeof(struct iwl_tof_range_rsp_ntfy_v8); +		return pkt_len == sizeof(struct iwl_tof_range_rsp_ntfy);  	case 7:  		return pkt_len == sizeof(struct iwl_tof_range_rsp_ntfy_v7);  	case 6: @@ -1360,7 +1266,7 @@ void iwl_mvm_ftm_range_resp(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb)  	struct iwl_tof_range_rsp_ntfy_v5 *fw_resp_v5 = (void *)pkt->data;  	struct iwl_tof_range_rsp_ntfy_v6 *fw_resp_v6 = (void *)pkt->data;  	struct iwl_tof_range_rsp_ntfy_v7 *fw_resp_v7 = (void *)pkt->data; -	struct iwl_tof_range_rsp_ntfy_v8 *fw_resp_v8 = (void *)pkt->data; +	struct iwl_tof_range_rsp_ntfy *fw_resp_v8 = (void *)pkt->data;  	int i;  	bool new_api = fw_has_api(&mvm->fw->ucode_capa,  				  IWL_UCODE_TLV_API_FTM_NEW_RANGE_REQ); @@ -1396,9 +1302,9 @@ void iwl_mvm_ftm_range_resp(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb)  	IWL_DEBUG_INFO(mvm, "request id: %lld, num of entries: %u\n",  		       mvm->ftm_initiator.req->cookie, num_of_aps); -	for (i = 0; i < num_of_aps && i < IWL_MVM_TOF_MAX_APS; i++) { +	for (i = 0; i < num_of_aps && i < IWL_TOF_MAX_APS; i++) {  		struct cfg80211_pmsr_result result = {}; -		struct iwl_tof_range_rsp_ap_entry_ntfy_v6 *fw_ap; +		struct iwl_tof_range_rsp_ap_entry_ntfy *fw_ap;  		int peer_idx;  		if (new_api) { diff --git a/sys/contrib/dev/iwlwifi/mvm/ftm-responder.c b/sys/contrib/dev/iwlwifi/mvm/ftm-responder.c index 3e989f3141b5..83f6e508a094 100644 --- a/sys/contrib/dev/iwlwifi/mvm/ftm-responder.c +++ b/sys/contrib/dev/iwlwifi/mvm/ftm-responder.c @@ -131,7 +131,7 @@ iwl_mvm_ftm_responder_cmd(struct iwl_mvm *mvm,  	lockdep_assert_held(&mvm->mutex); -	if (cmd_ver == 10) { +	if (cmd_ver >= 10) {  		cmd.band =  			iwl_mvm_phy_band_from_nl80211(chandef->chan->band);  	} @@ -324,94 +324,6 @@ static void iwl_mvm_resp_del_pasn_sta(struct iwl_mvm *mvm,  	kfree(sta);  } -#if defined(__linux__) -int iwl_mvm_ftm_respoder_add_pasn_sta(struct iwl_mvm *mvm, -				      struct ieee80211_vif *vif, -				      u8 *addr, u32 cipher, u8 *tk, u32 tk_len, -				      u8 *hltk, u32 hltk_len) -{ -	int ret; -	struct iwl_mvm_pasn_sta *sta = NULL; -	struct iwl_mvm_pasn_hltk_data hltk_data = { -		.addr = addr, -		.hltk = hltk, -	}; -	struct iwl_mvm_pasn_hltk_data *hltk_data_ptr = NULL; - -	u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, -					   WIDE_ID(LOCATION_GROUP, TOF_RESPONDER_DYN_CONFIG_CMD), -					   2); - -	lockdep_assert_held(&mvm->mutex); - -	if (cmd_ver < 3) { -		IWL_ERR(mvm, "Adding PASN station not supported by FW\n"); -		return -EOPNOTSUPP; -	} - -	if ((!hltk || !hltk_len) && (!tk || !tk_len)) { -		IWL_ERR(mvm, "TK and HLTK not set\n"); -		return -EINVAL; -	} - -	if (hltk && hltk_len) { -		if (!fw_has_capa(&mvm->fw->ucode_capa, -				 IWL_UCODE_TLV_CAPA_SECURE_LTF_SUPPORT)) { -			IWL_ERR(mvm, "No support for secure LTF measurement\n"); -			return -EINVAL; -		} - -		hltk_data.cipher = iwl_mvm_cipher_to_location_cipher(cipher); -		if (hltk_data.cipher == IWL_LOCATION_CIPHER_INVALID) { -			IWL_ERR(mvm, "invalid cipher: %u\n", cipher); -			return -EINVAL; -		} - -		hltk_data_ptr = &hltk_data; -	} - -	if (tk && tk_len) { -		sta = kzalloc(sizeof(*sta) + tk_len, GFP_KERNEL); -		if (!sta) -			return -ENOBUFS; - -		ret = iwl_mvm_add_pasn_sta(mvm, vif, &sta->int_sta, addr, -					   cipher, tk, tk_len, &sta->keyconf); -		if (ret) { -			kfree(sta); -			return ret; -		} - -		memcpy(sta->addr, addr, ETH_ALEN); -		list_add_tail(&sta->list, &mvm->resp_pasn_list); -	} - -	ret = iwl_mvm_ftm_responder_dyn_cfg_v3(mvm, vif, NULL, hltk_data_ptr); -	if (ret && sta) -		iwl_mvm_resp_del_pasn_sta(mvm, vif, sta); - -	return ret; -} - -int iwl_mvm_ftm_resp_remove_pasn_sta(struct iwl_mvm *mvm, -				     struct ieee80211_vif *vif, u8 *addr) -{ -	struct iwl_mvm_pasn_sta *sta, *prev; - -	lockdep_assert_held(&mvm->mutex); - -	list_for_each_entry_safe(sta, prev, &mvm->resp_pasn_list, list) { -		if (!memcmp(sta->addr, addr, ETH_ALEN)) { -			iwl_mvm_resp_del_pasn_sta(mvm, vif, sta); -			return 0; -		} -	} - -	IWL_ERR(mvm, "FTM: PASN station %pM not found\n", addr); -	return -EINVAL; -} -#endif -  int iwl_mvm_ftm_start_responder(struct iwl_mvm *mvm, struct ieee80211_vif *vif,  				struct ieee80211_bss_conf *bss_conf)  { diff --git a/sys/contrib/dev/iwlwifi/mvm/fw.c b/sys/contrib/dev/iwlwifi/mvm/fw.c index 08c4898c8f1a..d931c6eaf12f 100644 --- a/sys/contrib/dev/iwlwifi/mvm/fw.c +++ b/sys/contrib/dev/iwlwifi/mvm/fw.c @@ -1,6 +1,6 @@  // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause  /* - * Copyright (C) 2012-2014, 2018-2024 Intel Corporation + * Copyright (C) 2012-2014, 2018-2025 Intel Corporation   * Copyright (C) 2013-2015 Intel Mobile Communications GmbH   * Copyright (C) 2016-2017 Intel Deutschland GmbH   */ @@ -29,8 +29,8 @@  #define MVM_UCODE_CALIB_TIMEOUT	(2 * HZ)  struct iwl_mvm_alive_data { +	__le32 sku_id[3];  	bool valid; -	u32 scd_base_addr;  };  static int iwl_send_tx_ant_cfg(struct iwl_mvm *mvm, u8 valid_tx_ant) @@ -57,13 +57,13 @@ static int iwl_send_rss_cfg_cmd(struct iwl_mvm *mvm)  			     BIT(IWL_RSS_HASH_TYPE_IPV6_PAYLOAD),  	}; -	if (mvm->trans->num_rx_queues == 1) +	if (mvm->trans->info.num_rxqs == 1)  		return 0;  	/* Do not direct RSS traffic to Q 0 which is our fallback queue */  	for (i = 0; i < ARRAY_SIZE(cmd.indirection_table); i++)  		cmd.indirection_table[i] = -			1 + (i % (mvm->trans->num_rx_queues - 1)); +			1 + (i % (mvm->trans->info.num_rxqs - 1));  	netdev_rss_key_fill(cmd.secret_key, sizeof(cmd.secret_key));  	return iwl_mvm_send_cmd_pdu(mvm, RSS_CONFIG_CMD, 0, sizeof(cmd), &cmd); @@ -114,13 +114,29 @@ static bool iwl_alive_fn(struct iwl_notif_wait_data *notif_wait,  	u32 i; -	if (version == 6) { +	if (version >= 6) {  		struct iwl_alive_ntf_v6 *palive;  		if (pkt_len < sizeof(*palive))  			return false;  		palive = (void *)pkt->data; + +		umac = &palive->umac_data; +		lmac1 = &palive->lmac_data[0]; +		lmac2 = &palive->lmac_data[1]; +		status = le16_to_cpu(palive->status); + +		BUILD_BUG_ON(sizeof(palive->sku_id.data) != +			     sizeof(alive_data->sku_id)); +		memcpy(alive_data->sku_id, palive->sku_id.data, +		       sizeof(palive->sku_id.data)); + +		IWL_DEBUG_FW(mvm, "Got sku_id: 0x0%x 0x0%x 0x0%x\n", +			     le32_to_cpu(alive_data->sku_id[0]), +			     le32_to_cpu(alive_data->sku_id[1]), +			     le32_to_cpu(alive_data->sku_id[2])); +  		mvm->trans->dbg.imr_data.imr_enable =  			le32_to_cpu(palive->imr.enabled);  		mvm->trans->dbg.imr_data.imr_size = @@ -157,39 +173,17 @@ static bool iwl_alive_fn(struct iwl_notif_wait_data *notif_wait,  				}  			}  		} -	} -	if (version >= 5) { -		struct iwl_alive_ntf_v5 *palive; +		if (version >= 8) { +			const struct iwl_alive_ntf *palive_v8 = +				(void *)pkt->data; -		if (pkt_len < sizeof(*palive)) -			return false; - -		palive = (void *)pkt->data; -		umac = &palive->umac_data; -		lmac1 = &palive->lmac_data[0]; -		lmac2 = &palive->lmac_data[1]; -		status = le16_to_cpu(palive->status); +			if (pkt_len < sizeof(*palive_v8)) +				return false; -		mvm->trans->sku_id[0] = le32_to_cpu(palive->sku_id.data[0]); -		mvm->trans->sku_id[1] = le32_to_cpu(palive->sku_id.data[1]); -		mvm->trans->sku_id[2] = le32_to_cpu(palive->sku_id.data[2]); - -		IWL_DEBUG_FW(mvm, "Got sku_id: 0x0%x 0x0%x 0x0%x\n", -			     mvm->trans->sku_id[0], -			     mvm->trans->sku_id[1], -			     mvm->trans->sku_id[2]); -	} else if (iwl_rx_packet_payload_len(pkt) == sizeof(struct iwl_alive_ntf_v4)) { -		struct iwl_alive_ntf_v4 *palive; - -		if (pkt_len < sizeof(*palive)) -			return false; - -		palive = (void *)pkt->data; -		umac = &palive->umac_data; -		lmac1 = &palive->lmac_data[0]; -		lmac2 = &palive->lmac_data[1]; -		status = le16_to_cpu(palive->status); +			IWL_DEBUG_FW(mvm, "platform id: 0x%llx\n", +				     palive_v8->platform_id); +		}  	} else if (iwl_rx_packet_payload_len(pkt) ==  		   sizeof(struct iwl_alive_ntf_v3)) {  		struct iwl_alive_ntf_v3 *palive3; @@ -221,7 +215,7 @@ static bool iwl_alive_fn(struct iwl_notif_wait_data *notif_wait,  	if (umac_error_table) {  		if (umac_error_table >= -		    mvm->trans->cfg->min_umac_error_event_table) { +		    mvm->trans->mac_cfg->base->min_umac_error_event_table) {  			iwl_fw_umac_set_alive_err_table(mvm->trans,  							umac_error_table);  		} else { @@ -233,7 +227,6 @@ static bool iwl_alive_fn(struct iwl_notif_wait_data *notif_wait,  		}  	} -	alive_data->scd_base_addr = le32_to_cpu(lmac1->dbg_ptrs.scd_base_ptr);  	alive_data->valid = status == IWL_ALIVE_STATUS_OK;  	IWL_DEBUG_FW(mvm, @@ -282,7 +275,7 @@ static void iwl_mvm_print_pd_notification(struct iwl_mvm *mvm)  	IWL_ERR(mvm, #reg_name ": 0x%x\n", iwl_read_umac_prph(trans, reg_name))  	struct iwl_trans *trans = mvm->trans; -	enum iwl_device_family device_family = trans->trans_cfg->device_family; +	enum iwl_device_family device_family = trans->mac_cfg->device_family;  	if (device_family < IWL_DEVICE_FAMILY_8000)  		return; @@ -304,7 +297,6 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm,  {  	struct iwl_notification_wait alive_wait;  	struct iwl_mvm_alive_data alive_data = {}; -	const struct fw_img *fw;  	int ret;  	enum iwl_ucode_type old_type = mvm->fwrt.cur_fw_img;  	static const u16 alive_cmd[] = { UCODE_ALIVE_NTFY }; @@ -317,11 +309,7 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm,  	    iwl_fw_dbg_conf_usniffer(mvm->fw, FW_DBG_START_FROM_ALIVE) &&  	    !(fw_has_capa(&mvm->fw->ucode_capa,  			  IWL_UCODE_TLV_CAPA_USNIFFER_UNIFIED))) -		fw = iwl_get_ucode_image(mvm->fw, IWL_UCODE_REGULAR_USNIFFER); -	else -		fw = iwl_get_ucode_image(mvm->fw, ucode_type); -	if (WARN_ON(!fw)) -		return -EINVAL; +		ucode_type = IWL_UCODE_REGULAR_USNIFFER;  	iwl_fw_set_current_image(&mvm->fwrt, ucode_type);  	clear_bit(IWL_MVM_STATUS_FIRMWARE_RUNNING, &mvm->status); @@ -334,7 +322,8 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm,  	 * For the unified firmware case, the ucode_type is not  	 * INIT, but we still need to run it.  	 */ -	ret = iwl_trans_start_fw(mvm->trans, fw, run_in_rfkill); +	ret = iwl_trans_start_fw(mvm->trans, mvm->fw, ucode_type, +				 run_in_rfkill);  	if (ret) {  		iwl_fw_set_current_image(&mvm->fwrt, old_type);  		iwl_remove_notification(&mvm->notif_wait, &alive_wait); @@ -348,7 +337,7 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm,  	ret = iwl_wait_notification(&mvm->notif_wait, &alive_wait,  				    MVM_UCODE_ALIVE_TIMEOUT); -	if (mvm->trans->trans_cfg->device_family == +	if (mvm->trans->mac_cfg->device_family ==  	    IWL_DEVICE_FAMILY_AX210) {  		/* print these registers regardless of alive fail/success */  		IWL_INFO(mvm, "WFPM_UMAC_PD_NOTIFICATION: 0x%x\n", @@ -365,14 +354,14 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm,  		struct iwl_trans *trans = mvm->trans;  		/* SecBoot info */ -		if (trans->trans_cfg->device_family >= +		if (trans->mac_cfg->device_family >=  					IWL_DEVICE_FAMILY_22000) {  			IWL_ERR(mvm,  				"SecBoot CPU1 Status: 0x%x, CPU2 Status: 0x%x\n",  				iwl_read_umac_prph(trans, UMAG_SB_CPU_1_STATUS),  				iwl_read_umac_prph(trans,  						   UMAG_SB_CPU_2_STATUS)); -		} else if (trans->trans_cfg->device_family >= +		} else if (trans->mac_cfg->device_family >=  			   IWL_DEVICE_FAMILY_8000) {  			IWL_ERR(mvm,  				"SecBoot CPU1 Status: 0x%x, CPU2 Status: 0x%x\n", @@ -383,7 +372,7 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm,  		iwl_mvm_print_pd_notification(mvm);  		/* LMAC/UMAC PC info */ -		if (trans->trans_cfg->device_family >= +		if (trans->mac_cfg->device_family >=  					IWL_DEVICE_FAMILY_22000) {  			pc_data = trans->dbg.pc_data;  			for (count = 0; count < trans->dbg.num_pc; @@ -391,7 +380,7 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm,  				IWL_ERR(mvm, "%s: 0x%x\n",  					pc_data->pc_name,  					pc_data->pc_address); -		} else if (trans->trans_cfg->device_family >= +		} else if (trans->mac_cfg->device_family >=  					IWL_DEVICE_FAMILY_9000) {  			IWL_ERR(mvm, "UMAC PC: 0x%x\n",  				iwl_read_umac_prph(trans, @@ -422,16 +411,16 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm,  	/* if reached this point, Alive notification was received */  	iwl_mei_alive_notif(true); +	iwl_trans_fw_alive(mvm->trans); +  	ret = iwl_pnvm_load(mvm->trans, &mvm->notif_wait, -			    &mvm->fw->ucode_capa); +			    mvm->fw, alive_data.sku_id);  	if (ret) {  		IWL_ERR(mvm, "Timeout waiting for PNVM load!\n");  		iwl_fw_set_current_image(&mvm->fwrt, old_type);  		return ret;  	} -	iwl_trans_fw_alive(mvm->trans, alive_data.scd_base_addr); -  	/*  	 * Note: all the queues are enabled as part of the interface  	 * initialization, but in firmware restart scenarios they @@ -473,7 +462,7 @@ static void iwl_mvm_phy_filter_init(struct iwl_mvm *mvm,  				    struct iwl_phy_specific_cfg *phy_filters)  {  #ifdef CONFIG_ACPI -	*phy_filters = mvm->phy_filters; +	*phy_filters = mvm->fwrt.phy_filters;  #endif /* CONFIG_ACPI */  } @@ -490,7 +479,7 @@ static void iwl_mvm_uats_init(struct iwl_mvm *mvm)  		.dataflags[0] = IWL_HCMD_DFL_NOCOPY,  	}; -	if (mvm->trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_AX210) { +	if (mvm->trans->mac_cfg->device_family < IWL_DEVICE_FAMILY_AX210) {  		IWL_DEBUG_RADIO(mvm, "UATS feature is not supported\n");  		return;  	} @@ -504,11 +493,10 @@ static void iwl_mvm_uats_init(struct iwl_mvm *mvm)  		return;  	} -	ret = iwl_uefi_get_uats_table(mvm->trans, &mvm->fwrt); -	if (ret < 0) { -		IWL_DEBUG_FW(mvm, "failed to read UATS table (%d)\n", ret); +	iwl_uefi_get_uats_table(mvm->trans, &mvm->fwrt); + +	if (!mvm->fwrt.uats_valid)  		return; -	}  	ret = iwl_mvm_send_cmd(mvm, &cmd);  	if (ret < 0) @@ -578,7 +566,7 @@ static int iwl_send_phy_cfg_cmd(struct iwl_mvm *mvm)  	/* set flags extra PHY configuration flags from the device's cfg */  	phy_cfg_cmd.phy_cfg |= -		cpu_to_le32(mvm->trans->trans_cfg->extra_phy_cfg_flags); +		cpu_to_le32(mvm->trans->mac_cfg->extra_phy_cfg_flags);  	phy_cfg_cmd.calib_control.event_trigger =  		mvm->fw->default_calib[ucode_type].event_trigger; @@ -617,7 +605,7 @@ static int iwl_run_unified_mvm_ucode(struct iwl_mvm *mvm)  	mvm->rfkill_safe_init_done = false; -	if (mvm->trans->trans_cfg->device_family == IWL_DEVICE_FAMILY_AX210) { +	if (mvm->trans->mac_cfg->device_family == IWL_DEVICE_FAMILY_AX210) {  		sb_cfg = iwl_read_umac_prph(mvm->trans, SB_MODIFY_CFG_FLAG);  		/* if needed, we'll reset this on our way out later */  		mvm->fw_product_reset = sb_cfg == SB_CFG_RESIDES_IN_ROM; @@ -642,7 +630,8 @@ static int iwl_run_unified_mvm_ucode(struct iwl_mvm *mvm)  		/* if we needed reset then fail here, but notify and remove */  		if (mvm->fw_product_reset) {  			iwl_mei_alive_notif(false); -			iwl_trans_pcie_remove(mvm->trans, true); +			iwl_trans_pcie_reset(mvm->trans, +					     IWL_RESET_MODE_RESCAN);  		}  		goto error; @@ -650,11 +639,6 @@ static int iwl_run_unified_mvm_ucode(struct iwl_mvm *mvm)  	iwl_dbg_tlv_time_point(&mvm->fwrt, IWL_FW_INI_TIME_POINT_AFTER_ALIVE,  			       NULL); -	if (mvm->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_BZ) -		mvm->trans->step_urm = !!(iwl_read_umac_prph(mvm->trans, -							     CNVI_PMU_STEP_FLOW) & -						CNVI_PMU_STEP_FLOW_FORCE_URM); -  	/* Send init config command to mark that we are sending NVM access  	 * commands  	 */ @@ -755,7 +739,7 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm)  		goto remove_notif;  	} -	if (mvm->trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_8000) { +	if (mvm->trans->mac_cfg->device_family < IWL_DEVICE_FAMILY_8000) {  		ret = iwl_mvm_send_bt_init_conf(mvm);  		if (ret)  			goto remove_notif; @@ -863,7 +847,10 @@ static int iwl_mvm_config_ltr(struct iwl_mvm *mvm)  int iwl_mvm_sar_select_profile(struct iwl_mvm *mvm, int prof_a, int prof_b)  {  	u32 cmd_id = REDUCE_TX_POWER_CMD; -	struct iwl_dev_tx_power_cmd cmd = { +	struct iwl_dev_tx_power_cmd_v3_v8 cmd = { +		.common.set_mode = cpu_to_le32(IWL_TX_POWER_MODE_SET_CHAINS), +	}; +	struct iwl_dev_tx_power_cmd cmd_v9_v10 = {  		.common.set_mode = cpu_to_le32(IWL_TX_POWER_MODE_SET_CHAINS),  	};  	__le16 *per_chain; @@ -871,18 +858,23 @@ int iwl_mvm_sar_select_profile(struct iwl_mvm *mvm, int prof_a, int prof_b)  	u16 len = 0;  	u32 n_subbands;  	u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, cmd_id, 3); +	void *cmd_data = &cmd; -	if (cmd_ver >= 7) { -		len = sizeof(cmd.v7); +	if (cmd_ver == 10) { +		len = sizeof(cmd_v9_v10.v10);  		n_subbands = IWL_NUM_SUB_BANDS_V2; -		per_chain = cmd.v7.per_chain[0][0]; -		cmd.v7.flags = cpu_to_le32(mvm->fwrt.reduced_power_flags); -		if (cmd_ver == 8) -			len = sizeof(cmd.v8); -	} else if (cmd_ver == 6) { -		len = sizeof(cmd.v6); +		per_chain = &cmd_v9_v10.v10.per_chain[0][0][0]; +		cmd_v9_v10.v10.flags = +			cpu_to_le32(mvm->fwrt.reduced_power_flags); +	} else if (cmd_ver == 9) { +		len = sizeof(cmd_v9_v10.v9); +		n_subbands = IWL_NUM_SUB_BANDS_V1; +		per_chain = &cmd_v9_v10.v9.per_chain[0][0]; +	} else if (cmd_ver == 8) { +		len = sizeof(cmd.v8);  		n_subbands = IWL_NUM_SUB_BANDS_V2; -		per_chain = cmd.v6.per_chain[0][0]; +		per_chain = cmd.v8.per_chain[0][0]; +		cmd.v8.flags = cpu_to_le32(mvm->fwrt.reduced_power_flags);  	} else if (fw_has_api(&mvm->fw->ucode_capa,  			      IWL_UCODE_TLV_API_REDUCE_TX_POWER)) {  		len = sizeof(cmd.v5); @@ -899,9 +891,14 @@ int iwl_mvm_sar_select_profile(struct iwl_mvm *mvm, int prof_a, int prof_b)  		per_chain = cmd.v3.per_chain[0][0];  	} -	/* all structs have the same common part, add it */ +	/* all structs have the same common part, add its length */  	len += sizeof(cmd.common); +	if (cmd_ver < 9) +		len += sizeof(cmd.per_band); +	else +		cmd_data = &cmd_v9_v10; +  	ret = iwl_sar_fill_profile(&mvm->fwrt, per_chain,  				   IWL_NUM_CHAIN_TABLES,  				   n_subbands, prof_a, prof_b); @@ -913,7 +910,7 @@ int iwl_mvm_sar_select_profile(struct iwl_mvm *mvm, int prof_a, int prof_b)  	iwl_mei_set_power_limit(per_chain);  	IWL_DEBUG_RADIO(mvm, "Sending REDUCE_TX_POWER_CMD per chain\n"); -	return iwl_mvm_send_cmd_pdu(mvm, cmd_id, 0, len, &cmd); +	return iwl_mvm_send_cmd_pdu(mvm, cmd_id, 0, len, cmd_data);  }  int iwl_mvm_get_sar_geo_profile(struct iwl_mvm *mvm) @@ -1074,36 +1071,24 @@ static int iwl_mvm_ppag_init(struct iwl_mvm *mvm)  	return iwl_mvm_ppag_send_cmd(mvm);  } -static bool iwl_mvm_add_to_tas_block_list(__le32 *list, __le32 *le_size, unsigned int mcc) -{ -	int i; -	u32 size = le32_to_cpu(*le_size); - -	/* Verify that there is room for another country */ -	if (size >= IWL_WTAS_BLACK_LIST_MAX) -		return false; - -	for (i = 0; i < size; i++) { -		if (list[i] == cpu_to_le32(mcc)) -			return true; -	} - -	list[size++] = cpu_to_le32(mcc); -	*le_size = cpu_to_le32(size); -	return true; -} -  static void iwl_mvm_tas_init(struct iwl_mvm *mvm)  {  	u32 cmd_id = WIDE_ID(REGULATORY_AND_NVM_GROUP, TAS_CONFIG); -	int ret; +	int fw_ver = iwl_fw_lookup_cmd_ver(mvm->fw, cmd_id, +					   IWL_FW_CMD_VER_UNKNOWN); +	struct iwl_tas_selection_data selection_data = {}; +	struct iwl_tas_config_cmd_v2_v4 cmd_v2_v4 = {}; +	struct iwl_tas_config_cmd cmd_v5 = {};  	struct iwl_tas_data data = {}; -	struct iwl_tas_config_cmd cmd = {}; -	int cmd_size, fw_ver; +	void *cmd_data = &cmd_v2_v4; +	int cmd_size; +	int ret;  	BUILD_BUG_ON(ARRAY_SIZE(data.block_list_array) !=  		     IWL_WTAS_BLACK_LIST_MAX); -	BUILD_BUG_ON(ARRAY_SIZE(cmd.common.block_list_array) != +	BUILD_BUG_ON(ARRAY_SIZE(cmd_v2_v4.common.block_list_array) != +		     IWL_WTAS_BLACK_LIST_MAX); +	BUILD_BUG_ON(ARRAY_SIZE(cmd_v5.block_list_array) !=  		     IWL_WTAS_BLACK_LIST_MAX);  	if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_TAS_CFG)) { @@ -1119,17 +1104,17 @@ static void iwl_mvm_tas_init(struct iwl_mvm *mvm)  		return;  	} -	if (ret == 0) +	if (ret == 0 && fw_ver < 5)  		return;  	if (!iwl_is_tas_approved()) {  		IWL_DEBUG_RADIO(mvm,  				"System vendor '%s' is not in the approved list, disabling TAS in US and Canada.\n",  				dmi_get_system_info(DMI_SYS_VENDOR) ?: "<unknown>"); -		if ((!iwl_mvm_add_to_tas_block_list(data.block_list_array, +		if ((!iwl_add_mcc_to_tas_block_list(data.block_list_array,  						    &data.block_list_size,  						    IWL_MCC_US)) || -		    (!iwl_mvm_add_to_tas_block_list(data.block_list_array, +		    (!iwl_add_mcc_to_tas_block_list(data.block_list_array,  						    &data.block_list_size,  						    IWL_MCC_CANADA))) {  			IWL_DEBUG_RADIO(mvm, @@ -1142,63 +1127,53 @@ static void iwl_mvm_tas_init(struct iwl_mvm *mvm)  				dmi_get_system_info(DMI_SYS_VENDOR) ?: "<unknown>");  	} -	fw_ver = iwl_fw_lookup_cmd_ver(mvm->fw, cmd_id, -				       IWL_FW_CMD_VER_UNKNOWN); - -	memcpy(&cmd.common, &data, sizeof(struct iwl_tas_config_cmd_common)); - -	/* Set v3 or v4 specific parts. will be trunctated for fw_ver < 3 */ -	if (fw_ver == 4) { -		cmd.v4.override_tas_iec = data.override_tas_iec; -		cmd.v4.enable_tas_iec = data.enable_tas_iec; -		cmd.v4.usa_tas_uhb_allowed = data.usa_tas_uhb_allowed; +	if (fw_ver < 5) { +		selection_data = iwl_parse_tas_selection(data.tas_selection, +							 data.table_revision); +		cmd_v2_v4.common.block_list_size = +			cpu_to_le32(data.block_list_size); +		for (u8 i = 0; i < data.block_list_size; i++) +			cmd_v2_v4.common.block_list_array[i] = +				cpu_to_le32(data.block_list_array[i]); +	} + +	if (fw_ver == 5) { +		cmd_size = sizeof(cmd_v5); +		cmd_data = &cmd_v5; +		cmd_v5.block_list_size = cpu_to_le16(data.block_list_size); +		for (u16 i = 0; i < data.block_list_size; i++) +			cmd_v5.block_list_array[i] = +				cpu_to_le16(data.block_list_array[i]); +		cmd_v5.tas_config_info.table_source = data.table_source; +		cmd_v5.tas_config_info.table_revision = data.table_revision; +		cmd_v5.tas_config_info.value = cpu_to_le32(data.tas_selection); +	} else if (fw_ver == 4) { +		cmd_size = sizeof(cmd_v2_v4.common) + sizeof(cmd_v2_v4.v4); +		cmd_v2_v4.v4.override_tas_iec = selection_data.override_tas_iec; +		cmd_v2_v4.v4.enable_tas_iec = selection_data.enable_tas_iec; +		cmd_v2_v4.v4.usa_tas_uhb_allowed = +			selection_data.usa_tas_uhb_allowed; +		if (fw_has_capa(&mvm->fw->ucode_capa, +				IWL_UCODE_TLV_CAPA_UHB_CANADA_TAS_SUPPORT) && +		    selection_data.canada_tas_uhb_allowed) +			cmd_v2_v4.v4.uhb_allowed_flags = TAS_UHB_ALLOWED_CANADA; +	} else if (fw_ver == 3) { +		cmd_size = sizeof(cmd_v2_v4.common) + sizeof(cmd_v2_v4.v3); +		cmd_v2_v4.v3.override_tas_iec = +			cpu_to_le16(selection_data.override_tas_iec); +		cmd_v2_v4.v3.enable_tas_iec = +			cpu_to_le16(selection_data.enable_tas_iec); +	} else if (fw_ver == 2) { +		cmd_size = sizeof(cmd_v2_v4.common);  	} else { -		cmd.v3.override_tas_iec = cpu_to_le16(data.override_tas_iec); -		cmd.v3.enable_tas_iec = cpu_to_le16(data.enable_tas_iec); +		return;  	} -	cmd_size = sizeof(struct iwl_tas_config_cmd_common); -	if (fw_ver >= 3) -		/* v4 is the same size as v3 */ -		cmd_size += sizeof(struct iwl_tas_config_cmd_v3); - -	ret = iwl_mvm_send_cmd_pdu(mvm, cmd_id, 0, cmd_size, &cmd); +	ret = iwl_mvm_send_cmd_pdu(mvm, cmd_id, 0, cmd_size, cmd_data);  	if (ret < 0)  		IWL_DEBUG_RADIO(mvm, "failed to send TAS_CONFIG (%d)\n", ret);  } -static bool iwl_mvm_eval_dsm_rfi(struct iwl_mvm *mvm) -{ -	u32 value = 0; -	/* default behaviour is disabled */ -	bool bios_enable_rfi = false; -	int ret = iwl_bios_get_dsm(&mvm->fwrt, DSM_FUNC_RFI_CONFIG, &value); - - -	if (ret < 0) { -		IWL_DEBUG_RADIO(mvm, "Failed to get DSM RFI, ret=%d\n", ret); -		return bios_enable_rfi; -	} - -	value &= DSM_VALUE_RFI_DISABLE; -	/* RFI BIOS CONFIG value can be 0 or 3 only. -	 * i.e 0 means DDR and DLVR enabled. 3 means DDR and DLVR disabled. -	 * 1 and 2 are invalid BIOS configurations, So, it's not possible to -	 * disable ddr/dlvr separately. -	 */ -	if (!value) { -		IWL_DEBUG_RADIO(mvm, "DSM RFI is evaluated to enable\n"); -		bios_enable_rfi = true; -	} else if (value == DSM_VALUE_RFI_DISABLE) { -		IWL_DEBUG_RADIO(mvm, "DSM RFI is evaluated to disable\n"); -	} else { -		IWL_DEBUG_RADIO(mvm, -				"DSM RFI got invalid value, value=%d\n", value); -	} - -	return bios_enable_rfi; -} -  static void iwl_mvm_lari_cfg(struct iwl_mvm *mvm)  {  	struct iwl_lari_config_change_cmd cmd; @@ -1272,7 +1247,7 @@ void iwl_mvm_get_bios_tables(struct iwl_mvm *mvm)  		}  	} -	iwl_acpi_get_phy_filters(&mvm->fwrt, &mvm->phy_filters); +	iwl_acpi_get_phy_filters(&mvm->fwrt);  	if (iwl_bios_get_eckv(&mvm->fwrt, &mvm->ext_clock_valid))  		IWL_DEBUG_RADIO(mvm, "ECKV table doesn't exist in BIOS\n"); @@ -1288,8 +1263,8 @@ static void iwl_mvm_disconnect_iterator(void *data, u8 *mac,  void iwl_mvm_send_recovery_cmd(struct iwl_mvm *mvm, u32 flags)  {  	u32 error_log_size = mvm->fw->ucode_capa.error_log_size; +	u32 status = 0;  	int ret; -	u32 resp;  	struct iwl_fw_error_recovery_cmd recovery_cmd = {  		.flags = cpu_to_le32(flags), @@ -1297,7 +1272,6 @@ void iwl_mvm_send_recovery_cmd(struct iwl_mvm *mvm, u32 flags)  	};  	struct iwl_host_cmd host_cmd = {  		.id = WIDE_ID(SYSTEM_GROUP, FW_ERROR_RECOVERY_CMD), -		.flags = CMD_WANT_SKB,  		.data = {&recovery_cmd, },  		.len = {sizeof(recovery_cmd), },  	}; @@ -1317,7 +1291,7 @@ void iwl_mvm_send_recovery_cmd(struct iwl_mvm *mvm, u32 flags)  		recovery_cmd.buf_size = cpu_to_le32(error_log_size);  	} -	ret = iwl_mvm_send_cmd(mvm, &host_cmd); +	ret = iwl_mvm_send_cmd_status(mvm, &host_cmd, &status);  	kfree(mvm->error_recovery_buf);  	mvm->error_recovery_buf = NULL; @@ -1328,11 +1302,10 @@ void iwl_mvm_send_recovery_cmd(struct iwl_mvm *mvm, u32 flags)  	/* skb respond is only relevant in ERROR_RECOVERY_UPDATE_DB */  	if (flags & ERROR_RECOVERY_UPDATE_DB) { -		resp = le32_to_cpu(*(__le32 *)host_cmd.resp_pkt->data); -		if (resp) { +		if (status) {  			IWL_ERR(mvm,  				"Failed to send recovery cmd blob was invalid %d\n", -				resp); +				status);  			ieee80211_iterate_interfaces(mvm->hw, 0,  						     iwl_mvm_disconnect_iterator, @@ -1384,6 +1357,7 @@ int iwl_mvm_up(struct iwl_mvm *mvm)  	int ret, i;  	struct ieee80211_supported_band *sband = NULL; +	lockdep_assert_wiphy(mvm->hw->wiphy);  	lockdep_assert_held(&mvm->mutex);  	ret = iwl_trans_start_hw(mvm->trans); @@ -1464,10 +1438,7 @@ int iwl_mvm_up(struct iwl_mvm *mvm)  		RCU_INIT_POINTER(mvm->fw_id_to_link_sta[i], NULL);  	} -	for (i = 0; i < IWL_MVM_FW_MAX_LINK_ID + 1; i++) -		RCU_INIT_POINTER(mvm->link_id_to_link_conf[i], NULL); - -	mvm->tdls_cs.peer.sta_id = IWL_MVM_INVALID_STA; +	mvm->tdls_cs.peer.sta_id = IWL_INVALID_STA;  	/* reset quota debouncing buffer - 0xff will yield invalid data */  	memset(&mvm->last_quota_cmd, 0xff, sizeof(mvm->last_quota_cmd)); @@ -1586,7 +1557,7 @@ int iwl_mvm_up(struct iwl_mvm *mvm)  	iwl_mvm_uats_init(mvm);  	if (iwl_rfi_supported(mvm)) { -		if (iwl_mvm_eval_dsm_rfi(mvm)) +		if (iwl_rfi_is_enabled_in_bios(&mvm->fwrt))  			iwl_rfi_send_config_cmd(mvm, NULL);  	} @@ -1603,6 +1574,7 @@ int iwl_mvm_load_d3_fw(struct iwl_mvm *mvm)  {  	int ret, i; +	lockdep_assert_wiphy(mvm->hw->wiphy);  	lockdep_assert_held(&mvm->mutex);  	ret = iwl_trans_start_hw(mvm->trans); diff --git a/sys/contrib/dev/iwlwifi/mvm/led.c b/sys/contrib/dev/iwlwifi/mvm/led.c index 1ea7c44250d4..c3cc1ea3ccc9 100644 --- a/sys/contrib/dev/iwlwifi/mvm/led.c +++ b/sys/contrib/dev/iwlwifi/mvm/led.c @@ -1,6 +1,6 @@  // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause  /* - * Copyright (C) 2012-2014, 2018-2019 Intel Corporation + * Copyright (C) 2012-2014, 2018-2019, 2025 Intel Corporation   * Copyright (C) 2017 Intel Deutschland GmbH   */  #include <linux/leds.h> @@ -102,7 +102,7 @@ void iwl_mvm_leds_sync(struct iwl_mvm *mvm)  	 * if we control through the register, we're doing it  	 * even when the firmware isn't up, so no need to sync  	 */ -	if (mvm->trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_8000) +	if (mvm->trans->mac_cfg->device_family < IWL_DEVICE_FAMILY_8000)  		return;  	iwl_mvm_led_set(mvm, mvm->led.brightness > 0); diff --git a/sys/contrib/dev/iwlwifi/mvm/link.c b/sys/contrib/dev/iwlwifi/mvm/link.c index a9929aa49913..2269acc55c0e 100644 --- a/sys/contrib/dev/iwlwifi/mvm/link.c +++ b/sys/contrib/dev/iwlwifi/mvm/link.c @@ -12,6 +12,7 @@  	HOW(BLOCKED_FW)			\  	HOW(BLOCKED_NON_BSS)		\  	HOW(BLOCKED_ROC)		\ +	HOW(BLOCKED_TMP_NON_BSS)	\  	HOW(EXIT_MISSED_BEACON)		\  	HOW(EXIT_LOW_RSSI)		\  	HOW(EXIT_COEX)			\ @@ -48,20 +49,6 @@ static void iwl_mvm_print_esr_state(struct iwl_mvm *mvm, u32 mask)  #undef NAME_PR  } -static u32 iwl_mvm_get_free_fw_link_id(struct iwl_mvm *mvm, -				       struct iwl_mvm_vif *mvm_vif) -{ -	u32 i; - -	lockdep_assert_held(&mvm->mutex); - -	for (i = 0; i < ARRAY_SIZE(mvm->link_id_to_link_conf); i++) -		if (!rcu_access_pointer(mvm->link_id_to_link_conf[i])) -			return i; - -	return IWL_MVM_FW_LINK_ID_INVALID; -} -  static int iwl_mvm_link_cmd_send(struct iwl_mvm *mvm,  				 struct iwl_link_config_cmd *cmd,  				 enum iwl_ctxt_action action) @@ -78,25 +65,15 @@ static int iwl_mvm_link_cmd_send(struct iwl_mvm *mvm,  	return ret;  } -int iwl_mvm_set_link_mapping(struct iwl_mvm *mvm, struct ieee80211_vif *vif, -			     struct ieee80211_bss_conf *link_conf) +void iwl_mvm_set_link_fw_id(struct iwl_mvm *mvm, struct ieee80211_vif *vif, +			    struct ieee80211_bss_conf *link_conf)  {  	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);  	struct iwl_mvm_vif_link_info *link_info =  		mvmvif->link[link_conf->link_id]; -	if (link_info->fw_link_id == IWL_MVM_FW_LINK_ID_INVALID) { -		link_info->fw_link_id = iwl_mvm_get_free_fw_link_id(mvm, -								    mvmvif); -		if (link_info->fw_link_id >= -		    ARRAY_SIZE(mvm->link_id_to_link_conf)) -			return -EINVAL; - -		rcu_assign_pointer(mvm->link_id_to_link_conf[link_info->fw_link_id], -				   link_conf); -	} - -	return 0; +	if (link_info->fw_link_id == IWL_MVM_FW_LINK_ID_INVALID) +		link_info->fw_link_id = mvmvif->id;  }  int iwl_mvm_add_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif, @@ -108,14 +85,11 @@ int iwl_mvm_add_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif,  	struct iwl_link_config_cmd cmd = {};  	unsigned int cmd_id = WIDE_ID(MAC_CONF_GROUP, LINK_CONFIG_CMD);  	u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, cmd_id, 1); -	int ret;  	if (WARN_ON_ONCE(!link_info))  		return -EINVAL; -	ret = iwl_mvm_set_link_mapping(mvm, vif, link_conf); -	if (ret) -		return ret; +	iwl_mvm_set_link_fw_id(mvm, vif, link_conf);  	/* Update SF - Disable if needed. if this fails, SF might still be on  	 * while many macs are bound, which is forbidden - so fail the binding. @@ -233,10 +207,15 @@ int iwl_mvm_link_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif,  		WARN_ON_ONCE(active == link_info->active);  		/* When deactivating a link session protection should -		 * be stopped +		 * be stopped. Also let the firmware know if we can't Tx.  		 */ -		if (!active && vif->type == NL80211_IFTYPE_STATION) +		if (!active && vif->type == NL80211_IFTYPE_STATION) {  			iwl_mvm_stop_session_protection(mvm, vif); +			if (link_info->csa_block_tx) { +				cmd.block_tx = 1; +				link_info->csa_block_tx = false; +			} +		}  	}  	cmd.link_id = cpu_to_le32(link_info->fw_link_id); @@ -258,7 +237,7 @@ int iwl_mvm_link_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif,  	if (vif->type == NL80211_IFTYPE_ADHOC && link_conf->bssid)  		memcpy(cmd.ibss_bssid_addr, link_conf->bssid, ETH_ALEN); -	iwl_mvm_set_fw_basic_rates(mvm, vif, link_conf, +	iwl_mvm_set_fw_basic_rates(mvm, vif, link_info,  				   &cmd.cck_rates, &cmd.ofdm_rates);  	cmd.cck_short_preamble = cpu_to_le32(link_conf->use_short_preamble); @@ -293,6 +272,17 @@ int iwl_mvm_link_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif,  			(link_conf->uora_ocw_range >> 3) & 0x7;  	} +	/* ap_sta may be NULL if we're disconnecting */ +	if (changes & LINK_CONTEXT_MODIFY_HE_PARAMS && mvmvif->ap_sta) { +		struct ieee80211_link_sta *link_sta = +			link_sta_dereference_check(mvmvif->ap_sta, link_id); + +		if (!WARN_ON(!link_sta) && link_sta->he_cap.has_he && +		    link_sta->he_cap.he_cap_elem.mac_cap_info[5] & +		    IEEE80211_HE_MAC_CAP5_OM_CTRL_UL_MU_DATA_DIS_RX) +			cmd.ul_mu_data_disable = 1; +	} +  	/* TODO  how to set ndp_fdbk_buff_th_exp? */  	if (iwl_mvm_set_fw_mu_edca_params(mvm, mvmvif->link[link_id], @@ -343,7 +333,8 @@ int iwl_mvm_link_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif,  send_cmd:  	cmd.modify_mask = cpu_to_le32(changes);  	cmd.flags = cpu_to_le32(flags); -	cmd.flags_mask = cpu_to_le32(flags_mask); +	if (cmd_ver < 6) +		cmd.flags_mask = cpu_to_le32(flags_mask);  	cmd.spec_link_id = link_conf->link_id;  	if (cmd_ver < 2)  		cmd.listen_lmac = cpu_to_le32(link_info->listen_lmac); @@ -355,24 +346,6 @@ send_cmd:  	return ret;  } -int iwl_mvm_unset_link_mapping(struct iwl_mvm *mvm, struct ieee80211_vif *vif, -			       struct ieee80211_bss_conf *link_conf) -{ -	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); -	struct iwl_mvm_vif_link_info *link_info = -		mvmvif->link[link_conf->link_id]; - -	/* mac80211 thought we have the link, but it was never configured */ -	if (WARN_ON(!link_info || -		    link_info->fw_link_id >= -		    ARRAY_SIZE(mvm->link_id_to_link_conf))) -		return -EINVAL; - -	RCU_INIT_POINTER(mvm->link_id_to_link_conf[link_info->fw_link_id], -			 NULL); -	return 0; -} -  int iwl_mvm_remove_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif,  			struct ieee80211_bss_conf *link_conf)  { @@ -382,10 +355,6 @@ int iwl_mvm_remove_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif,  	struct iwl_link_config_cmd cmd = {};  	int ret; -	ret = iwl_mvm_unset_link_mapping(mvm, vif, link_conf); -	if (ret) -		return 0; -  	cmd.link_id = cpu_to_le32(link_info->fw_link_id);  	link_info->fw_link_id = IWL_MVM_FW_LINK_ID_INVALID;  	cmd.spec_link_id = link_conf->link_id; @@ -393,9 +362,8 @@ int iwl_mvm_remove_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif,  	ret = iwl_mvm_link_cmd_send(mvm, &cmd, FW_CTXT_ACTION_REMOVE); -	if (!ret) -		if (iwl_mvm_sf_update(mvm, vif, true)) -			IWL_ERR(mvm, "Failed to update SF state\n"); +	if (!ret && iwl_mvm_sf_update(mvm, vif, true)) +		IWL_ERR(mvm, "Failed to update SF state\n");  	return ret;  } @@ -743,9 +711,8 @@ bool iwl_mvm_mld_valid_link_pair(struct ieee80211_vif *vif,  	    iwl_mvm_esr_disallowed_with_link(mvm, vif, b, false))  		return false; -	if (a->chandef->width != b->chandef->width || -	    !(a->chandef->chan->band == NL80211_BAND_6GHZ && -	      b->chandef->chan->band == NL80211_BAND_5GHZ)) +	if (a->chandef->chan->band == b->chandef->chan->band || +	    a->chandef->width != b->chandef->width)  		ret |= IWL_MVM_ESR_EXIT_BANDWIDTH;  	if (ret) { @@ -1148,3 +1115,14 @@ void iwl_mvm_unblock_esr(struct iwl_mvm *mvm, struct ieee80211_vif *vif,  	if (!mvmvif->esr_disable_reason)  		iwl_mvm_esr_unblocked(mvm, vif);  } + +void iwl_mvm_init_link(struct iwl_mvm_vif_link_info *link) +{ +	link->bcast_sta.sta_id = IWL_INVALID_STA; +	link->mcast_sta.sta_id = IWL_INVALID_STA; +	link->ap_sta_id = IWL_INVALID_STA; + +	for (int r = 0; r < NUM_IWL_MVM_SMPS_REQ; r++) +		link->smps_requests[r] = +			IEEE80211_SMPS_AUTOMATIC; +} diff --git a/sys/contrib/dev/iwlwifi/mvm/mac-ctxt.c b/sys/contrib/dev/iwlwifi/mvm/mac-ctxt.c index 24bfdb054a63..a3ff2f083aef 100644 --- a/sys/contrib/dev/iwlwifi/mvm/mac-ctxt.c +++ b/sys/contrib/dev/iwlwifi/mvm/mac-ctxt.c @@ -1,6 +1,6 @@  // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause  /* - * Copyright (C) 2012-2014, 2018-2024 Intel Corporation + * Copyright (C) 2012-2014, 2018-2025 Intel Corporation   * Copyright (C) 2013-2014 Intel Mobile Communications GmbH   * Copyright (C) 2015-2017 Intel Deutschland GmbH   */ @@ -12,6 +12,7 @@  #include "fw-api.h"  #include "mvm.h"  #include "time-event.h" +#include "iwl-utils.h"  const u8 iwl_mvm_ac_to_tx_fifo[] = {  	IWL_MVM_TX_FIFO_VO, @@ -216,7 +217,7 @@ int iwl_mvm_mac_ctxt_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif)  		.preferred_tsf = NUM_TSF_IDS,  		.found_vif = false,  	}; -	int ret, i; +	int ret;  	lockdep_assert_held(&mvm->mutex); @@ -298,11 +299,9 @@ int iwl_mvm_mac_ctxt_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif)  	mvmvif->time_event_data.id = TE_MAX;  	mvmvif->roc_activity = ROC_NUM_ACTIVITIES; -	mvmvif->deflink.bcast_sta.sta_id = IWL_MVM_INVALID_STA; -	mvmvif->deflink.mcast_sta.sta_id = IWL_MVM_INVALID_STA; -	mvmvif->deflink.ap_sta_id = IWL_MVM_INVALID_STA; +	iwl_mvm_init_link(&mvmvif->deflink); -	/* No need to allocate data queues to P2P Device MAC and NAN.*/ +	/* No need to allocate data queues to P2P Device MAC */  	if (vif->type == NL80211_IFTYPE_P2P_DEVICE)  		return 0; @@ -316,9 +315,6 @@ int iwl_mvm_mac_ctxt_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif)  		mvmvif->deflink.cab_queue = IWL_MVM_DQA_GCAST_QUEUE;  	} -	for (i = 0; i < NUM_IWL_MVM_SMPS_REQ; i++) -		mvmvif->deflink.smps_requests[i] = IEEE80211_SMPS_AUTOMATIC; -  	return 0;  exit_fail: @@ -413,19 +409,18 @@ static void iwl_mvm_ack_rates(struct iwl_mvm *mvm,  }  void iwl_mvm_set_fw_basic_rates(struct iwl_mvm *mvm, struct ieee80211_vif *vif, -				struct ieee80211_bss_conf *link_conf, +				struct iwl_mvm_vif_link_info *link_info,  				__le32 *cck_rates, __le32 *ofdm_rates)  { -	struct ieee80211_chanctx_conf *chanctx; +	struct iwl_mvm_phy_ctxt *phy_ctxt;  	u8 cck_ack_rates = 0, ofdm_ack_rates = 0; +	enum nl80211_band band = NL80211_BAND_2GHZ; -	rcu_read_lock(); -	chanctx = rcu_dereference(link_conf->chanctx_conf); -	iwl_mvm_ack_rates(mvm, vif, chanctx ? chanctx->def.chan->band -					    : NL80211_BAND_2GHZ, -			  &cck_ack_rates, &ofdm_ack_rates); +	phy_ctxt = link_info->phy_ctxt; +	if (phy_ctxt && phy_ctxt->channel) +		band = phy_ctxt->channel->band; -	rcu_read_unlock(); +	iwl_mvm_ack_rates(mvm, vif, band, &cck_ack_rates, &ofdm_ack_rates);  	*cck_rates = cpu_to_le32((u32)cck_ack_rates);  	*ofdm_rates = cpu_to_le32((u32)ofdm_ack_rates); @@ -563,7 +558,7 @@ static void iwl_mvm_mac_ctxt_cmd_common(struct iwl_mvm *mvm,  	else  		eth_broadcast_addr(cmd->bssid_addr); -	iwl_mvm_set_fw_basic_rates(mvm, vif, &vif->bss_conf, &cmd->cck_rates, +	iwl_mvm_set_fw_basic_rates(mvm, vif, &mvmvif->deflink, &cmd->cck_rates,  				   &cmd->ofdm_rates);  	cmd->cck_short_preamble = @@ -874,23 +869,6 @@ void iwl_mvm_mac_ctxt_set_tim(struct iwl_mvm *mvm,  	}  } -u32 iwl_mvm_find_ie_offset(u8 *beacon, u8 eid, u32 frame_size) -{ -	struct ieee80211_mgmt *mgmt = (void *)beacon; -	const u8 *ie; - -	if (WARN_ON_ONCE(frame_size <= (mgmt->u.beacon.variable - beacon))) -		return 0; - -	frame_size -= mgmt->u.beacon.variable - beacon; - -	ie = cfg80211_find_ie(eid, mgmt->u.beacon.variable, frame_size); -	if (!ie) -		return 0; - -	return ie - beacon; -} -  u8 iwl_mvm_mac_ctxt_get_lowest_rate(struct iwl_mvm *mvm,  				    struct ieee80211_tx_info *info,  				    struct ieee80211_vif *vif) @@ -960,12 +938,19 @@ u8 iwl_mvm_mac_ctxt_get_lowest_rate(struct iwl_mvm *mvm,  u16 iwl_mvm_mac_ctxt_get_beacon_flags(const struct iwl_fw *fw, u8 rate_idx)  { -	u16 flags = iwl_mvm_mac80211_idx_to_hwrate(fw, rate_idx);  	bool is_new_rate = iwl_fw_lookup_cmd_ver(fw, BEACON_TEMPLATE_CMD, 0) > 10; +	u16 flags, cck_flag; + +	if (is_new_rate) { +		flags = iwl_mvm_mac80211_idx_to_hwrate(fw, rate_idx); +		cck_flag = IWL_MAC_BEACON_CCK; +	} else { +		cck_flag = IWL_MAC_BEACON_CCK_V1; +		flags = iwl_fw_rate_idx_to_plcp(rate_idx); +	} -	if (rate_idx <= IWL_FIRST_CCK_RATE) -		flags |= is_new_rate ? IWL_MAC_BEACON_CCK -			  : IWL_MAC_BEACON_CCK_V1; +	if (rate_idx <= IWL_LAST_CCK_RATE) +		flags |= cck_flag;  	return flags;  } @@ -991,7 +976,7 @@ u8 iwl_mvm_mac_ctxt_get_beacon_rate(struct iwl_mvm *mvm,  static void iwl_mvm_mac_ctxt_set_tx(struct iwl_mvm *mvm,  				    struct ieee80211_vif *vif,  				    struct sk_buff *beacon, -				    struct iwl_tx_cmd *tx) +				    struct iwl_tx_cmd_v6_params *tx_params)  {  	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);  	struct ieee80211_tx_info *info; @@ -1001,30 +986,30 @@ static void iwl_mvm_mac_ctxt_set_tx(struct iwl_mvm *mvm,  	info = IEEE80211_SKB_CB(beacon);  	/* Set up TX command fields */ -	tx->len = cpu_to_le16((u16)beacon->len); -	tx->sta_id = mvmvif->deflink.bcast_sta.sta_id; -	tx->life_time = cpu_to_le32(TX_CMD_LIFE_TIME_INFINITE); +	tx_params->len = cpu_to_le16((u16)beacon->len); +	tx_params->sta_id = mvmvif->deflink.bcast_sta.sta_id; +	tx_params->life_time = cpu_to_le32(TX_CMD_LIFE_TIME_INFINITE);  	tx_flags = TX_CMD_FLG_SEQ_CTL | TX_CMD_FLG_TSF;  	tx_flags |=  		iwl_mvm_bt_coex_tx_prio(mvm, (void *)beacon->data, info, 0) <<  						TX_CMD_FLG_BT_PRIO_POS; -	tx->tx_flags = cpu_to_le32(tx_flags); +	tx_params->tx_flags = cpu_to_le32(tx_flags);  	if (!fw_has_capa(&mvm->fw->ucode_capa,  			 IWL_UCODE_TLV_CAPA_BEACON_ANT_SELECTION)) {  		iwl_mvm_toggle_tx_ant(mvm, &mvm->mgmt_last_antenna_idx); -		tx->rate_n_flags = +		tx_params->rate_n_flags =  			cpu_to_le32(BIT(mvm->mgmt_last_antenna_idx) <<  				    RATE_MCS_ANT_POS);  	}  	rate = iwl_mvm_mac_ctxt_get_beacon_rate(mvm, info, vif); -	tx->rate_n_flags |= +	tx_params->rate_n_flags |=  		cpu_to_le32(iwl_mvm_mac80211_idx_to_hwrate(mvm->fw, rate));  	if (rate == IWL_FIRST_CCK_RATE) -		tx->rate_n_flags |= cpu_to_le32(RATE_MCS_CCK_MSK_V1); +		tx_params->rate_n_flags |= cpu_to_le32(RATE_MCS_CCK_MSK_V1);  } @@ -1084,22 +1069,23 @@ static int iwl_mvm_mac_ctxt_send_beacon_v7(struct iwl_mvm *mvm,  					 beacon->data, beacon->len);  	beacon_cmd.csa_offset = -		cpu_to_le32(iwl_mvm_find_ie_offset(beacon->data, -						   WLAN_EID_CHANNEL_SWITCH, -						   beacon->len)); +		cpu_to_le32(iwl_find_ie_offset(beacon->data, +					       WLAN_EID_CHANNEL_SWITCH, +					       beacon->len));  	beacon_cmd.ecsa_offset = -		cpu_to_le32(iwl_mvm_find_ie_offset(beacon->data, -						   WLAN_EID_EXT_CHANSWITCH_ANN, -						   beacon->len)); +		cpu_to_le32(iwl_find_ie_offset(beacon->data, +					       WLAN_EID_EXT_CHANSWITCH_ANN, +					       beacon->len));  	return iwl_mvm_mac_ctxt_send_beacon_cmd(mvm, beacon, &beacon_cmd,  						sizeof(beacon_cmd));  }  bool iwl_mvm_enable_fils(struct iwl_mvm *mvm, +			 struct ieee80211_vif *vif,  			 struct ieee80211_chanctx_conf *ctx)  { -	if (IWL_MVM_DISABLE_AP_FILS) +	if (vif->type != NL80211_IFTYPE_AP || IWL_MVM_DISABLE_AP_FILS)  		return false;  	if (cfg80211_channel_is_psc(ctx->def.chan)) @@ -1128,7 +1114,7 @@ static int iwl_mvm_mac_ctxt_send_beacon_v9(struct iwl_mvm *mvm,  	ctx = rcu_dereference(link_conf->chanctx_conf);  	channel = ieee80211_frequency_to_channel(ctx->def.chan->center_freq);  	WARN_ON(channel == 0); -	if (iwl_mvm_enable_fils(mvm, ctx)) { +	if (iwl_mvm_enable_fils(mvm, vif, ctx)) {  		flags |= iwl_fw_lookup_cmd_ver(mvm->fw, BEACON_TEMPLATE_CMD,  					       0) > 10 ?  			IWL_MAC_BEACON_FILS : @@ -1157,20 +1143,20 @@ static int iwl_mvm_mac_ctxt_send_beacon_v9(struct iwl_mvm *mvm,  					 beacon->data, beacon->len);  	beacon_cmd.csa_offset = -		cpu_to_le32(iwl_mvm_find_ie_offset(beacon->data, -						   WLAN_EID_CHANNEL_SWITCH, -						   beacon->len)); +		cpu_to_le32(iwl_find_ie_offset(beacon->data, +					       WLAN_EID_CHANNEL_SWITCH, +					       beacon->len));  	beacon_cmd.ecsa_offset = -		cpu_to_le32(iwl_mvm_find_ie_offset(beacon->data, -						   WLAN_EID_EXT_CHANSWITCH_ANN, -						   beacon->len)); +		cpu_to_le32(iwl_find_ie_offset(beacon->data, +					       WLAN_EID_EXT_CHANSWITCH_ANN, +					       beacon->len));  	if (vif->type == NL80211_IFTYPE_AP &&  	    iwl_fw_lookup_cmd_ver(mvm->fw, BEACON_TEMPLATE_CMD, 0) >= 14)  		beacon_cmd.btwt_offset = -			cpu_to_le32(iwl_mvm_find_ie_offset(beacon->data, -							   WLAN_EID_S1G_TWT, -							   beacon->len)); +			cpu_to_le32(iwl_find_ie_offset(beacon->data, +						       WLAN_EID_S1G_TWT, +						       beacon->len));  	return iwl_mvm_mac_ctxt_send_beacon_cmd(mvm, beacon, &beacon_cmd,  						sizeof(beacon_cmd)); @@ -1528,7 +1514,7 @@ void iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm,  	mvm->ap_last_beacon_gp2 = le32_to_cpu(beacon->gp2);  	if (!iwl_mvm_is_short_beacon_notif_supported(mvm)) { -		struct iwl_mvm_tx_resp *beacon_notify_hdr = +		struct iwl_tx_resp *beacon_notify_hdr =  			&beacon_v5->beacon_notify_hdr;  		if (unlikely(pkt_len < sizeof(*beacon_v5))) @@ -1586,11 +1572,11 @@ void iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm,  	}  } -void iwl_mvm_rx_missed_beacons_notif(struct iwl_mvm *mvm, -				     struct iwl_rx_cmd_buffer *rxb) +static void +iwl_mvm_handle_missed_beacons_notif(struct iwl_mvm *mvm, +				    const struct iwl_missed_beacons_notif *mb, +				    struct iwl_rx_packet *pkt)  { -	struct iwl_rx_packet *pkt = rxb_addr(rxb); -	struct iwl_missed_beacons_notif *mb = (void *)pkt->data;  	struct iwl_fw_dbg_trigger_missed_bcon *bcon_trig;  	struct iwl_fw_dbg_trigger_tlv *trigger;  	u32 stop_trig_missed_bcon, stop_trig_missed_bcon_since_rx; @@ -1600,37 +1586,39 @@ void iwl_mvm_rx_missed_beacons_notif(struct iwl_mvm *mvm,  	u32 id = le32_to_cpu(mb->link_id);  	union iwl_dbg_tlv_tp_data tp_data = { .fw_pkt = pkt };  	u32 mac_type; -	int link_id = -1; +	int link_id;  	u8 notif_ver = iwl_fw_lookup_notif_ver(mvm->fw, LEGACY_GROUP,  					       MISSED_BEACONS_NOTIFICATION,  					       0); - -	/* before version four the ID in the notification refers to mac ID */ -	if (notif_ver < 4) { -		vif = iwl_mvm_rcu_dereference_vif_id(mvm, id, false); -	} else { -		struct ieee80211_bss_conf *bss_conf = -			iwl_mvm_rcu_fw_link_id_to_link_conf(mvm, id, false); - -		if (!bss_conf) -			return; - -		vif = bss_conf->vif; -		link_id = bss_conf->link_id; -	} +	u8 new_notif_ver = iwl_fw_lookup_notif_ver(mvm->fw, MAC_CONF_GROUP, +						   MISSED_BEACONS_NOTIF, 0); +	struct ieee80211_bss_conf *bss_conf; + +	/* If the firmware uses the new notification (from MAC_CONF_GROUP), +	 * refer to that notification's version. +	 * Note that the new notification from MAC_CONF_GROUP starts from +	 * version 5. +	 */ +	if (new_notif_ver) +		notif_ver = new_notif_ver;  	IWL_DEBUG_INFO(mvm, -		       "missed bcn %s_id=%u, consecutive=%u (%u, %u, %u)\n", +		       "missed bcn %s_id=%u, consecutive=%u (%u)\n",  		       notif_ver < 4 ? "mac" : "link",  		       id,  		       le32_to_cpu(mb->consec_missed_beacons), -		       le32_to_cpu(mb->consec_missed_beacons_since_last_rx), -		       le32_to_cpu(mb->num_recvd_beacons), -		       le32_to_cpu(mb->num_expected_beacons)); +		       le32_to_cpu(mb->consec_missed_beacons_since_last_rx)); +	/* +	 * starting from version 4 the ID is link ID, but driver +	 * uses link ID == MAC ID, so always treat as MAC ID +	 */ +	vif = iwl_mvm_rcu_dereference_vif_id(mvm, id, false);  	if (!vif)  		return; +	bss_conf = &vif->bss_conf; +	link_id = bss_conf->link_id;  	mac_type = iwl_mvm_get_mac_type(vif);  	IWL_DEBUG_INFO(mvm, "missed beacon mac_type=%u,\n", mac_type); @@ -1656,15 +1644,41 @@ void iwl_mvm_rx_missed_beacons_notif(struct iwl_mvm *mvm,  				 "missed_beacons:%d, missed_beacons_since_rx:%d\n",  				 rx_missed_bcon, rx_missed_bcon_since_rx);  		} -	} else if (rx_missed_bcon >= IWL_MVM_MISSED_BEACONS_EXIT_ESR_THRESH && -		   link_id >= 0 && hweight16(vif->active_links) > 1) { -		iwl_mvm_exit_esr(mvm, vif, IWL_MVM_ESR_EXIT_MISSED_BEACON, -				 iwl_mvm_get_other_link(vif, link_id)); +	} else if (link_id >= 0 && hweight16(vif->active_links) > 1) { +		u32 bss_param_ch_cnt_link_id = +			bss_conf->bss_param_ch_cnt_link_id; +		u32 scnd_lnk_bcn_lost = 0; + +		if (notif_ver >= 5 && +		    !IWL_FW_CHECK(mvm, +				  le32_to_cpu(mb->other_link_id) == IWL_MVM_FW_LINK_ID_INVALID, +				  "No data for other link id but we are in EMLSR active_links: 0x%x\n", +				  vif->active_links)) +			scnd_lnk_bcn_lost = +				le32_to_cpu(mb->consec_missed_beacons_other_link); + +		/* Exit EMLSR if we lost more than +		 * IWL_MVM_MISSED_BEACONS_EXIT_ESR_THRESH beacons on boths links +		 * OR more than IWL_MVM_BCN_LOSS_EXIT_ESR_THRESH on any link. +		 * OR more than IWL_MVM_BCN_LOSS_EXIT_ESR_THRESH_BSS_PARAM_CHANGED +		 * and the link's bss_param_ch_count has changed. +		 */ +		if ((rx_missed_bcon >= IWL_MVM_BCN_LOSS_EXIT_ESR_THRESH_2_LINKS && +		     scnd_lnk_bcn_lost >= IWL_MVM_BCN_LOSS_EXIT_ESR_THRESH_2_LINKS) || +		    rx_missed_bcon >= IWL_MVM_BCN_LOSS_EXIT_ESR_THRESH || +		    (bss_param_ch_cnt_link_id != link_id && +		     rx_missed_bcon >= IWL_MVM_BCN_LOSS_EXIT_ESR_THRESH_BSS_PARAM_CHANGED)) +			iwl_mvm_exit_esr(mvm, vif, +					 IWL_MVM_ESR_EXIT_MISSED_BEACON, +					 iwl_mvm_get_primary_link(vif));  	} else if (rx_missed_bcon_since_rx > IWL_MVM_MISSED_BEACONS_THRESHOLD) {  		if (!iwl_mvm_has_new_tx_api(mvm))  			ieee80211_beacon_loss(vif);  		else  			ieee80211_cqm_beacon_loss_notify(vif, GFP_ATOMIC); + +		/* try to switch links, no-op if we don't have MLO */ +		iwl_mvm_int_mlo_scan(mvm, vif);  	}  	iwl_dbg_tlv_time_point(&mvm->fwrt, @@ -1691,6 +1705,31 @@ void iwl_mvm_rx_missed_beacons_notif(struct iwl_mvm *mvm,  #endif  } +void iwl_mvm_rx_missed_beacons_notif(struct iwl_mvm *mvm, +				     struct iwl_rx_cmd_buffer *rxb) +{ +	struct iwl_rx_packet *pkt = rxb_addr(rxb); + +	iwl_mvm_handle_missed_beacons_notif(mvm, (const void *)pkt->data, pkt); +} + +void iwl_mvm_rx_missed_beacons_notif_legacy(struct iwl_mvm *mvm, +					    struct iwl_rx_cmd_buffer *rxb) +{ +	struct iwl_rx_packet *pkt = rxb_addr(rxb); +	const struct iwl_missed_beacons_notif_v4 *mb_v4 = +		(const void *)pkt->data; +	struct iwl_missed_beacons_notif mb = { +		.link_id = mb_v4->link_id, +		.consec_missed_beacons = mb_v4->consec_missed_beacons, +		.consec_missed_beacons_since_last_rx = +			mb_v4->consec_missed_beacons_since_last_rx, +		.other_link_id = cpu_to_le32(IWL_MVM_FW_LINK_ID_INVALID), +	}; + +	iwl_mvm_handle_missed_beacons_notif(mvm, &mb, pkt); +} +  void iwl_mvm_rx_stored_beacon_notif(struct iwl_mvm *mvm,  				    struct iwl_rx_cmd_buffer *rxb)  { @@ -1717,7 +1756,7 @@ void iwl_mvm_rx_stored_beacon_notif(struct iwl_mvm *mvm,  		data = sb_v2->data;  	} else { -		struct iwl_stored_beacon_notif_v3 *sb_v3 = (void *)pkt->data; +		struct iwl_stored_beacon_notif *sb_v3 = (void *)pkt->data;  		if (pkt_len < struct_size(sb_v3, data, size))  			return; @@ -1833,16 +1872,15 @@ void iwl_mvm_channel_switch_start_notif(struct iwl_mvm *mvm,  	} else {  		struct iwl_channel_switch_start_notif *notif = (void *)pkt->data;  		u32 link_id = le32_to_cpu(notif->link_id); -		struct ieee80211_bss_conf *bss_conf = -			iwl_mvm_rcu_fw_link_id_to_link_conf(mvm, link_id, true); -		if (!bss_conf) +		/* we use link ID == MAC ID */ +		vif = iwl_mvm_rcu_dereference_vif_id(mvm, link_id, true); +		if (!vif)  			goto out_unlock;  		id = link_id; -		mac_link_id = bss_conf->link_id; -		vif = bss_conf->vif; -		csa_active = bss_conf->csa_active; +		mac_link_id = vif->bss_conf.link_id; +		csa_active = vif->bss_conf.csa_active;  	}  	mvmvif = iwl_mvm_vif_from_mac80211(vif); @@ -1925,26 +1963,3 @@ void iwl_mvm_channel_switch_error_notif(struct iwl_mvm *mvm,  		ieee80211_channel_switch_disconnect(vif);  	rcu_read_unlock();  } - -void iwl_mvm_rx_missed_vap_notif(struct iwl_mvm *mvm, -				 struct iwl_rx_cmd_buffer *rxb) -{ -	struct iwl_rx_packet *pkt = rxb_addr(rxb); -	struct iwl_missed_vap_notif *mb = (void *)pkt->data; -	struct ieee80211_vif *vif; -	u32 id = le32_to_cpu(mb->mac_id); - -	IWL_DEBUG_INFO(mvm, -		       "missed_vap notify mac_id=%u, num_beacon_intervals_elapsed=%u, profile_periodicity=%u\n", -		       le32_to_cpu(mb->mac_id), -		       mb->num_beacon_intervals_elapsed, -		       mb->profile_periodicity); - -	rcu_read_lock(); - -	vif = iwl_mvm_rcu_dereference_vif_id(mvm, id, true); -	if (vif) -		iwl_mvm_connection_loss(mvm, vif, "missed vap beacon"); - -	rcu_read_unlock(); -} diff --git a/sys/contrib/dev/iwlwifi/mvm/mac80211.c b/sys/contrib/dev/iwlwifi/mvm/mac80211.c index a2f455616fbe..f32398213ab8 100644 --- a/sys/contrib/dev/iwlwifi/mvm/mac80211.c +++ b/sys/contrib/dev/iwlwifi/mvm/mac80211.c @@ -1,10 +1,11 @@  // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause  /* - * Copyright (C) 2012-2014, 2018-2024 Intel Corporation + * Copyright (C) 2012-2014, 2018-2025 Intel Corporation   * Copyright (C) 2013-2015 Intel Mobile Communications GmbH   * Copyright (C) 2016-2017 Intel Deutschland GmbH   */  #include <linux/kernel.h> +#include <linux/fips.h>  #include <linux/slab.h>  #include <linux/skbuff.h>  #include <linux/netdevice.h> @@ -78,7 +79,7 @@ static const struct ieee80211_iface_combination iwl_mvm_iface_combinations[] = {  };  static const struct cfg80211_pmsr_capabilities iwl_mvm_pmsr_capa = { -	.max_peers = IWL_MVM_TOF_MAX_APS, +	.max_peers = IWL_TOF_MAX_APS,  	.report_ap_tsf = 1,  	.randomize_mac_addr = 1, @@ -154,7 +155,7 @@ struct ieee80211_regdomain *iwl_mvm_get_regdomain(struct wiphy *wiphy,  					   MCC_UPDATE_CMD, 0);  	IWL_DEBUG_LAR(mvm, "MCC update response version: %d\n", resp_ver); -	regd = iwl_parse_nvm_mcc_info(mvm->trans->dev, mvm->cfg, +	regd = iwl_parse_nvm_mcc_info(mvm->trans,  				      __le32_to_cpu(resp->n_channels),  				      resp->channels,  				      __le16_to_cpu(resp->mcc), @@ -173,16 +174,6 @@ struct ieee80211_regdomain *iwl_mvm_get_regdomain(struct wiphy *wiphy,  	mvm->lar_regdom_set = true;  	mvm->mcc_src = src_id; -	/* Some kind of regulatory mess means we need to currently disallow -	 * puncturing in the US and Canada. Do that here, at least until we -	 * figure out the new chanctx APIs for puncturing. -	 */ -	if (resp->mcc == cpu_to_le16(IWL_MCC_US) || -	    resp->mcc == cpu_to_le16(IWL_MCC_CANADA)) -		ieee80211_hw_set(mvm->hw, DISALLOW_PUNCTURING); -	else -		__clear_bit(IEEE80211_HW_DISALLOW_PUNCTURING, mvm->hw->flags); -  	iwl_mei_set_country_code(__le16_to_cpu(resp->mcc));  out: @@ -284,9 +275,10 @@ static const u8 tm_if_types_ext_capa_sta[] = {  					__bf_shf(IEEE80211_EML_CAP_EMLSR_PADDING_DELAY) | \  				 IEEE80211_EML_CAP_EMLSR_TRANSITION_DELAY_64US << \  					__bf_shf(IEEE80211_EML_CAP_EMLSR_TRANSITION_DELAY)) -#define IWL_MVM_MLD_CAPA_OPS FIELD_PREP_CONST( \ +#define IWL_MVM_MLD_CAPA_OPS (FIELD_PREP_CONST( \  			IEEE80211_MLD_CAP_OP_TID_TO_LINK_MAP_NEG_SUPP, \ -			IEEE80211_MLD_CAP_OP_TID_TO_LINK_MAP_NEG_SUPP_SAME) +			IEEE80211_MLD_CAP_OP_TID_TO_LINK_MAP_NEG_SUPP_SAME) | \ +			IEEE80211_MLD_CAP_OP_LINK_RECONF_SUPPORT)  static const struct wiphy_iftype_ext_capab add_iftypes_ext_capa[] = {  	{ @@ -309,7 +301,8 @@ static const struct wiphy_iftype_ext_capab add_iftypes_ext_capa[] = {  	},  }; -int iwl_mvm_op_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant) +int iwl_mvm_op_get_antenna(struct ieee80211_hw *hw, int radio_idx, +			   u32 *tx_ant, u32 *rx_ant)  {  	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);  	*tx_ant = iwl_mvm_get_valid_tx_ant(mvm); @@ -317,13 +310,15 @@ int iwl_mvm_op_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant)  	return 0;  } -int iwl_mvm_op_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) +int iwl_mvm_op_set_antenna(struct ieee80211_hw *hw, int radio_idx, u32 tx_ant, +			   u32 rx_ant)  {  	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);  	/* This has been tested on those devices only */ -	if (mvm->trans->trans_cfg->device_family != IWL_DEVICE_FAMILY_9000 && -	    mvm->trans->trans_cfg->device_family != IWL_DEVICE_FAMILY_22000) +	if (mvm->trans->mac_cfg->device_family != IWL_DEVICE_FAMILY_9000 && +	    mvm->trans->mac_cfg->device_family != IWL_DEVICE_FAMILY_22000 && +	    mvm->trans->mac_cfg->device_family != IWL_DEVICE_FAMILY_AX210)  		return -EOPNOTSUPP;  	if (!mvm->nvm_data) @@ -402,7 +397,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)  	 * for older devices. We also don't see this issue on any newer  	 * devices.  	 */ -	if (mvm->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_9000) +	if (mvm->trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_9000)  		ieee80211_hw_set(hw, TX_AMSDU);  	ieee80211_hw_set(hw, TX_FRAG_LIST); @@ -413,7 +408,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)  	/* We want to use the mac80211's reorder buffer for 9000 */  	if (iwl_mvm_has_new_rx_api(mvm) && -	    mvm->trans->trans_cfg->device_family > IWL_DEVICE_FAMILY_9000) +	    mvm->trans->mac_cfg->device_family > IWL_DEVICE_FAMILY_9000)  		ieee80211_hw_set(hw, SUPPORTS_REORDERING_BUFFER);  	if (fw_has_capa(&mvm->fw->ucode_capa, @@ -428,10 +423,10 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)  		return -EINVAL;  	} -	if (mvm->trans->num_rx_queues > 1) +	if (mvm->trans->info.num_rxqs > 1)  		ieee80211_hw_set(hw, USES_RSS); -	if (mvm->trans->max_skb_frags) +	if (mvm->trans->info.max_skb_frags)  		hw->netdev_features = NETIF_F_HIGHDMA | NETIF_F_SG;  	hw->queues = IEEE80211_NUM_ACS; @@ -452,7 +447,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)  	hw->uapsd_queues = IWL_MVM_UAPSD_QUEUES;  	hw->uapsd_max_sp_len = IWL_UAPSD_MAX_SP; -	hw->max_tx_fragments = mvm->trans->max_skb_frags; +	hw->max_tx_fragments = mvm->trans->info.max_skb_frags;  	BUILD_BUG_ON(ARRAY_SIZE(mvm->ciphers) < ARRAY_SIZE(mvm_ciphers) + 6);  	memcpy(mvm->ciphers, mvm_ciphers, sizeof(mvm_ciphers)); @@ -475,7 +470,9 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)  		IWL_ERR(mvm,  			"iwlmvm doesn't allow to disable BT Coex, check bt_coex_active module parameter\n"); -	ieee80211_hw_set(hw, MFP_CAPABLE); +	if (!fips_enabled) +		ieee80211_hw_set(hw, MFP_CAPABLE); +  	mvm->ciphers[hw->wiphy->n_cipher_suites] = WLAN_CIPHER_SUITE_AES_CMAC;  	hw->wiphy->n_cipher_suites++;  	if (iwl_mvm_has_new_rx_api(mvm)) { @@ -499,12 +496,17 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)  		hw->wiphy->pmsr_capa = &iwl_mvm_pmsr_capa;  	} -	if (sec_key_ver && +	/* +	 * beacon protection must be handled by firmware, +	 * so cannot be done with fips_enabled +	 */ +	if (!fips_enabled && sec_key_ver &&  	    fw_has_capa(&mvm->fw->ucode_capa,  			IWL_UCODE_TLV_CAPA_BIGTK_TX_SUPPORT))  		wiphy_ext_feature_set(hw->wiphy,  				      NL80211_EXT_FEATURE_BEACON_PROTECTION); -	else if (fw_has_capa(&mvm->fw->ucode_capa, +	else if (!fips_enabled && +		 fw_has_capa(&mvm->fw->ucode_capa,  			     IWL_UCODE_TLV_CAPA_BIGTK_SUPPORT))  		wiphy_ext_feature_set(hw->wiphy,  				      NL80211_EXT_FEATURE_BEACON_PROTECTION_CLIENT); @@ -555,7 +557,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)  		hw->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG |  					       REGULATORY_DISABLE_BEACON_HINTS; -	if (mvm->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) +	if (mvm->trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_AX210)  		wiphy_ext_feature_set(hw->wiphy,  				      NL80211_EXT_FEATURE_DFS_CONCURRENT); @@ -621,7 +623,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)  		hw->wiphy->bands[NL80211_BAND_6GHZ] =  			&mvm->nvm_data->bands[NL80211_BAND_6GHZ]; -	hw->wiphy->hw_version = mvm->trans->hw_id; +	hw->wiphy->hw_version = mvm->trans->info.hw_id;  	if (iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_CAM)  		hw->wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT; @@ -647,10 +649,15 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)  			       NL80211_FEATURE_LOW_PRIORITY_SCAN |  			       NL80211_FEATURE_P2P_GO_OPPPS |  			       NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE | -			       NL80211_FEATURE_DYNAMIC_SMPS | -			       NL80211_FEATURE_STATIC_SMPS |  			       NL80211_FEATURE_SUPPORTS_WMM_ADMISSION; +	/* when firmware supports RLC/SMPS offload, do not set these +	 * driver features, since it's no longer supported by driver. +	 */ +	if (!iwl_mvm_has_rlc_offload(mvm)) +		hw->wiphy->features |= NL80211_FEATURE_STATIC_SMPS | +				       NL80211_FEATURE_DYNAMIC_SMPS; +  	if (fw_has_capa(&mvm->fw->ucode_capa,  			IWL_UCODE_TLV_CAPA_TXPOWER_INSERTION_SUPPORT))  		hw->wiphy->features |= NL80211_FEATURE_TX_POWER_INSERTION; @@ -737,11 +744,9 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)  	mvm->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD; -	ieee80211_hw_set(hw, DISALLOW_PUNCTURING_5GHZ); -  #ifdef CONFIG_PM_SLEEP  	if ((unified || mvm->fw->img[IWL_UCODE_WOWLAN].num_sec) && -	    device_can_wakeup(mvm->trans->dev)) { +	    device_can_wakeup(mvm->trans->dev) && !fips_enabled) {  		mvm->wowlan.flags |= WIPHY_WOWLAN_MAGIC_PKT |  				     WIPHY_WOWLAN_DISCONNECT |  				     WIPHY_WOWLAN_EAP_IDENTITY_REQ | @@ -777,7 +782,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)  		hw->wiphy->features |= NL80211_FEATURE_TDLS_CHANNEL_SWITCH;  	} -	hw->netdev_features |= mvm->cfg->features; +	hw->netdev_features |= mvm->trans->mac_cfg->base->features;  	if (!iwl_mvm_is_csum_supported(mvm))  		hw->netdev_features &= ~IWL_CSUM_NETIF_FLAGS_MASK; @@ -846,20 +851,10 @@ void iwl_mvm_mac_tx(struct ieee80211_hw *hw,  	if (ieee80211_is_mgmt(hdr->frame_control))  		sta = NULL; -	/* If there is no sta, and it's not offchannel - send through AP */ +	/* this shouldn't even happen: just drop */  	if (!sta && info->control.vif->type == NL80211_IFTYPE_STATION && -	    !offchannel) { -		struct iwl_mvm_vif *mvmvif = -			iwl_mvm_vif_from_mac80211(info->control.vif); -		u8 ap_sta_id = READ_ONCE(mvmvif->deflink.ap_sta_id); - -		if (ap_sta_id < mvm->fw->ucode_capa.num_stations) { -			/* mac80211 holds rcu read lock */ -			sta = rcu_dereference(mvm->fw_id_to_mac_id[ap_sta_id]); -			if (IS_ERR_OR_NULL(sta)) -				goto drop; -		} -	} +	    !offchannel) +		goto drop;  	if (tmp_sta && !sta && link_id != IEEE80211_LINK_UNSPECIFIED &&  	    !ieee80211_is_probe_resp(hdr->frame_control)) { @@ -1126,7 +1121,7 @@ static void iwl_mvm_cleanup_iterator(void *data, u8 *mac,  	vif->driver_flags &= ~IEEE80211_VIF_EML_ACTIVE;  	for_each_mvm_vif_valid_link(mvmvif, link_id) { -		mvmvif->link[link_id]->ap_sta_id = IWL_MVM_INVALID_STA; +		mvmvif->link[link_id]->ap_sta_id = IWL_INVALID_STA;  		mvmvif->link[link_id]->fw_link_id = IWL_MVM_FW_LINK_ID_INVALID;  		mvmvif->link[link_id]->phy_ctxt = NULL;  		mvmvif->link[link_id]->active = 0; @@ -1170,7 +1165,7 @@ static void iwl_mvm_cleanup_sta_iterator(void *data, struct ieee80211_sta *sta)  			 * Delete the stale data to avoid issues later on.  			 */  			iwl_mvm_mld_free_sta_link(mvm, mvm_sta, mvm_link_sta, -						  link_id, false); +						  link_id);  		}  	}  } @@ -1249,11 +1244,12 @@ int __iwl_mvm_mac_start(struct iwl_mvm *mvm)  		mvm->nvm_data = NULL;  	} -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	/* fast_resume will be cleared by iwl_mvm_fast_resume */  	fast_resume = mvm->fast_resume;  	if (fast_resume) { +		iwl_mvm_mei_device_state(mvm, true);  		ret = iwl_mvm_fast_resume(mvm);  		if (ret) {  			iwl_mvm_stop_device(mvm); @@ -1271,7 +1267,7 @@ int __iwl_mvm_mac_start(struct iwl_mvm *mvm)  			set_bit(IWL_MVM_STATUS_FIRMWARE_RUNNING, &mvm->status);  		}  	} -#endif /* CONFIG_PM */ +#endif /* CONFIG_PM_SLEEP */  	if (test_bit(IWL_MVM_STATUS_HW_RESTART_REQUESTED, &mvm->status)) {  		/* @@ -1310,21 +1306,22 @@ int iwl_mvm_mac_start(struct ieee80211_hw *hw)  {  	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);  	int ret; +	int retry, max_retry = 0;  	mutex_lock(&mvm->mutex);  	/* we are starting the mac not in error flow, and restart is enabled */  	if (!test_bit(IWL_MVM_STATUS_HW_RESTART_REQUESTED, &mvm->status) && -	    iwlwifi_mod_params.fw_restart) { -		/* -		 * This will prevent mac80211 recovery flows to trigger during -		 * init failures -		 */ -		set_bit(IWL_MVM_STATUS_STARTING, &mvm->status); -	} +	    iwlwifi_mod_params.fw_restart) +		max_retry = IWL_MAX_INIT_RETRY; + +	for (retry = 0; retry <= max_retry; retry++) { +		ret = __iwl_mvm_mac_start(mvm); +		if (ret != -ETIMEDOUT) +			break; -	ret = __iwl_mvm_mac_start(mvm); -	clear_bit(IWL_MVM_STATUS_STARTING, &mvm->status); +		IWL_ERR(mvm, "mac start retry %d\n", retry); +	}  	mutex_unlock(&mvm->mutex); @@ -1353,6 +1350,13 @@ static void iwl_mvm_restart_complete(struct iwl_mvm *mvm)  	 * of packets the FW sent out, so we must reconnect.  	 */  	iwl_mvm_teardown_tdls_peers(mvm); + +	IWL_INFO(mvm, "restart completed\n"); +	iwl_trans_finish_sw_reset(mvm->trans); + +	/* no need to lock, adding in parallel would schedule too */ +	if (!list_empty(&mvm->add_stream_txqs)) +		schedule_work(&mvm->add_stream_wk);  }  void iwl_mvm_mac_reconfig_complete(struct ieee80211_hw *hw, @@ -1386,10 +1390,13 @@ void __iwl_mvm_mac_stop(struct iwl_mvm *mvm, bool suspend)  		iwl_mvm_rm_aux_sta(mvm);  	if (suspend && -	    mvm->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) +	    mvm->trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_22000) {  		iwl_mvm_fast_suspend(mvm); -	else +		/* From this point on, we won't touch the device */ +		iwl_mvm_mei_device_state(mvm, false); +	} else {  		iwl_mvm_stop_device(mvm); +	}  	iwl_mvm_async_handlers_purge(mvm);  	/* async_handlers_list is empty and will stay empty: HW is stopped */ @@ -1483,29 +1490,47 @@ struct iwl_mvm_phy_ctxt *iwl_mvm_get_free_phy_ctxt(struct iwl_mvm *mvm)  	return NULL;  } -int iwl_mvm_set_tx_power(struct iwl_mvm *mvm, struct ieee80211_vif *vif, +int iwl_mvm_set_tx_power(struct iwl_mvm *mvm, +			 struct ieee80211_bss_conf *link_conf,  			 s16 tx_power)  {  	u32 cmd_id = REDUCE_TX_POWER_CMD; +	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(link_conf->vif); +	u32 mac_id = mvmvif->id;  	int len; -	struct iwl_dev_tx_power_cmd cmd = { -		.common.set_mode = cpu_to_le32(IWL_TX_POWER_MODE_SET_MAC), -		.common.mac_context_id = -			cpu_to_le32(iwl_mvm_vif_from_mac80211(vif)->id), -		.common.pwr_restriction = cpu_to_le16(8 * tx_power), +	struct iwl_dev_tx_power_cmd_v3_v8 cmd = { +		.common.set_mode = cpu_to_le32(IWL_TX_POWER_MODE_SET_LINK), +		.common.link_id = cpu_to_le32(mac_id),  	}; -	u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, cmd_id, -					   IWL_FW_CMD_VER_UNKNOWN); +	struct iwl_dev_tx_power_cmd cmd_v9_v10; +	u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, cmd_id, 3); +	u16 u_tx_power = tx_power == IWL_DEFAULT_MAX_TX_POWER ? +		IWL_DEV_MAX_TX_POWER : 8 * tx_power; +	void *cmd_data = &cmd; + +	cmd.common.pwr_restriction = cpu_to_le16(u_tx_power); + +	if (cmd_ver > 8) { +		u32 link_id; + +		if (WARN_ON(!mvmvif->link[link_conf->link_id])) +			return -ENODEV; -	if (tx_power == IWL_DEFAULT_MAX_TX_POWER) -		cmd.common.pwr_restriction = cpu_to_le16(IWL_DEV_MAX_TX_POWER); +		link_id = mvmvif->link[link_conf->link_id]->fw_link_id; -	if (cmd_ver == 8) +		/* Those fields sit on the same place for v9 and v10 */ +		cmd_v9_v10.common.set_mode = cpu_to_le32(IWL_TX_POWER_MODE_SET_LINK); +		cmd_v9_v10.common.link_id = cpu_to_le32(link_id); +		cmd_v9_v10.common.pwr_restriction = cpu_to_le16(u_tx_power); +		cmd_data = &cmd_v9_v10; +	} + +	if (cmd_ver == 10) +		len = sizeof(cmd_v9_v10.v10); +	else if (cmd_ver == 9) +		len = sizeof(cmd_v9_v10.v9); +	else if (cmd_ver == 8)  		len = sizeof(cmd.v8); -	else if (cmd_ver == 7) -		len = sizeof(cmd.v7); -	else if (cmd_ver == 6) -		len = sizeof(cmd.v6);  	else if (fw_has_api(&mvm->fw->ucode_capa,  			    IWL_UCODE_TLV_API_REDUCE_TX_POWER))  		len = sizeof(cmd.v5); @@ -1515,10 +1540,14 @@ int iwl_mvm_set_tx_power(struct iwl_mvm *mvm, struct ieee80211_vif *vif,  	else  		len = sizeof(cmd.v3); -	/* all structs have the same common part, add it */ +	/* all structs have the same common part, add its length */  	len += sizeof(cmd.common); -	return iwl_mvm_send_cmd_pdu(mvm, cmd_id, 0, len, &cmd); +	if (cmd_ver < 9) +		len += sizeof(cmd.per_band); + +	return iwl_mvm_send_cmd_pdu(mvm, cmd_id, 0, len, cmd_data); +  }  static void iwl_mvm_post_csa_tx(void *data, struct ieee80211_sta *sta) @@ -1730,6 +1759,21 @@ static void iwl_mvm_unblock_esr_tpt(struct wiphy *wiphy, struct wiphy_work *wk)  	iwl_mvm_unblock_esr(mvm, vif, IWL_MVM_ESR_BLOCKED_TPT);  } +static void iwl_mvm_unblock_esr_tmp_non_bss(struct wiphy *wiphy, +					    struct wiphy_work *wk) +{ +	struct iwl_mvm_vif *mvmvif = +		container_of(wk, struct iwl_mvm_vif, +			     unblock_esr_tmp_non_bss_wk.work); +	struct iwl_mvm *mvm = mvmvif->mvm; +	struct ieee80211_vif *vif = +		container_of((void *)mvmvif, struct ieee80211_vif, drv_priv); + +	mutex_lock(&mvm->mutex); +	iwl_mvm_unblock_esr(mvm, vif, IWL_MVM_ESR_BLOCKED_TMP_NON_BSS); +	mutex_unlock(&mvm->mutex); +} +  void iwl_mvm_mac_init_mvmvif(struct iwl_mvm *mvm, struct iwl_mvm_vif *mvmvif)  {  	lockdep_assert_held(&mvm->mutex); @@ -1737,6 +1781,8 @@ void iwl_mvm_mac_init_mvmvif(struct iwl_mvm *mvm, struct iwl_mvm_vif *mvmvif)  	if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))  		return; +	mvmvif->deflink.average_beacon_energy = 0; +  	INIT_DELAYED_WORK(&mvmvif->csa_work,  			  iwl_mvm_channel_switch_disconnect_wk); @@ -1748,6 +1794,9 @@ void iwl_mvm_mac_init_mvmvif(struct iwl_mvm *mvm, struct iwl_mvm_vif *mvmvif)  	wiphy_work_init(&mvmvif->unblock_esr_tpt_wk,  			iwl_mvm_unblock_esr_tpt); + +	wiphy_delayed_work_init(&mvmvif->unblock_esr_tmp_non_bss_wk, +				iwl_mvm_unblock_esr_tmp_non_bss);  }  static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, @@ -1769,9 +1818,9 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,  	mvmvif->deflink.active = 0;  	mvmvif->link[0] = &mvmvif->deflink; -	ret = iwl_mvm_set_link_mapping(mvm, vif, &vif->bss_conf); -	if (ret) -		goto out; +	vif->driver_flags = IEEE80211_VIF_REMOVE_AP_AFTER_DISASSOC; + +	iwl_mvm_set_link_fw_id(mvm, vif, &vif->bss_conf);  	/*  	 * Not much to do here. The stack will not allow interface @@ -1792,12 +1841,6 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,  	rcu_assign_pointer(mvm->vif_id_to_mac[mvmvif->id], vif); -	/* Currently not much to do for NAN */ -	if (vif->type == NL80211_IFTYPE_NAN) { -		ret = 0; -		goto out; -	} -  	/*  	 * The AP binding flow can be done only after the beacon  	 * template is configured (which happens only in the mac80211 @@ -1898,6 +1941,8 @@ void iwl_mvm_prepare_mac_removal(struct iwl_mvm *mvm,  				  &mvmvif->mlo_int_scan_wk);  	wiphy_work_cancel(mvm->hw->wiphy, &mvmvif->unblock_esr_tpt_wk); +	wiphy_delayed_work_cancel(mvm->hw->wiphy, +				  &mvmvif->unblock_esr_tmp_non_bss_wk);  	cancel_delayed_work_sync(&mvmvif->csa_work);  } @@ -1944,15 +1989,8 @@ static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw,  	 * interface is be handled as part of the stop_ap flow.  	 */  	if (vif->type == NL80211_IFTYPE_AP || -	    vif->type == NL80211_IFTYPE_ADHOC) { -#ifdef CONFIG_NL80211_TESTMODE -		if (vif == mvm->noa_vif) { -			mvm->noa_vif = NULL; -			mvm->noa_duration = 0; -		} -#endif +	    vif->type == NL80211_IFTYPE_ADHOC)  		goto out; -	}  	iwl_mvm_power_update_mac(mvm); @@ -1969,7 +2007,6 @@ static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw,  		mvm->p2p_device_vif = NULL;  	} -	iwl_mvm_unset_link_mapping(mvm, vif, &vif->bss_conf);  	iwl_mvm_mac_ctxt_remove(mvm, vif);  	RCU_INIT_POINTER(mvm->vif_id_to_mac[mvmvif->id], NULL); @@ -2937,7 +2974,7 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,  						    IWL_MVM_SMPS_REQ_PROT,  						    IEEE80211_SMPS_DYNAMIC, 0);  			} -		} else if (mvmvif->deflink.ap_sta_id != IWL_MVM_INVALID_STA) { +		} else if (mvmvif->deflink.ap_sta_id != IWL_INVALID_STA) {  			iwl_mvm_mei_host_disassociated(mvm);  			/*  			 * If update fails - SF might be running in associated @@ -2949,33 +2986,6 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,  					    &mvm->status),  				  "Failed to update SF upon disassociation\n"); -			/* -			 * If we get an assert during the connection (after the -			 * station has been added, but before the vif is set -			 * to associated), mac80211 will re-add the station and -			 * then configure the vif. Since the vif is not -			 * associated, we would remove the station here and -			 * this would fail the recovery. -			 */ -			if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, -				      &mvm->status)) { -				/* first remove remaining keys */ -				iwl_mvm_sec_key_remove_ap(mvm, vif, -							  &mvmvif->deflink, 0); - -				/* -				 * Remove AP station now that -				 * the MAC is unassoc -				 */ -				ret = iwl_mvm_rm_sta_id(mvm, vif, -							mvmvif->deflink.ap_sta_id); -				if (ret) -					IWL_ERR(mvm, -						"failed to remove AP station\n"); - -				mvmvif->deflink.ap_sta_id = IWL_MVM_INVALID_STA; -			} -  			/* remove quota for this interface */  			ret = iwl_mvm_update_quotas(mvm, false, NULL);  			if (ret) @@ -3059,7 +3069,7 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw,  	 * context. For the newer, the beacon is a resource that belongs to a  	 * MAC, so need to send beacon template after adding the mac.  	 */ -	if (mvm->trans->trans_cfg->device_family > IWL_DEVICE_FAMILY_22000) { +	if (mvm->trans->mac_cfg->device_family > IWL_DEVICE_FAMILY_22000) {  		/* Add the mac context */  		ret = iwl_mvm_mac_ctxt_add(mvm, vif);  		if (ret) @@ -3319,7 +3329,7 @@ static void iwl_mvm_bss_info_changed(struct ieee80211_hw *hw,  	if (changes & BSS_CHANGED_TXPOWER) {  		IWL_DEBUG_CALIB(mvm, "Changing TX Power to %d dBm\n",  				bss_conf->txpower); -		iwl_mvm_set_tx_power(mvm, vif, bss_conf->txpower); +		iwl_mvm_set_tx_power(mvm, bss_conf, bss_conf->txpower);  	}  } @@ -3347,7 +3357,7 @@ void iwl_mvm_mac_cancel_hw_scan(struct ieee80211_hw *hw,  	 * us to stop a hw_scan when it's already stopped.  This can  	 * happen, for instance, if we stopped the scan ourselves,  	 * called ieee80211_scan_completed() and the userspace called -	 * cancel scan scan before ieee80211_scan_work() could run. +	 * cancel scan before ieee80211_scan_work() could run.  	 * To handle that, simply return if the scan is not running.  	*/  	if (mvm->scan_status & IWL_MVM_SCAN_REGULAR) @@ -3430,7 +3440,7 @@ static void __iwl_mvm_mac_sta_notify(struct ieee80211_hw *hw,  		 */  		break;  	case STA_NOTIFY_AWAKE: -		if (WARN_ON(mvmsta->deflink.sta_id == IWL_MVM_INVALID_STA)) +		if (WARN_ON(mvmsta->deflink.sta_id == IWL_INVALID_STA))  			break;  		if (txqs) @@ -3510,6 +3520,8 @@ void iwl_mvm_sta_pre_rcu_remove(struct ieee80211_hw *hw,  	struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);  	unsigned int link_id; +	lockdep_assert_wiphy(mvm->hw->wiphy); +  	/*  	 * This is called before mac80211 does RCU synchronisation,  	 * so here we already invalidate our internal RCU-protected @@ -3893,7 +3905,7 @@ iwl_mvm_sta_state_notexist_to_none(struct iwl_mvm *mvm,  	if (sta->tdls &&  	    (vif->p2p || -	     iwl_mvm_tdls_sta_count(mvm, NULL) == IWL_MVM_TDLS_STA_COUNT || +	     iwl_mvm_tdls_sta_count(mvm, NULL) == IWL_TDLS_STA_COUNT ||  	     iwl_mvm_phy_ctx_count(mvm) > 1)) {  		IWL_DEBUG_MAC80211(mvm, "refusing TDLS sta\n");  		return -EBUSY; @@ -4091,15 +4103,28 @@ iwl_mvm_sta_state_authorized_to_assoc(struct iwl_mvm *mvm,  					  &mvmvif->mlo_int_scan_wk);  		wiphy_work_cancel(mvm->hw->wiphy, &mvmvif->unblock_esr_tpt_wk); - -		/* No need for the periodic statistics anymore */ -		if (ieee80211_vif_is_mld(vif) && mvmvif->esr_active) -			iwl_mvm_request_periodic_system_statistics(mvm, false); +		wiphy_delayed_work_cancel(mvm->hw->wiphy, +					  &mvmvif->unblock_esr_tmp_non_bss_wk);  	}  	return 0;  } +void iwl_mvm_smps_workaround(struct iwl_mvm *mvm, struct ieee80211_vif *vif, +			     bool update) +{ +	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + +	if (!iwl_mvm_has_rlc_offload(mvm) || +	    iwl_fw_lookup_cmd_ver(mvm->fw, MAC_PM_POWER_TABLE, 0) >= 2) +		return; + +	mvmvif->ps_disabled = !vif->cfg.ps; + +	if (update) +		iwl_mvm_power_update_mac(mvm); +} +  /* Common part for MLD and non-MLD modes */  int iwl_mvm_mac_sta_state_common(struct ieee80211_hw *hw,  				 struct ieee80211_vif *vif, @@ -4192,6 +4217,7 @@ int iwl_mvm_mac_sta_state_common(struct ieee80211_hw *hw,  		   new_state == IEEE80211_STA_AUTHORIZED) {  		ret = iwl_mvm_sta_state_assoc_to_authorized(mvm, vif, sta,  							    callbacks); +		iwl_mvm_smps_workaround(mvm, vif, true);  	} else if (old_state == IEEE80211_STA_AUTHORIZED &&  		   new_state == IEEE80211_STA_ASSOC) {  		ret = iwl_mvm_sta_state_authorized_to_assoc(mvm, vif, sta, @@ -4242,7 +4268,8 @@ int iwl_mvm_mac_sta_state_common(struct ieee80211_hw *hw,  	return ret;  } -int iwl_mvm_mac_set_rts_threshold(struct ieee80211_hw *hw, u32 value) +int iwl_mvm_mac_set_rts_threshold(struct ieee80211_hw *hw, int radio_idx, +				  u32 value)  {  	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); @@ -4252,8 +4279,9 @@ int iwl_mvm_mac_set_rts_threshold(struct ieee80211_hw *hw, u32 value)  }  void iwl_mvm_sta_rc_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif, -			   struct ieee80211_sta *sta, u32 changed) +			   struct ieee80211_link_sta *link_sta, u32 changed)  { +	struct ieee80211_sta *sta = link_sta->sta;  	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);  	if (changed & (IEEE80211_RC_BW_CHANGED | @@ -4342,7 +4370,7 @@ int iwl_mvm_mac_sched_scan_stop(struct ieee80211_hw *hw,  	 * us to stop a sched_scan when it's already stopped.  This  	 * can happen, for instance, if we stopped the scan ourselves,  	 * called ieee80211_sched_scan_stopped() and the userspace called -	 * stop sched scan scan before ieee80211_sched_scan_stopped_work() +	 * stop sched scan before ieee80211_sched_scan_stopped_work()  	 * could run.  To handle this, simply return if the scan is  	 * not running.  	*/ @@ -4379,7 +4407,7 @@ static int __iwl_mvm_mac_set_key(struct ieee80211_hw *hw,  	switch (key->cipher) {  	case WLAN_CIPHER_SUITE_TKIP: -		if (!mvm->trans->trans_cfg->gen2) { +		if (!mvm->trans->mac_cfg->gen2) {  			key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;  			key->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE;  		} else if (vif->type == NL80211_IFTYPE_STATION) { @@ -4496,7 +4524,7 @@ static int __iwl_mvm_mac_set_key(struct ieee80211_hw *hw,  			WARN_ON(rcu_access_pointer(mvmsta->ptk_pn[keyidx]));  			ptk_pn = kzalloc(struct_size(ptk_pn, q, -						     mvm->trans->num_rx_queues), +						     mvm->trans->info.num_rxqs),  					 GFP_KERNEL);  			if (!ptk_pn) {  				ret = -ENOMEM; @@ -4505,7 +4533,7 @@ static int __iwl_mvm_mac_set_key(struct ieee80211_hw *hw,  			for (tid = 0; tid < IWL_MAX_TID_COUNT; tid++) {  				ieee80211_get_key_rx_seq(key, tid, &seq); -				for (q = 0; q < mvm->trans->num_rx_queues; q++) +				for (q = 0; q < mvm->trans->info.num_rxqs; q++)  					memcpy(ptk_pn->q[q].pn[tid],  					       seq.ccmp.pn,  					       IEEE80211_CCMP_PN_LEN); @@ -4606,6 +4634,10 @@ int iwl_mvm_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,  {  	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); +	/* When resuming from wowlan, FW already knows about the newest keys */ +	if (test_bit(IWL_MVM_STATUS_IN_D3, &mvm->status)) +		return 0; +  	guard(mvm)(mvm);  	return __iwl_mvm_mac_set_key(hw, cmd, vif, sta, key);  } @@ -4981,34 +5013,46 @@ int iwl_mvm_cancel_roc(struct ieee80211_hw *hw,  	return 0;  } -struct iwl_mvm_ftm_responder_iter_data { -	bool responder; +struct iwl_mvm_chanctx_usage_data { +	struct iwl_mvm *mvm;  	struct ieee80211_chanctx_conf *ctx; +	bool use_def;  }; -static void iwl_mvm_ftm_responder_chanctx_iter(void *_data, u8 *mac, -					       struct ieee80211_vif *vif) +static void iwl_mvm_chanctx_usage_iter(void *_data, u8 *mac, +				       struct ieee80211_vif *vif)  { -	struct iwl_mvm_ftm_responder_iter_data *data = _data; +	struct iwl_mvm_chanctx_usage_data *data = _data; +	struct ieee80211_bss_conf *link_conf; +	int link_id; + +	for_each_vif_active_link(vif, link_conf, link_id) { +		if (rcu_access_pointer(link_conf->chanctx_conf) != data->ctx) +			continue; + +		if (iwl_mvm_enable_fils(data->mvm, vif, data->ctx)) +			data->use_def = true; -	if (rcu_access_pointer(vif->bss_conf.chanctx_conf) == data->ctx && -	    vif->type == NL80211_IFTYPE_AP && vif->bss_conf.ftmr_params) -		data->responder = true; +		if (vif->type == NL80211_IFTYPE_AP && link_conf->ftmr_params) +			data->use_def = true; +	}  } -bool iwl_mvm_is_ftm_responder_chanctx(struct iwl_mvm *mvm, -				      struct ieee80211_chanctx_conf *ctx) +struct cfg80211_chan_def * +iwl_mvm_chanctx_def(struct iwl_mvm *mvm, struct ieee80211_chanctx_conf *ctx)  { -	struct iwl_mvm_ftm_responder_iter_data data = { -		.responder = false, +	struct iwl_mvm_chanctx_usage_data data = { +		.mvm = mvm,  		.ctx = ctx, +		.use_def = false,  	};  	ieee80211_iterate_active_interfaces_atomic(mvm->hw, -					IEEE80211_IFACE_ITER_NORMAL, -					iwl_mvm_ftm_responder_chanctx_iter, -					&data); -	return data.responder; +						   IEEE80211_IFACE_ITER_NORMAL, +						   iwl_mvm_chanctx_usage_iter, +						   &data); + +	return data.use_def ? &ctx->def : &ctx->min_def;  }  static int __iwl_mvm_add_chanctx(struct iwl_mvm *mvm, @@ -5083,7 +5127,7 @@ void iwl_mvm_change_chanctx(struct ieee80211_hw *hw,  		      (changed & ~(IEEE80211_CHANCTX_CHANGE_WIDTH |  				   IEEE80211_CHANCTX_CHANGE_RX_CHAINS |  				   IEEE80211_CHANCTX_CHANGE_RADAR | -				   IEEE80211_CHANCTX_CHANGE_MIN_WIDTH)), +				   IEEE80211_CHANCTX_CHANGE_MIN_DEF)),  		      "Cannot change PHY. Ref=%d, changed=0x%X\n",  		      phy_ctxt->ref, changed))  		return; @@ -5091,7 +5135,7 @@ void iwl_mvm_change_chanctx(struct ieee80211_hw *hw,  	guard(mvm)(mvm);  	/* we are only changing the min_width, may be a noop */ -	if (changed == IEEE80211_CHANCTX_CHANGE_MIN_WIDTH) { +	if (changed == IEEE80211_CHANCTX_CHANGE_MIN_DEF) {  		if (phy_ctxt->width == def->width)  			return; @@ -5392,7 +5436,7 @@ out_reassign:  out_restart:  	/* things keep failing, better restart the hw */ -	iwl_mvm_nic_restart(mvm, false); +	iwl_force_nmi(mvm->trans);  	return ret;  } @@ -5428,7 +5472,7 @@ out_reassign:  out_restart:  	/* things keep failing, better restart the hw */ -	iwl_mvm_nic_restart(mvm, false); +	iwl_force_nmi(mvm->trans);  	return ret;  } @@ -5497,70 +5541,6 @@ static int iwl_mvm_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta,  					       &mvm_sta->vif->bss_conf);  } -#ifdef CONFIG_NL80211_TESTMODE -static const struct nla_policy iwl_mvm_tm_policy[IWL_MVM_TM_ATTR_MAX + 1] = { -	[IWL_MVM_TM_ATTR_CMD] = { .type = NLA_U32 }, -	[IWL_MVM_TM_ATTR_NOA_DURATION] = { .type = NLA_U32 }, -	[IWL_MVM_TM_ATTR_BEACON_FILTER_STATE] = { .type = NLA_U32 }, -}; - -static int __iwl_mvm_mac_testmode_cmd(struct iwl_mvm *mvm, -				      struct ieee80211_vif *vif, -				      void *data, int len) -{ -	struct nlattr *tb[IWL_MVM_TM_ATTR_MAX + 1]; -	int err; -	u32 noa_duration; - -	err = nla_parse_deprecated(tb, IWL_MVM_TM_ATTR_MAX, data, len, -				   iwl_mvm_tm_policy, NULL); -	if (err) -		return err; - -	if (!tb[IWL_MVM_TM_ATTR_CMD]) -		return -EINVAL; - -	switch (nla_get_u32(tb[IWL_MVM_TM_ATTR_CMD])) { -	case IWL_MVM_TM_CMD_SET_NOA: -		if (!vif || vif->type != NL80211_IFTYPE_AP || !vif->p2p || -		    !vif->bss_conf.enable_beacon || -		    !tb[IWL_MVM_TM_ATTR_NOA_DURATION]) -			return -EINVAL; - -		noa_duration = nla_get_u32(tb[IWL_MVM_TM_ATTR_NOA_DURATION]); -		if (noa_duration >= vif->bss_conf.beacon_int) -			return -EINVAL; - -		mvm->noa_duration = noa_duration; -		mvm->noa_vif = vif; - -		return iwl_mvm_update_quotas(mvm, true, NULL); -	case IWL_MVM_TM_CMD_SET_BEACON_FILTER: -		/* must be associated client vif - ignore authorized */ -		if (!vif || vif->type != NL80211_IFTYPE_STATION || -		    !vif->cfg.assoc || !vif->bss_conf.dtim_period || -		    !tb[IWL_MVM_TM_ATTR_BEACON_FILTER_STATE]) -			return -EINVAL; - -		if (nla_get_u32(tb[IWL_MVM_TM_ATTR_BEACON_FILTER_STATE])) -			return iwl_mvm_enable_beacon_filter(mvm, vif); -		return iwl_mvm_disable_beacon_filter(mvm, vif); -	} - -	return -EOPNOTSUPP; -} - -int iwl_mvm_mac_testmode_cmd(struct ieee80211_hw *hw, -			     struct ieee80211_vif *vif, -			     void *data, int len) -{ -	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); - -	guard(mvm)(mvm); -	return __iwl_mvm_mac_testmode_cmd(mvm, vif, data, len); -} -#endif -  void iwl_mvm_channel_switch(struct ieee80211_hw *hw, struct ieee80211_vif *vif,  			    struct ieee80211_channel_switch *chsw)  { @@ -6112,12 +6092,12 @@ static void iwl_mvm_set_sta_rate(u32 rate_n_flags, struct rate_info *rinfo)  		break;  	} -	if (format == RATE_MCS_CCK_MSK || -	    format == RATE_MCS_LEGACY_OFDM_MSK) { +	if (format == RATE_MCS_MOD_TYPE_CCK || +	    format == RATE_MCS_MOD_TYPE_LEGACY_OFDM) {  		int rate = u32_get_bits(rate_n_flags, RATE_LEGACY_RATE_MSK);  		/* add the offset needed to get to the legacy ofdm indices */ -		if (format == RATE_MCS_LEGACY_OFDM_MSK) +		if (format == RATE_MCS_MOD_TYPE_LEGACY_OFDM)  			rate += IWL_FIRST_OFDM_RATE;  		switch (rate) { @@ -6162,7 +6142,7 @@ static void iwl_mvm_set_sta_rate(u32 rate_n_flags, struct rate_info *rinfo)  	rinfo->nss = u32_get_bits(rate_n_flags,  				  RATE_MCS_NSS_MSK) + 1; -	rinfo->mcs = format == RATE_MCS_HT_MSK ? +	rinfo->mcs = format == RATE_MCS_MOD_TYPE_HT ?  		RATE_HT_MCS_INDEX(rate_n_flags) :  		u32_get_bits(rate_n_flags, RATE_MCS_CODE_MSK); @@ -6170,11 +6150,11 @@ static void iwl_mvm_set_sta_rate(u32 rate_n_flags, struct rate_info *rinfo)  		rinfo->flags |= RATE_INFO_FLAGS_SHORT_GI;  	switch (format) { -	case RATE_MCS_EHT_MSK: +	case RATE_MCS_MOD_TYPE_EHT:  		/* TODO: GI/LTF/RU. How does the firmware encode them? */  		rinfo->flags |= RATE_INFO_FLAGS_EHT_MCS;  		break; -	case RATE_MCS_HE_MSK: +	case RATE_MCS_MOD_TYPE_HE:  		gi_ltf = u32_get_bits(rate_n_flags, RATE_MCS_HE_GI_LTF_MSK);  		rinfo->flags |= RATE_INFO_FLAGS_HE_MCS; @@ -6215,10 +6195,10 @@ static void iwl_mvm_set_sta_rate(u32 rate_n_flags, struct rate_info *rinfo)  		if (rate_n_flags & RATE_HE_DUAL_CARRIER_MODE_MSK)  			rinfo->he_dcm = 1;  		break; -	case RATE_MCS_HT_MSK: +	case RATE_MCS_MOD_TYPE_HT:  		rinfo->flags |= RATE_INFO_FLAGS_MCS;  		break; -	case RATE_MCS_VHT_MSK: +	case RATE_MCS_MOD_TYPE_VHT:  		rinfo->flags |= RATE_INFO_FLAGS_VHT_MCS;  		break;  	} @@ -6255,7 +6235,7 @@ void iwl_mvm_mac_sta_statistics(struct ieee80211_hw *hw,  	guard(mvm)(mvm); -	if (mvmvif->deflink.ap_sta_id != mvmsta->deflink.sta_id) +	if (sta != mvmvif->ap_sta)  		return;  	if (iwl_mvm_request_statistics(mvm, false)) @@ -6398,37 +6378,36 @@ void iwl_mvm_sync_rx_queues_internal(struct iwl_mvm *mvm,  				     bool sync,  				     const void *data, u32 size)  { -	struct { -		struct iwl_rxq_sync_cmd cmd; -		struct iwl_mvm_internal_rxq_notif notif; -	} __packed cmd = { -		.cmd.rxq_mask = cpu_to_le32(BIT(mvm->trans->num_rx_queues) - 1), -		.cmd.count = -			cpu_to_le32(sizeof(struct iwl_mvm_internal_rxq_notif) + -				    size), -		.notif.type = type, -		.notif.sync = sync, -	}; +	DEFINE_RAW_FLEX(struct iwl_rxq_sync_cmd, cmd, payload, +			sizeof(struct iwl_mvm_internal_rxq_notif)); +	struct iwl_mvm_internal_rxq_notif *notif = +			(struct iwl_mvm_internal_rxq_notif *)cmd->payload;  	struct iwl_host_cmd hcmd = {  		.id = WIDE_ID(DATA_PATH_GROUP, TRIGGER_RX_QUEUES_NOTIF_CMD), -		.data[0] = &cmd, -		.len[0] = sizeof(cmd), +		.data[0] = cmd, +		.len[0] = __struct_size(cmd),  		.data[1] = data,  		.len[1] = size,  		.flags = CMD_SEND_IN_RFKILL | (sync ? 0 : CMD_ASYNC),  	};  	int ret; +	cmd->rxq_mask = cpu_to_le32(BIT(mvm->trans->info.num_rxqs) - 1); +	cmd->count = cpu_to_le32(sizeof(struct iwl_mvm_internal_rxq_notif) + +				 size); +	notif->type = type; +	notif->sync = sync; +  	/* size must be a multiple of DWORD */ -	if (WARN_ON(cmd.cmd.count & cpu_to_le32(3))) +	if (WARN_ON(cmd->count & cpu_to_le32(3)))  		return;  	if (!iwl_mvm_has_new_rx_api(mvm))  		return;  	if (sync) { -		cmd.notif.cookie = mvm->queue_sync_cookie; -		mvm->queue_sync_state = (1 << mvm->trans->num_rx_queues) - 1; +		notif->cookie = mvm->queue_sync_cookie; +		mvm->queue_sync_state = (1 << mvm->trans->info.num_rxqs) - 1;  	}  	ret = iwl_mvm_send_cmd(mvm, &hcmd); @@ -6578,7 +6557,7 @@ const struct ieee80211_ops iwl_mvm_hw_ops = {  	.allow_buffered_frames = iwl_mvm_mac_allow_buffered_frames,  	.release_buffered_frames = iwl_mvm_mac_release_buffered_frames,  	.set_rts_threshold = iwl_mvm_mac_set_rts_threshold, -	.sta_rc_update = iwl_mvm_sta_rc_update, +	.link_sta_rc_update = iwl_mvm_sta_rc_update,  	.conf_tx = iwl_mvm_mac_conf_tx,  	.mgd_prepare_tx = iwl_mvm_mac_mgd_prepare_tx,  	.mgd_complete_tx = iwl_mvm_mac_mgd_complete_tx, @@ -6621,8 +6600,6 @@ const struct ieee80211_ops iwl_mvm_hw_ops = {  	.sync_rx_queues = iwl_mvm_sync_rx_queues, -	CFG80211_TESTMODE_CMD(iwl_mvm_mac_testmode_cmd) -  #ifdef CONFIG_PM_SLEEP  	/* look at d3.c */  	.suspend = iwl_mvm_suspend, diff --git a/sys/contrib/dev/iwlwifi/mvm/mld-key.c b/sys/contrib/dev/iwlwifi/mvm/mld-key.c index 8a38fc4b0b0f..ef0be44207e1 100644 --- a/sys/contrib/dev/iwlwifi/mvm/mld-key.c +++ b/sys/contrib/dev/iwlwifi/mvm/mld-key.c @@ -144,7 +144,7 @@ static void iwl_mvm_mld_update_sta_key(struct ieee80211_hw *hw,  	if (sta != data->sta || key->link_id >= 0)  		return; -	err = iwl_mvm_send_cmd_pdu(mvm, cmd_id, CMD_ASYNC, sizeof(cmd), &cmd); +	err = iwl_mvm_send_cmd_pdu(mvm, cmd_id, 0, sizeof(cmd), &cmd);  	if (err)  		data->err = err; @@ -162,8 +162,8 @@ int iwl_mvm_mld_update_sta_keys(struct iwl_mvm *mvm,  		.new_sta_mask = new_sta_mask,  	}; -	ieee80211_iter_keys_rcu(mvm->hw, vif, iwl_mvm_mld_update_sta_key, -				&data); +	ieee80211_iter_keys(mvm->hw, vif, iwl_mvm_mld_update_sta_key, +			    &data);  	return data.err;  } @@ -396,13 +396,13 @@ void iwl_mvm_sec_key_remove_ap(struct iwl_mvm *mvm,  	u8 sec_key_ver = iwl_fw_lookup_cmd_ver(mvm->fw, sec_key_id, 0);  	if (WARN_ON_ONCE(vif->type != NL80211_IFTYPE_STATION || -			 link->ap_sta_id == IWL_MVM_INVALID_STA)) +			 link->ap_sta_id == IWL_INVALID_STA))  		return;  	if (!sec_key_ver)  		return; -	ieee80211_iter_keys_rcu(mvm->hw, vif, -				iwl_mvm_sec_key_remove_ap_iter, -				(void *)(uintptr_t)link_id); +	ieee80211_iter_keys(mvm->hw, vif, +			    iwl_mvm_sec_key_remove_ap_iter, +			    (void *)(uintptr_t)link_id);  } diff --git a/sys/contrib/dev/iwlwifi/mvm/mld-mac.c b/sys/contrib/dev/iwlwifi/mvm/mld-mac.c index bb7851042177..2d116a41913c 100644 --- a/sys/contrib/dev/iwlwifi/mvm/mld-mac.c +++ b/sys/contrib/dev/iwlwifi/mvm/mld-mac.c @@ -1,17 +1,25 @@  // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause  /* - * Copyright (C) 2022 - 2024 Intel Corporation + * Copyright (C) 2022 - 2025 Intel Corporation   */  #include "mvm.h"  static void iwl_mvm_mld_set_he_support(struct iwl_mvm *mvm,  				       struct ieee80211_vif *vif, -				       struct iwl_mac_config_cmd *cmd) +				       struct iwl_mac_config_cmd *cmd, +				       int cmd_ver)  { -	if (vif->type == NL80211_IFTYPE_AP) -		cmd->he_ap_support = cpu_to_le16(1); -	else -		cmd->he_support = cpu_to_le16(1); +	if (vif->type == NL80211_IFTYPE_AP) { +		if (cmd_ver == 2) +			cmd->wifi_gen_v2.he_ap_support = cpu_to_le16(1); +		else +			cmd->wifi_gen.he_ap_support = 1; +	} else { +		if (cmd_ver == 2) +			cmd->wifi_gen_v2.he_support = cpu_to_le16(1); +		else +			cmd->wifi_gen.he_support = 1; +	}  }  static void iwl_mvm_mld_mac_ctxt_cmd_common(struct iwl_mvm *mvm, @@ -22,6 +30,12 @@ static void iwl_mvm_mld_mac_ctxt_cmd_common(struct iwl_mvm *mvm,  	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);  	struct ieee80211_bss_conf *link_conf;  	unsigned int link_id; +	int cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, +					    WIDE_ID(MAC_CONF_GROUP, +						    MAC_CONFIG_CMD), 1); + +	if (WARN_ON(cmd_ver > 3)) +		return;  	cmd->id_and_color = cpu_to_le32(mvmvif->id);  	cmd->action = cpu_to_le32(action); @@ -30,8 +44,8 @@ static void iwl_mvm_mld_mac_ctxt_cmd_common(struct iwl_mvm *mvm,  	memcpy(cmd->local_mld_addr, vif->addr, ETH_ALEN); -	cmd->he_support = 0; -	cmd->eht_support = 0; +	cmd->wifi_gen_v2.he_support = 0; +	cmd->wifi_gen_v2.eht_support = 0;  	/* should be set by specific context type handler */  	cmd->filter_flags = 0; @@ -51,8 +65,11 @@ static void iwl_mvm_mld_mac_ctxt_cmd_common(struct iwl_mvm *mvm,  	 * and enable both when we have MLO.  	 */  	if (ieee80211_vif_is_mld(vif)) { -		iwl_mvm_mld_set_he_support(mvm, vif, cmd); -		cmd->eht_support = cpu_to_le32(1); +		iwl_mvm_mld_set_he_support(mvm, vif, cmd, cmd_ver); +		if (cmd_ver == 2) +			cmd->wifi_gen_v2.eht_support = cpu_to_le32(1); +		else +			cmd->wifi_gen.eht_support = 1;  		return;  	} @@ -63,16 +80,19 @@ static void iwl_mvm_mld_mac_ctxt_cmd_common(struct iwl_mvm *mvm,  			continue;  		if (link_conf->he_support) -			iwl_mvm_mld_set_he_support(mvm, vif, cmd); +			iwl_mvm_mld_set_he_support(mvm, vif, cmd, cmd_ver); -		/* it's not reasonable to have EHT without HE and FW API doesn't +		/* It's not reasonable to have EHT without HE and FW API doesn't  		 * support it. Ignore EHT in this case.  		 */  		if (!link_conf->he_support && link_conf->eht_support)  			continue;  		if (link_conf->eht_support) { -			cmd->eht_support = cpu_to_le32(1); +			if (cmd_ver == 2) +				cmd->wifi_gen_v2.eht_support = cpu_to_le32(1); +			else +				cmd->wifi_gen.eht_support = 1;  			break;  		}  	} @@ -262,9 +282,6 @@ int iwl_mvm_mld_mac_ctxt_add(struct iwl_mvm *mvm, struct ieee80211_vif *vif)  	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);  	int ret; -	if (WARN_ON_ONCE(vif->type == NL80211_IFTYPE_NAN)) -		return -EOPNOTSUPP; -  	if (WARN_ONCE(mvmvif->uploaded, "Adding active MAC %pM/%d\n",  		      vif->addr, ieee80211_vif_type_p2p(vif)))  		return -EIO; @@ -287,9 +304,6 @@ int iwl_mvm_mld_mac_ctxt_changed(struct iwl_mvm *mvm,  {  	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); -	if (WARN_ON_ONCE(vif->type == NL80211_IFTYPE_NAN)) -		return -EOPNOTSUPP; -  	if (WARN_ONCE(!mvmvif->uploaded, "Changing inactive MAC %pM/%d\n",  		      vif->addr, ieee80211_vif_type_p2p(vif)))  		return -EIO; @@ -307,9 +321,6 @@ int iwl_mvm_mld_mac_ctxt_remove(struct iwl_mvm *mvm, struct ieee80211_vif *vif)  	};  	int ret; -	if (WARN_ON_ONCE(vif->type == NL80211_IFTYPE_NAN)) -		return -EOPNOTSUPP; -  	if (WARN_ONCE(!mvmvif->uploaded, "Removing inactive MAC %pM/%d\n",  		      vif->addr, ieee80211_vif_type_p2p(vif)))  		return -EIO; diff --git a/sys/contrib/dev/iwlwifi/mvm/mld-mac80211.c b/sys/contrib/dev/iwlwifi/mvm/mld-mac80211.c index 3c99396ad369..bf24f8cb673e 100644 --- a/sys/contrib/dev/iwlwifi/mvm/mld-mac80211.c +++ b/sys/contrib/dev/iwlwifi/mvm/mld-mac80211.c @@ -1,6 +1,6 @@  // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause  /* - * Copyright (C) 2022-2024 Intel Corporation + * Copyright (C) 2022-2025 Intel Corporation   */  #include "mvm.h" @@ -18,6 +18,8 @@ static int iwl_mvm_mld_mac_add_interface(struct ieee80211_hw *hw,  	mvmvif->mvm = mvm; +	vif->driver_flags |= IEEE80211_VIF_REMOVE_AP_AFTER_DISASSOC; +  	/* Not much to do here. The stack will not allow interface  	 * types or combinations that we didn't advertise, so we  	 * don't really have to check the types. @@ -41,8 +43,6 @@ static int iwl_mvm_mld_mac_add_interface(struct ieee80211_hw *hw,  	/* reset deflink MLO parameters */  	mvmvif->deflink.fw_link_id = IWL_MVM_FW_LINK_ID_INVALID;  	mvmvif->deflink.active = 0; -	/* the first link always points to the default one */ -	mvmvif->link[0] = &mvmvif->deflink;  	ret = iwl_mvm_mld_mac_ctxt_add(mvm, vif);  	if (ret) @@ -60,9 +60,19 @@ static int iwl_mvm_mld_mac_add_interface(struct ieee80211_hw *hw,  				     IEEE80211_VIF_SUPPORTS_CQM_RSSI;  	} -	ret = iwl_mvm_add_link(mvm, vif, &vif->bss_conf); -	if (ret) -		goto out_free_bf; +	/* We want link[0] to point to the default link, unless we have MLO and +	 * in this case this will be modified later by .change_vif_links() +	 * If we are in the restart flow with an MLD connection, we will wait +	 * to .change_vif_links() to setup the links. +	 */ +	if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) || +	    !ieee80211_vif_is_mld(vif)) { +		mvmvif->link[0] = &mvmvif->deflink; + +		ret = iwl_mvm_add_link(mvm, vif, &vif->bss_conf); +		if (ret) +			goto out_free_bf; +	}  	/* Save a pointer to p2p device vif, so it can later be used to  	 * update the p2p device MAC when a GO is started/stopped @@ -140,19 +150,6 @@ static void iwl_mvm_mld_mac_remove_interface(struct ieee80211_hw *hw,  	iwl_mvm_vif_dbgfs_rm_link(mvm, vif); -	/* For AP/GO interface, the tear down of the resources allocated to the -	 * interface is be handled as part of the stop_ap flow. -	 */ -	if (vif->type == NL80211_IFTYPE_AP || -	    vif->type == NL80211_IFTYPE_ADHOC) { -#ifdef CONFIG_NL80211_TESTMODE -		if (vif == mvm->noa_vif) { -			mvm->noa_vif = NULL; -			mvm->noa_duration = 0; -		} -#endif -	} -  	iwl_mvm_power_update_mac(mvm);  	/* Before the interface removal, mac80211 would cancel the ROC, and the @@ -200,32 +197,6 @@ static unsigned int iwl_mvm_mld_count_active_links(struct iwl_mvm_vif *mvmvif)  	return n_active;  } -static void iwl_mvm_restart_mpdu_count(struct iwl_mvm *mvm, -				       struct iwl_mvm_vif *mvmvif) -{ -	struct ieee80211_sta *ap_sta = mvmvif->ap_sta; -	struct iwl_mvm_sta *mvmsta; - -	lockdep_assert_held(&mvm->mutex); - -	if (!ap_sta) -		return; - -	mvmsta = iwl_mvm_sta_from_mac80211(ap_sta); -	if (!mvmsta->mpdu_counters) -		return; - -	for (int q = 0; q < mvm->trans->num_rx_queues; q++) { -		spin_lock_bh(&mvmsta->mpdu_counters[q].lock); -		memset(mvmsta->mpdu_counters[q].per_link, 0, -		       sizeof(mvmsta->mpdu_counters[q].per_link)); -		mvmsta->mpdu_counters[q].window_start = jiffies; -		spin_unlock_bh(&mvmsta->mpdu_counters[q].lock); -	} - -	IWL_DEBUG_STATS(mvm, "MPDU counters are cleared\n"); -} -  static int iwl_mvm_esr_mode_active(struct iwl_mvm *mvm,  				   struct ieee80211_vif *vif)  { @@ -259,15 +230,8 @@ static int iwl_mvm_esr_mode_active(struct iwl_mvm *mvm,  	else  		mvmvif->primary_link = __ffs(vif->active_links); -	/* Needed for tracking RSSI */ -	iwl_mvm_request_periodic_system_statistics(mvm, true); - -	/* -	 * Restart the MPDU counters and the counting window, so when the -	 * statistics arrive (which is where we look at the counters) we -	 * will be at the end of the window. -	 */ -	iwl_mvm_restart_mpdu_count(mvm, mvmvif); +	iwl_dbg_tlv_time_point(&mvm->fwrt, IWL_FW_INI_TIME_ESR_LINK_UP, +			       NULL);  	return ret;  } @@ -312,7 +276,6 @@ __iwl_mvm_mld_assign_vif_chanctx(struct iwl_mvm *mvm,  		ret = iwl_mvm_esr_mode_active(mvm, vif);  		if (ret) {  			IWL_ERR(mvm, "failed to activate ESR mode (%d)\n", ret); -			iwl_mvm_request_periodic_system_statistics(mvm, false);  			goto out;  		}  	} @@ -328,23 +291,18 @@ __iwl_mvm_mld_assign_vif_chanctx(struct iwl_mvm *mvm,  	if (ret)  		goto out; -	/* Initialize rate control for the AP station, since we might be -	 * doing a link switch here - we cannot initialize it before since -	 * this needs the phy context assigned (and in FW?), and we cannot -	 * do it later because it needs to be initialized as soon as we're -	 * able to TX on the link, i.e. when active. +	/* +	 * if link switching (link not active yet) we'll activate it in +	 * firmware later on link-info change, which mac80211 guarantees +	 * for link switch after the stations are set up  	 */ -	if (mvmvif->ap_sta) { -		struct ieee80211_link_sta *link_sta; - -		rcu_read_lock(); -		link_sta = rcu_dereference(mvmvif->ap_sta->link[link_id]); - -		if (!WARN_ON_ONCE(!link_sta)) -			iwl_mvm_rs_rate_init(mvm, vif, mvmvif->ap_sta, -					     link_conf, link_sta, -					     phy_ctxt->channel->band); -		rcu_read_unlock(); +	if (ieee80211_vif_link_active(vif, link_conf->link_id)) { +		ret = iwl_mvm_link_changed(mvm, vif, link_conf, +					   LINK_CONTEXT_MODIFY_ACTIVE | +					   LINK_CONTEXT_MODIFY_RATES_INFO, +					   true); +		if (ret) +			goto out;  	}  	if (vif->type == NL80211_IFTYPE_STATION) @@ -352,14 +310,6 @@ __iwl_mvm_mld_assign_vif_chanctx(struct iwl_mvm *mvm,  							link_conf,  							false); -	/* then activate */ -	ret = iwl_mvm_link_changed(mvm, vif, link_conf, -				   LINK_CONTEXT_MODIFY_ACTIVE | -				   LINK_CONTEXT_MODIFY_RATES_INFO, -				   true); -	if (ret) -		goto out; -  	/*  	 * Power state must be updated before quotas,  	 * otherwise fw will complain. @@ -451,10 +401,8 @@ static int iwl_mvm_esr_mode_inactive(struct iwl_mvm *mvm,  			break;  	} -	iwl_mvm_request_periodic_system_statistics(mvm, false); - -	/* Start a new counting window */ -	iwl_mvm_restart_mpdu_count(mvm, mvmvif); +	iwl_dbg_tlv_time_point(&mvm->fwrt, IWL_FW_INI_TIME_ESR_LINK_DOWN, +			       NULL);  	return ret;  } @@ -769,6 +717,11 @@ iwl_mvm_mld_link_info_changed_station(struct iwl_mvm *mvm,  	if (WARN_ON_ONCE(!mvmvif->link[link_conf->link_id]))  		return; +	/* not yet marked active in vif means during link switch */ +	if (!ieee80211_vif_link_active(vif, link_conf->link_id) && +	    vif->cfg.assoc && mvmvif->link[link_conf->link_id]->phy_ctxt) +		link_changes |= LINK_CONTEXT_MODIFY_ACTIVE; +  	has_he = link_conf->he_support && !iwlwifi_mod_params.disable_11ax;  	has_eht = link_conf->eht_support && !iwlwifi_mod_params.disable_11be; @@ -818,37 +771,13 @@ static bool iwl_mvm_mld_vif_have_valid_ap_sta(struct iwl_mvm_vif *mvmvif)  	int i;  	for_each_mvm_vif_valid_link(mvmvif, i) { -		if (mvmvif->link[i]->ap_sta_id != IWL_MVM_INVALID_STA) +		if (mvmvif->link[i]->ap_sta_id != IWL_INVALID_STA)  			return true;  	}  	return false;  } -static void iwl_mvm_mld_vif_delete_all_stas(struct iwl_mvm *mvm, -					    struct ieee80211_vif *vif) -{ -	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); -	int i, ret; - -	if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) -		return; - -	for_each_mvm_vif_valid_link(mvmvif, i) { -		struct iwl_mvm_vif_link_info *link = mvmvif->link[i]; - -		if (!link) -			continue; - -		iwl_mvm_sec_key_remove_ap(mvm, vif, link, i); -		ret = iwl_mvm_mld_rm_sta_id(mvm, link->ap_sta_id); -		if (ret) -			IWL_ERR(mvm, "failed to remove AP station\n"); - -		link->ap_sta_id = IWL_MVM_INVALID_STA; -	} -} -  static void iwl_mvm_mld_vif_cfg_changed_station(struct iwl_mvm *mvm,  						struct ieee80211_vif *vif,  						u64 changes) @@ -875,8 +804,13 @@ static void iwl_mvm_mld_vif_cfg_changed_station(struct iwl_mvm *mvm,  		if (vif->cfg.assoc) {  			mvmvif->session_prot_connection_loss = false; -			/* clear statistics to get clean beacon counter */ +			/* +			 * Clear statistics to get clean beacon counter, and ask for +			 * periodic statistics, as they are needed for link +			 * selection and RX OMI decisions. +			 */  			iwl_mvm_request_statistics(mvm, true); +			iwl_mvm_request_periodic_system_statistics(mvm, true);  			iwl_mvm_sf_update(mvm, vif, false);  			iwl_mvm_power_vif_assoc(mvm, vif); @@ -924,6 +858,8 @@ static void iwl_mvm_mld_vif_cfg_changed_station(struct iwl_mvm *mvm,  		} else if (iwl_mvm_mld_vif_have_valid_ap_sta(mvmvif)) {  			iwl_mvm_mei_host_disassociated(mvm); +			iwl_mvm_request_periodic_system_statistics(mvm, false); +  			/* If update fails - SF might be running in associated  			 * mode while disassociated - which is forbidden.  			 */ @@ -932,21 +868,13 @@ static void iwl_mvm_mld_vif_cfg_changed_station(struct iwl_mvm *mvm,  				  !test_bit(IWL_MVM_STATUS_HW_RESTART_REQUESTED,  					    &mvm->status),  				  "Failed to update SF upon disassociation\n"); - -			/* If we get an assert during the connection (after the -			 * station has been added, but before the vif is set -			 * to associated), mac80211 will re-add the station and -			 * then configure the vif. Since the vif is not -			 * associated, we would remove the station here and -			 * this would fail the recovery. -			 */ -			iwl_mvm_mld_vif_delete_all_stas(mvm, vif);  		}  		iwl_mvm_bss_info_changed_station_assoc(mvm, vif, changes);  	}  	if (changes & BSS_CHANGED_PS) { +		iwl_mvm_smps_workaround(mvm, vif, false);  		ret = iwl_mvm_power_update_mac(mvm);  		if (ret)  			IWL_ERR(mvm, "failed to update power mode\n"); @@ -1032,7 +960,7 @@ static void iwl_mvm_mld_link_info_changed(struct ieee80211_hw *hw,  	if (changes & BSS_CHANGED_TXPOWER) {  		IWL_DEBUG_CALIB(mvm, "Changing TX Power to %d dBm\n",  				link_conf->txpower); -		iwl_mvm_set_tx_power(mvm, vif, link_conf->txpower); +		iwl_mvm_set_tx_power(mvm, link_conf, link_conf->txpower);  	}  } @@ -1163,8 +1091,6 @@ iwl_mvm_mld_change_vif_links(struct ieee80211_hw *hw,  	int err, i;  	for (i = 0; i < IEEE80211_MLD_MAX_NUM_LINKS; i++) { -		int r; -  		if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))  			break; @@ -1176,19 +1102,17 @@ iwl_mvm_mld_change_vif_links(struct ieee80211_hw *hw,  			goto free;  		} -		new_link[i]->bcast_sta.sta_id = IWL_MVM_INVALID_STA; -		new_link[i]->mcast_sta.sta_id = IWL_MVM_INVALID_STA; -		new_link[i]->ap_sta_id = IWL_MVM_INVALID_STA;  		new_link[i]->fw_link_id = IWL_MVM_FW_LINK_ID_INVALID; - -		for (r = 0; r < NUM_IWL_MVM_SMPS_REQ; r++) -			new_link[i]->smps_requests[r] = -				IEEE80211_SMPS_AUTOMATIC; +		iwl_mvm_init_link(new_link[i]);  	}  	mutex_lock(&mvm->mutex); -	if (old_links == 0) { +	/* If we're in RESTART flow, the default link wasn't added in +         * drv_add_interface(), and link[0] doesn't point to it. +	 */ +	if (old_links == 0 && !test_bit(IWL_MVM_STATUS_IN_HW_RESTART, +					&mvm->status)) {  		err = iwl_mvm_disable_link(mvm, vif, &vif->bss_conf);  		if (err)  			goto out_err; @@ -1335,6 +1259,22 @@ iwl_mvm_mld_mac_pre_channel_switch(struct ieee80211_hw *hw,  		else  			selected = primary; +		/* +		 * remembers to tell the firmware that this link can't tx +		 * Note that this logic seems to be unrelated to esr, but it +		 * really is needed only when esr is active. When we have a +		 * single link, the firmware will handle all this on its own. +		 * In multi-link scenarios, we can learn about the CSA from +		 * another link and this logic is too complex for the firmware +		 * to track. +		 * Since we want to de-activate the link that got a CSA, we +		 * need to tell the firmware not to send any frame on that link +		 * as the firmware may not be aware that link is under a CSA +		 * with mode=1 (no Tx allowed). +		 */ +		if (chsw->block_tx && mvmvif->link[chsw->link_id]) +			mvmvif->link[chsw->link_id]->csa_block_tx = true; +  		iwl_mvm_exit_esr(mvm, vif, IWL_MVM_ESR_EXIT_CSA, selected);  		mutex_unlock(&mvm->mutex); @@ -1354,6 +1294,36 @@ iwl_mvm_mld_mac_pre_channel_switch(struct ieee80211_hw *hw,  	return ret;  } +#define IWL_MVM_MLD_UNBLOCK_ESR_NON_BSS_TIMEOUT (5 * HZ) + +static void iwl_mvm_mld_prep_add_interface(struct ieee80211_hw *hw, +					   enum nl80211_iftype type) +{ +	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); +	struct ieee80211_vif *bss_vif = iwl_mvm_get_bss_vif(mvm); +	struct iwl_mvm_vif *mvmvif; +	int ret; + +	IWL_DEBUG_MAC80211(mvm, "prep_add_interface: type=%u\n", +			   type); + +	if (IS_ERR_OR_NULL(bss_vif) || +	    !(type == NL80211_IFTYPE_AP || +	      type == NL80211_IFTYPE_P2P_GO || +	      type == NL80211_IFTYPE_P2P_CLIENT)) +		return; + +	mvmvif = iwl_mvm_vif_from_mac80211(bss_vif); +	ret = iwl_mvm_block_esr_sync(mvm, bss_vif, +				     IWL_MVM_ESR_BLOCKED_TMP_NON_BSS); +	if (ret) +		return; + +	wiphy_delayed_work_queue(mvmvif->mvm->hw->wiphy, +				 &mvmvif->unblock_esr_tmp_non_bss_wk, +				 IWL_MVM_MLD_UNBLOCK_ESR_NON_BSS_TIMEOUT); +} +  const struct ieee80211_ops iwl_mvm_mld_hw_ops = {  	.tx = iwl_mvm_mac_tx,  	.wake_tx_queue = iwl_mvm_mac_wake_tx_queue, @@ -1379,7 +1349,7 @@ const struct ieee80211_ops iwl_mvm_mld_hw_ops = {  	.allow_buffered_frames = iwl_mvm_mac_allow_buffered_frames,  	.release_buffered_frames = iwl_mvm_mac_release_buffered_frames,  	.set_rts_threshold = iwl_mvm_mac_set_rts_threshold, -	.sta_rc_update = iwl_mvm_sta_rc_update, +	.link_sta_rc_update = iwl_mvm_sta_rc_update,  	.conf_tx = iwl_mvm_mld_mac_conf_tx,  	.mgd_prepare_tx = iwl_mvm_mac_mgd_prepare_tx,  	.mgd_complete_tx = iwl_mvm_mac_mgd_complete_tx, @@ -1420,8 +1390,6 @@ const struct ieee80211_ops iwl_mvm_mld_hw_ops = {  	.sync_rx_queues = iwl_mvm_sync_rx_queues, -	CFG80211_TESTMODE_CMD(iwl_mvm_mac_testmode_cmd) -  #ifdef CONFIG_PM_SLEEP  	/* look at d3.c */  	.suspend = iwl_mvm_suspend, @@ -1450,4 +1418,5 @@ const struct ieee80211_ops iwl_mvm_mld_hw_ops = {  	.change_sta_links = iwl_mvm_mld_change_sta_links,  	.can_activate_links = iwl_mvm_mld_can_activate_links,  	.can_neg_ttlm = iwl_mvm_mld_can_neg_ttlm, +	.prep_add_interface = iwl_mvm_mld_prep_add_interface,  }; diff --git a/sys/contrib/dev/iwlwifi/mvm/mld-sta.c b/sys/contrib/dev/iwlwifi/mvm/mld-sta.c index d5a204e52076..e1010521c3ea 100644 --- a/sys/contrib/dev/iwlwifi/mvm/mld-sta.c +++ b/sys/contrib/dev/iwlwifi/mvm/mld-sta.c @@ -1,6 +1,6 @@  // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause  /* - * Copyright (C) 2022-2024 Intel Corporation + * Copyright (C) 2022-2025 Intel Corporation   */  #include "mvm.h"  #include "time-sync.h" @@ -46,11 +46,15 @@ u32 iwl_mvm_sta_fw_id_mask(struct iwl_mvm *mvm, struct ieee80211_sta *sta,  }  static int iwl_mvm_mld_send_sta_cmd(struct iwl_mvm *mvm, -				    struct iwl_mvm_sta_cfg_cmd *cmd) +				    struct iwl_sta_cfg_cmd *cmd)  { +	u32 cmd_id = WIDE_ID(MAC_CONF_GROUP, STA_CONFIG_CMD); +	int cmd_len = iwl_fw_lookup_cmd_ver(mvm->fw, cmd_id, 0) > 1 ? +		      sizeof(*cmd) : +		      sizeof(struct iwl_sta_cfg_cmd_v1);  	int ret = iwl_mvm_send_cmd_pdu(mvm,  				       WIDE_ID(MAC_CONF_GROUP, STA_CONFIG_CMD), -				       0, sizeof(*cmd), cmd); +				       0, cmd_len, cmd);  	if (ret)  		IWL_ERR(mvm, "STA_CONFIG_CMD send failed, ret=0x%x\n", ret);  	return ret; @@ -63,7 +67,7 @@ static int iwl_mvm_mld_add_int_sta_to_fw(struct iwl_mvm *mvm,  					 struct iwl_mvm_int_sta *sta,  					 const u8 *addr, int link_id)  { -	struct iwl_mvm_sta_cfg_cmd cmd; +	struct iwl_sta_cfg_cmd cmd;  	lockdep_assert_held(&mvm->mutex); @@ -94,7 +98,7 @@ static int iwl_mvm_mld_add_int_sta_to_fw(struct iwl_mvm *mvm,   */  static int iwl_mvm_mld_rm_sta_from_fw(struct iwl_mvm *mvm, u32 sta_id)  { -	struct iwl_mvm_remove_sta_cmd rm_sta_cmd = { +	struct iwl_remove_sta_cmd rm_sta_cmd = {  		.sta_id = cpu_to_le32(sta_id),  	};  	int ret; @@ -121,7 +125,7 @@ static int iwl_mvm_add_aux_sta_to_fw(struct iwl_mvm *mvm,  {  	int ret; -	struct iwl_mvm_aux_sta_cmd cmd = { +	struct iwl_aux_sta_cmd cmd = {  		.sta_id = cpu_to_le32(sta->sta_id),  		.lmac_id = cpu_to_le32(lmac_id),  	}; @@ -144,9 +148,9 @@ int iwl_mvm_mld_add_int_sta_with_queue(struct iwl_mvm *mvm,  {  	int ret, txq;  	unsigned int wdg_timeout = _wdg_timeout ? *_wdg_timeout : -		mvm->trans->trans_cfg->base_params->wd_timeout; +		mvm->trans->mac_cfg->base->wd_timeout; -	if (WARN_ON_ONCE(sta->sta_id == IWL_MVM_INVALID_STA)) +	if (WARN_ON_ONCE(sta->sta_id == IWL_INVALID_STA))  		return -ENOSPC;  	if (sta->type == STATION_TYPE_AUX) @@ -216,7 +220,7 @@ int iwl_mvm_mld_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,  	static const u8 _baddr[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};  	const u8 *baddr = _baddr;  	unsigned int wdg_timeout = -		iwl_mvm_get_wd_timeout(mvm, vif, false, false); +		iwl_mvm_get_wd_timeout(mvm, vif);  	u16 *queue;  	lockdep_assert_held(&mvm->mutex); @@ -254,7 +258,7 @@ int iwl_mvm_mld_add_mcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,  	struct iwl_mvm_int_sta *msta = &mvm_link->mcast_sta;  	static const u8 _maddr[] = {0x03, 0x00, 0x00, 0x00, 0x00, 0x00};  	const u8 *maddr = _maddr; -	unsigned int timeout = iwl_mvm_get_wd_timeout(mvm, vif, false, false); +	unsigned int timeout = iwl_mvm_get_wd_timeout(mvm, vif);  	lockdep_assert_held(&mvm->mutex); @@ -346,7 +350,7 @@ static int iwl_mvm_mld_rm_int_sta(struct iwl_mvm *mvm,  	lockdep_assert_held(&mvm->mutex); -	if (WARN_ON_ONCE(int_sta->sta_id == IWL_MVM_INVALID_STA)) +	if (WARN_ON_ONCE(int_sta->sta_id == IWL_INVALID_STA))  		return -EINVAL;  	if (flush) @@ -438,7 +442,7 @@ static int iwl_mvm_mld_cfg_sta(struct iwl_mvm *mvm, struct ieee80211_sta *sta,  	struct iwl_mvm_vif *mvm_vif = iwl_mvm_vif_from_mac80211(vif);  	struct iwl_mvm_vif_link_info *link_info =  					mvm_vif->link[link_conf->link_id]; -	struct iwl_mvm_sta_cfg_cmd cmd = { +	struct iwl_sta_cfg_cmd cmd = {  		.sta_id = cpu_to_le32(mvm_link_sta->sta_id),  		.station_type = cpu_to_le32(mvm_sta->sta_type),  	}; @@ -518,11 +522,12 @@ static int iwl_mvm_mld_cfg_sta(struct iwl_mvm *mvm, struct ieee80211_sta *sta,  void iwl_mvm_mld_free_sta_link(struct iwl_mvm *mvm,  			       struct iwl_mvm_sta *mvm_sta,  			       struct iwl_mvm_link_sta *mvm_sta_link, -			       unsigned int link_id, -			       bool is_in_fw) +			       unsigned int link_id)  { -	RCU_INIT_POINTER(mvm->fw_id_to_mac_id[mvm_sta_link->sta_id], -			 is_in_fw ? ERR_PTR(-EINVAL) : NULL); +	lockdep_assert_wiphy(mvm->hw->wiphy); +	lockdep_assert_held(&mvm->mutex); + +	RCU_INIT_POINTER(mvm->fw_id_to_mac_id[mvm_sta_link->sta_id], NULL);  	RCU_INIT_POINTER(mvm->fw_id_to_link_sta[mvm_sta_link->sta_id], NULL);  	RCU_INIT_POINTER(mvm_sta->link[link_id], NULL); @@ -543,7 +548,7 @@ static void iwl_mvm_mld_sta_rm_all_sta_links(struct iwl_mvm *mvm,  		if (!link)  			continue; -		iwl_mvm_mld_free_sta_link(mvm, mvm_sta, link, link_id, false); +		iwl_mvm_mld_free_sta_link(mvm, mvm_sta, link, link_id);  	}  } @@ -559,7 +564,10 @@ static int iwl_mvm_mld_alloc_sta_link(struct iwl_mvm *mvm,  	u32 sta_id = iwl_mvm_find_free_sta_id(mvm,  					  ieee80211_vif_type_p2p(vif)); -	if (sta_id == IWL_MVM_INVALID_STA) +	lockdep_assert_wiphy(mvm->hw->wiphy); +	lockdep_assert_held(&mvm->mutex); + +	if (sta_id == IWL_INVALID_STA)  		return -ENOSPC;  	if (rcu_access_pointer(sta->link[link_id]) == &sta->deflink) { @@ -612,10 +620,10 @@ static void iwl_mvm_mld_set_ap_sta_id(struct ieee80211_sta *sta,  				      struct iwl_mvm_link_sta *sta_link)  {  	if (!sta->tdls) { -		WARN_ON(vif_link->ap_sta_id != IWL_MVM_INVALID_STA); +		WARN_ON(vif_link->ap_sta_id != IWL_INVALID_STA);  		vif_link->ap_sta_id = sta_link->sta_id;  	} else { -		WARN_ON(vif_link->ap_sta_id == IWL_MVM_INVALID_STA); +		WARN_ON(vif_link->ap_sta_id == IWL_INVALID_STA);  	}  } @@ -631,6 +639,9 @@ static int iwl_mvm_alloc_sta_after_restart(struct iwl_mvm *mvm,  	int ret = -EINVAL;  	int sta_id; +	lockdep_assert_wiphy(mvm->hw->wiphy); +	lockdep_assert_held(&mvm->mutex); +  	/* First add an empty station since allocating a queue requires  	 * a valid station. Since we need a link_id to allocate a station,  	 * pick up the first valid one. @@ -686,7 +697,7 @@ int iwl_mvm_mld_add_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,  		spin_lock_init(&mvm_sta->lock); -		ret = iwl_mvm_sta_init(mvm, vif, sta, IWL_MVM_INVALID_STA, +		ret = iwl_mvm_sta_init(mvm, vif, sta, IWL_INVALID_STA,  				       STATION_TYPE_PEER);  	} else {  		ret = iwl_mvm_alloc_sta_after_restart(mvm, vif, sta); @@ -835,18 +846,11 @@ int iwl_mvm_mld_rm_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,  		struct iwl_mvm_link_sta *mvm_link_sta =  			rcu_dereference_protected(mvm_sta->link[link_id],  						  lockdep_is_held(&mvm->mutex)); -		bool stay_in_fw; +		iwl_mvm_sta_del(mvm, vif, sta, link_sta); -		stay_in_fw = iwl_mvm_sta_del(mvm, vif, sta, link_sta, &ret); -		if (ret) -			break; +		ret = iwl_mvm_mld_rm_sta_from_fw(mvm, mvm_link_sta->sta_id); -		if (!stay_in_fw) -			ret = iwl_mvm_mld_rm_sta_from_fw(mvm, -							 mvm_link_sta->sta_id); - -		iwl_mvm_mld_free_sta_link(mvm, mvm_sta, mvm_link_sta, -					  link_id, stay_in_fw); +		iwl_mvm_mld_free_sta_link(mvm, mvm_sta, mvm_link_sta, link_id);  	}  	kfree(mvm_sta->mpdu_counters);  	mvm_sta->mpdu_counters = NULL; @@ -858,9 +862,10 @@ int iwl_mvm_mld_rm_sta_id(struct iwl_mvm *mvm, u8 sta_id)  {  	int ret; +	lockdep_assert_wiphy(mvm->hw->wiphy);  	lockdep_assert_held(&mvm->mutex); -	if (WARN_ON(sta_id == IWL_MVM_INVALID_STA)) +	if (WARN_ON(sta_id == IWL_INVALID_STA))  		return 0;  	ret = iwl_mvm_mld_rm_sta_from_fw(mvm, sta_id); @@ -1064,6 +1069,7 @@ int iwl_mvm_mld_update_sta_links(struct iwl_mvm *mvm,  	unsigned int link_id;  	int ret; +	lockdep_assert_wiphy(mvm->hw->wiphy);  	lockdep_assert_held(&mvm->mutex);  	for_each_set_bit(link_id, &old_links_long, @@ -1109,10 +1115,9 @@ int iwl_mvm_mld_update_sta_links(struct iwl_mvm *mvm,  			goto err;  		if (vif->type == NL80211_IFTYPE_STATION) -			mvm_vif_link->ap_sta_id = IWL_MVM_INVALID_STA; +			mvm_vif_link->ap_sta_id = IWL_INVALID_STA; -		iwl_mvm_mld_free_sta_link(mvm, mvm_sta, mvm_sta_link, link_id, -					  false); +		iwl_mvm_mld_free_sta_link(mvm, mvm_sta, mvm_sta_link, link_id);  	}  	for_each_set_bit(link_id, &links_to_add, IEEE80211_MLD_MAX_NUM_LINKS) { @@ -1182,6 +1187,9 @@ int iwl_mvm_mld_update_sta_links(struct iwl_mvm *mvm,  		link_sta_added_to_fw |= BIT(link_id);  		iwl_mvm_rs_add_sta_link(mvm, mvm_sta_link); + +		iwl_mvm_rs_rate_init(mvm, vif, sta, link_conf, link_sta, +				     link_conf->chanreq.oper.chan->band);  	}  	if (sta_mask_added) { @@ -1213,8 +1221,7 @@ err:  			rcu_dereference_protected(mvm_sta->link[link_id],  						  lockdep_is_held(&mvm->mutex)); -		iwl_mvm_mld_free_sta_link(mvm, mvm_sta, mvm_sta_link, link_id, -					  false); +		iwl_mvm_mld_free_sta_link(mvm, mvm_sta, mvm_sta_link, link_id);  	}  	return ret; diff --git a/sys/contrib/dev/iwlwifi/mvm/mvm.h b/sys/contrib/dev/iwlwifi/mvm/mvm.h index 6278c8be3950..41125adf4fd1 100644 --- a/sys/contrib/dev/iwlwifi/mvm/mvm.h +++ b/sys/contrib/dev/iwlwifi/mvm/mvm.h @@ -1,6 +1,6 @@  /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */  /* - * Copyright (C) 2012-2014, 2018-2024 Intel Corporation + * Copyright (C) 2012-2014, 2018-2025 Intel Corporation   * Copyright (C) 2013-2015 Intel Mobile Communications GmbH   * Copyright (C) 2016-2017 Intel Deutschland GmbH   */ @@ -108,6 +108,7 @@ struct iwl_mvm_phy_ctxt {  	u32 center_freq1;  	bool rlc_disabled;  	u32 channel_load_by_us; +	u32 channel_load_not_by_us;  };  struct iwl_mvm_time_event_data { @@ -130,7 +131,7 @@ struct iwl_mvm_time_event_data {   /* Power management */  /** - * enum iwl_power_scheme + * enum iwl_power_scheme - iwl power schemes   * @IWL_POWER_SCHEME_CAM: Continuously Active Mode   * @IWL_POWER_SCHEME_BPS: Balanced Power Save (default)   * @IWL_POWER_SCHEME_LP: Low Power @@ -304,9 +305,12 @@ struct iwl_probe_resp_data {   * @active: indicates the link is active in FW (for sanity checking)   * @cab_queue: content-after-beacon (multicast) queue   * @listen_lmac: indicates this link is allocated to the listen LMAC + * @csa_block_tx: we got CSA with mode=1   * @mcast_sta: multicast station   * @phy_ctxt: phy context allocated to this link, if any   * @bf_data: beacon filtering data + * @average_beacon_energy: average beacon energy for beacons received during + *	client connections   */  struct iwl_mvm_vif_link_info {  	u8 bssid[ETH_ALEN]; @@ -329,6 +333,7 @@ struct iwl_mvm_vif_link_info {  	bool he_ru_2mhz_block;  	bool active;  	bool listen_lmac; +	bool csa_block_tx;  	u16 cab_queue;  	/* Assigned while mac80211 has the link in a channel context, @@ -344,6 +349,7 @@ struct iwl_mvm_vif_link_info {  	u16 mgmt_queue;  	struct iwl_mvm_link_bf_data bf_data; +	u32 average_beacon_energy;  };  /** @@ -364,6 +370,9 @@ struct iwl_mvm_vif_link_info {   * @IWL_MVM_ESR_BLOCKED_NON_BSS: An active non-BSS interface's link is   *	preventing EMLSR   * @IWL_MVM_ESR_BLOCKED_ROC: remain-on-channel is preventing EMLSR + * @IWL_MVM_ESR_BLOCKED_TMP_NON_BSS: An expected active non-BSS interface's link + *      is preventing EMLSR. This is a temporary blocking that is set when there + *      is an indication that a non-BSS interface is to be added.   * @IWL_MVM_ESR_EXIT_MISSED_BEACON: exited EMLSR due to missed beacons   * @IWL_MVM_ESR_EXIT_LOW_RSSI: link is deactivated/not allowed for EMLSR   *	due to low RSSI. @@ -381,6 +390,7 @@ enum iwl_mvm_esr_state {  	IWL_MVM_ESR_BLOCKED_FW		= 0x8,  	IWL_MVM_ESR_BLOCKED_NON_BSS	= 0x10,  	IWL_MVM_ESR_BLOCKED_ROC		= 0x20, +	IWL_MVM_ESR_BLOCKED_TMP_NON_BSS	= 0x40,  	IWL_MVM_ESR_EXIT_MISSED_BEACON	= 0x10000,  	IWL_MVM_ESR_EXIT_LOW_RSSI	= 0x20000,  	IWL_MVM_ESR_EXIT_COEX		= 0x40000, @@ -453,6 +463,8 @@ struct iwl_mvm_esr_exit {   * @prevent_esr_done_wk: work that should be done when esr prevention ends.   * @mlo_int_scan_wk: work for the internal MLO scan.   * @unblock_esr_tpt_wk: work for unblocking EMLSR when tpt is high enough. + * @unblock_esr_tmp_non_bss_wk: work for removing the + *      IWL_MVM_ESR_BLOCKED_TMP_NON_BSS blocking for EMLSR.   * @roc_activity: currently running ROC activity for this vif (or   *	ROC_NUM_ACTIVITIES if no activity is running).   * @session_prot_connection_loss: the connection was lost due to session @@ -513,7 +525,7 @@ struct iwl_mvm_vif {  	bool bf_enabled;  	bool ba_enabled; -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	/* WoWLAN GTK rekey data */  	struct {  		u8 kck[NL80211_KCK_EXT_LEN]; @@ -589,6 +601,7 @@ struct iwl_mvm_vif {  	struct wiphy_delayed_work prevent_esr_done_wk;  	struct wiphy_delayed_work mlo_int_scan_wk;  	struct wiphy_work unblock_esr_tpt_wk; +	struct wiphy_delayed_work unblock_esr_tmp_non_bss_wk;  	struct iwl_mvm_vif_link_info deflink;  	struct iwl_mvm_vif_link_info *link[IEEE80211_MLD_MAX_NUM_LINKS]; @@ -657,6 +670,8 @@ enum iwl_mvm_sched_scan_pass_all_states {   * @min_backoff: The minimal tx backoff due to power restrictions   * @params: Parameters to configure the thermal throttling algorithm.   * @throttle: Is thermal throttling is active? + * @power_budget_mw: maximum cTDP power budget as defined for this system and + *	device   */  struct iwl_mvm_tt_mgmt {  	struct delayed_work ct_kill_exit; @@ -665,6 +680,8 @@ struct iwl_mvm_tt_mgmt {  	u32 min_backoff;  	struct iwl_tt_params params;  	bool throttle; + +	u32 power_budget_mw;  };  #ifdef CONFIG_THERMAL @@ -774,8 +791,6 @@ struct iwl_mvm_tcm {   * @head_sn: reorder window head sn   * @num_stored: number of mpdus stored in the buffer   * @queue: queue of this reorder buffer - * @last_amsdu: track last ASMDU SN for duplication detection - * @last_sub_index: track ASMDU sub frame index for duplication detection   * @valid: reordering is valid for this queue   * @lock: protect reorder buffer internal state   */ @@ -783,8 +798,6 @@ struct iwl_mvm_reorder_buffer {  	u16 head_sn;  	u16 num_stored;  	int queue; -	u16 last_amsdu; -	u8 last_sub_index;  	bool valid;  	spinlock_t lock;  } ____cacheline_aligned_in_smp; @@ -996,7 +1009,7 @@ struct iwl_mvm {  	struct iwl_trans *trans;  	const struct iwl_fw *fw; -	const struct iwl_cfg *cfg; +	const struct iwl_rf_cfg *cfg;  	struct iwl_phy_db *phy_db;  	struct ieee80211_hw *hw; @@ -1030,6 +1043,8 @@ struct iwl_mvm {  	u8 cca_40mhz_workaround; +	u8 fw_rates_ver; +  	u32 ampdu_ref;  	bool ampdu_toggle; @@ -1079,8 +1094,9 @@ struct iwl_mvm {  	/* data related to data path */  	struct iwl_rx_phy_info last_phy_info; -	struct ieee80211_sta __rcu *fw_id_to_mac_id[IWL_MVM_STATION_COUNT_MAX]; -	struct ieee80211_link_sta __rcu *fw_id_to_link_sta[IWL_MVM_STATION_COUNT_MAX]; +	struct ieee80211_sta __rcu *fw_id_to_mac_id[IWL_STATION_COUNT_MAX]; +	/* note: fw_id_to_link_sta must be protected by wiphy and mvm mutexes */ +	struct ieee80211_link_sta __rcu *fw_id_to_link_sta[IWL_STATION_COUNT_MAX];  	u8 rx_ba_sessions;  	/* configured by mac80211 */ @@ -1169,10 +1185,6 @@ struct iwl_mvm {  	struct ieee80211_vif __rcu *vif_id_to_mac[NUM_MAC_INDEX_DRIVER]; -	struct ieee80211_bss_conf __rcu *link_id_to_link_conf[IWL_MVM_FW_MAX_LINK_ID + 1]; - -	/* -1 for always, 0 for never, >0 for that many times */ -	s8 fw_restart;  	u8 *error_recovery_buf;  #ifdef CONFIG_IWLWIFI_LEDS @@ -1181,7 +1193,7 @@ struct iwl_mvm {  	struct ieee80211_vif *p2p_device_vif; -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	struct wiphy_wowlan_support wowlan;  	int gtk_ivlen, gtk_icvlen, ptk_ivlen, ptk_icvlen; @@ -1205,8 +1217,11 @@ struct iwl_mvm {  	wait_queue_head_t rx_sync_waitq; -	/* BT-Coex */ -	struct iwl_bt_coex_profile_notif last_bt_notif; +	/* BT-Coex - only one of those will be used */ +	union { +		struct iwl_bt_coex_prof_old_notif last_bt_notif; +		struct iwl_bt_coex_profile_notif last_bt_wifi_loss; +	};  	struct iwl_bt_coex_ci_cmd last_bt_ci_cmd;  	u8 bt_tx_prio; @@ -1241,11 +1256,6 @@ struct iwl_mvm {  	struct iwl_time_quota_cmd last_quota_cmd; -#ifdef CONFIG_NL80211_TESTMODE -	u32 noa_duration; -	struct ieee80211_vif *noa_vif; -#endif -  	/* Tx queues */  	u16 aux_queue;  	u16 snif_queue; @@ -1305,7 +1315,7 @@ struct iwl_mvm {  		struct cfg80211_pmsr_request *req;  		struct wireless_dev *req_wdev;  		struct list_head loc_list; -		int responses[IWL_MVM_TOF_MAX_APS]; +		int responses[IWL_TOF_MAX_APS];  		struct {  			struct list_head resp;  		} smooth; @@ -1320,7 +1330,6 @@ struct iwl_mvm {  		u8 range_resp;  	} cmd_ver; -	struct ieee80211_vif *nan_vif;  	struct iwl_mvm_baid_data __rcu *baid_map[IWL_MAX_BAID];  	/* @@ -1343,10 +1352,6 @@ struct iwl_mvm {  	__le16 cur_aid;  	u8 cur_bssid[ETH_ALEN]; -#ifdef CONFIG_ACPI -	struct iwl_phy_specific_cfg phy_filters; -#endif -  	/* report rx timestamp in ptp clock time */  	bool rx_ts_ptp; @@ -1394,8 +1399,6 @@ DEFINE_GUARD(mvm, struct iwl_mvm *, mutex_lock(&_T->mutex), mutex_unlock(&_T->mu   * @IWL_MVM_STATUS_IN_D3: in D3 (or at least about to go into it)   * @IWL_MVM_STATUS_SUPPRESS_ERROR_LOG_ONCE: suppress one error log   *	if this is set, when intentionally triggered - * @IWL_MVM_STATUS_STARTING: starting mac, - *	used to disable restart flow while in STARTING state   */  enum iwl_mvm_status {  	IWL_MVM_STATUS_HW_RFKILL, @@ -1407,7 +1410,6 @@ enum iwl_mvm_status {  	IWL_MVM_STATUS_FIRMWARE_RUNNING,  	IWL_MVM_STATUS_IN_D3,  	IWL_MVM_STATUS_SUPPRESS_ERROR_LOG_ONCE, -	IWL_MVM_STATUS_STARTING,  };  struct iwl_mvm_csme_conn_info { @@ -1488,20 +1490,6 @@ iwl_mvm_rcu_dereference_vif_id(struct iwl_mvm *mvm, u8 vif_id, bool rcu)  					 lockdep_is_held(&mvm->mutex));  } -static inline struct ieee80211_bss_conf * -iwl_mvm_rcu_fw_link_id_to_link_conf(struct iwl_mvm *mvm, u8 link_id, bool rcu) -{ -	if (IWL_FW_CHECK(mvm, link_id >= ARRAY_SIZE(mvm->link_id_to_link_conf), -			 "erroneous FW link ID: %d\n", link_id)) -		return NULL; - -	if (rcu) -		return rcu_dereference(mvm->link_id_to_link_conf[link_id]); - -	return rcu_dereference_protected(mvm->link_id_to_link_conf[link_id], -					 lockdep_is_held(&mvm->mutex)); -} -  static inline bool iwl_mvm_is_adaptive_dwell_supported(struct iwl_mvm *mvm)  {  	return fw_has_api(&mvm->fw->ucode_capa, @@ -1559,7 +1547,7 @@ static inline bool iwl_mvm_is_lar_supported(struct iwl_mvm *mvm)  	 * Enable LAR only if it is supported by the FW (TLV) &&  	 * enabled in the NVM  	 */ -	if (mvm->cfg->nvm_type == IWL_NVM_EXT) +	if (mvm->trans->cfg->nvm_type == IWL_NVM_EXT)  		return nvm_lar && tlv_lar;  	else  		return tlv_lar; @@ -1583,8 +1571,7 @@ static inline bool iwl_mvm_bt_is_rrc_supported(struct iwl_mvm *mvm)  static inline bool iwl_mvm_is_csum_supported(struct iwl_mvm *mvm)  {  	return fw_has_capa(&mvm->fw->ucode_capa, -			   IWL_UCODE_TLV_CAPA_CSUM_SUPPORT) && -		!IWL_MVM_HW_CSUM_DISABLE; +			   IWL_UCODE_TLV_CAPA_CSUM_SUPPORT);  }  static inline bool iwl_mvm_is_mplut_supported(struct iwl_mvm *mvm) @@ -1624,13 +1611,13 @@ static inline bool iwl_mvm_has_new_station_api(const struct iwl_fw *fw)  static inline bool iwl_mvm_has_new_tx_api(struct iwl_mvm *mvm)  {  	/* TODO - replace with TLV once defined */ -	return mvm->trans->trans_cfg->gen2; +	return mvm->trans->mac_cfg->gen2;  }  static inline bool iwl_mvm_has_unified_ucode(struct iwl_mvm *mvm)  {  	/* TODO - better define this */ -	return mvm->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_22000; +	return mvm->trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_22000;  }  static inline bool iwl_mvm_is_cdb_supported(struct iwl_mvm *mvm) @@ -1655,7 +1642,7 @@ static inline bool iwl_mvm_cdb_scan_api(struct iwl_mvm *mvm)  	 * but then there's a little bit of code in scan that won't make  	 * any sense...  	 */ -	return mvm->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_22000; +	return mvm->trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_22000;  }  static inline bool iwl_mvm_is_scan_ext_chan_supported(struct iwl_mvm *mvm) @@ -1705,9 +1692,9 @@ static inline struct agg_tx_status *  iwl_mvm_get_agg_status(struct iwl_mvm *mvm, void *tx_resp)  {  	if (iwl_mvm_has_new_tx_api(mvm)) -		return &((struct iwl_mvm_tx_resp *)tx_resp)->status; +		return &((struct iwl_tx_resp *)tx_resp)->status;  	else -		return ((struct iwl_mvm_tx_resp_v3 *)tx_resp)->status; +		return ((struct iwl_tx_resp_v3 *)tx_resp)->status;  }  static inline bool iwl_mvm_is_tt_in_fw(struct iwl_mvm *mvm) @@ -1730,12 +1717,19 @@ static inline bool iwl_mvm_is_ctdp_supported(struct iwl_mvm *mvm)  static inline bool iwl_mvm_is_esr_supported(struct iwl_trans *trans)  { -	if ((CSR_HW_RFID_TYPE(trans->hw_rf_id) == IWL_CFG_RF_TYPE_FM) && -	    !CSR_HW_RFID_IS_CDB(trans->hw_rf_id)) -		/* Step A doesn't support eSR */ -		return CSR_HW_RFID_STEP(trans->hw_rf_id); +	if (CSR_HW_RFID_IS_CDB(trans->info.hw_rf_id)) +		return false; -	return false; +	switch (CSR_HW_RFID_TYPE(trans->info.hw_rf_id)) { +	case IWL_CFG_RF_TYPE_FM: +		/* Step A doesn't support eSR */ +		return CSR_HW_RFID_STEP(trans->info.hw_rf_id); +	case IWL_CFG_RF_TYPE_WH: +	case IWL_CFG_RF_TYPE_PE: +		return true; +	default: +		return false; +	}  }  static inline int iwl_mvm_max_active_links(struct iwl_mvm *mvm, @@ -1748,9 +1742,9 @@ static inline int iwl_mvm_max_active_links(struct iwl_mvm *mvm,  	/* Check if HW supports eSR or STR */  	if (iwl_mvm_is_esr_supported(trans) || -	    (CSR_HW_RFID_TYPE(trans->hw_rf_id) == IWL_CFG_RF_TYPE_FM && -	     CSR_HW_RFID_IS_CDB(trans->hw_rf_id))) -		return IWL_MVM_FW_MAX_ACTIVE_LINKS_NUM; +	    (CSR_HW_RFID_TYPE(trans->info.hw_rf_id) == IWL_CFG_RF_TYPE_FM && +	     CSR_HW_RFID_IS_CDB(trans->info.hw_rf_id))) +		return IWL_FW_MAX_ACTIVE_LINKS_NUM;  	return 1;  } @@ -1762,13 +1756,20 @@ extern const u8 iwl_mvm_ac_to_bz_tx_fifo[];  static inline u8 iwl_mvm_mac_ac_to_tx_fifo(struct iwl_mvm *mvm,  					   enum ieee80211_ac_numbers ac)  { -	if (mvm->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_BZ) +	if (mvm->trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_BZ)  		return iwl_mvm_ac_to_bz_tx_fifo[ac];  	if (iwl_mvm_has_new_tx_api(mvm))  		return iwl_mvm_ac_to_gen2_tx_fifo[ac];  	return iwl_mvm_ac_to_tx_fifo[ac];  } +static inline bool iwl_mvm_has_rlc_offload(struct iwl_mvm *mvm) +{ +	return iwl_fw_lookup_cmd_ver(mvm->fw, +				     WIDE_ID(DATA_PATH_GROUP, RLC_CONFIG_CMD), +				     0) >= 3; +} +  struct iwl_rate_info {  	u8 plcp;	/* uCode API:  IWL_RATE_6M_PLCP, etc. */  	u8 plcp_siso;	/* uCode API:  IWL_RATE_SISO_6M_PLCP, etc. */ @@ -1794,9 +1795,6 @@ int iwl_mvm_legacy_rate_to_mac80211_idx(u32 rate_n_flags,  void iwl_mvm_hwrate_to_tx_rate(u32 rate_n_flags,  			       enum nl80211_band band,  			       struct ieee80211_tx_rate *r); -void iwl_mvm_hwrate_to_tx_rate_v1(u32 rate_n_flags, -				  enum nl80211_band band, -				  struct ieee80211_tx_rate *r);  u8 iwl_mvm_mac80211_idx_to_hwrate(const struct iwl_fw *fw, int rate_idx);  u8 iwl_mvm_mac80211_ac_to_ucode_ac(enum ieee80211_ac_numbers ac);  bool iwl_mvm_is_nic_ack_enabled(struct iwl_mvm *mvm, struct ieee80211_vif *vif); @@ -1811,7 +1809,6 @@ u8 iwl_mvm_next_antenna(struct iwl_mvm *mvm, u8 valid, u8 last_idx);  void iwl_mvm_get_sync_time(struct iwl_mvm *mvm, int clock_type, u32 *gp2,  			   u64 *boottime, ktime_t *realtime);  u32 iwl_mvm_get_systime(struct iwl_mvm *mvm); -u32 iwl_mvm_find_ie_offset(u8 *beacon, u8 eid, u32 frame_size);  /* Tx / Host Commands */  int __must_check iwl_mvm_send_cmd(struct iwl_mvm *mvm, @@ -1828,11 +1825,12 @@ int iwl_mvm_tx_skb_sta(struct iwl_mvm *mvm, struct sk_buff *skb,  		       struct ieee80211_sta *sta);  int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb);  void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb, -			struct iwl_tx_cmd *tx_cmd, +			struct iwl_tx_cmd_v6_params *tx_cmd_params,  			struct ieee80211_tx_info *info, u8 sta_id); -void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm, struct iwl_tx_cmd *tx_cmd, -			    struct ieee80211_tx_info *info, -			    struct ieee80211_sta *sta, __le16 fc); +void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm, +			     struct iwl_tx_cmd_v6_params *tx_cmd_params, +			     struct ieee80211_tx_info *info, +			     struct ieee80211_sta *sta, __le16 fc);  void iwl_mvm_mac_itxq_xmit(struct ieee80211_hw *hw, struct ieee80211_txq *txq);  unsigned int iwl_mvm_max_amsdu_size(struct iwl_mvm *mvm,  				    struct ieee80211_sta *sta, @@ -1861,12 +1859,12 @@ int iwl_mvm_set_sta_pkt_ext(struct iwl_mvm *mvm,  void iwl_mvm_async_handlers_purge(struct iwl_mvm *mvm);  static inline void iwl_mvm_set_tx_cmd_ccmp(struct ieee80211_tx_info *info, -					   struct iwl_tx_cmd *tx_cmd) +					   struct iwl_tx_cmd_v6_params *tx_cmd_params)  {  	struct ieee80211_key_conf *keyconf = info->control.hw_key; -	tx_cmd->sec_ctl = TX_CMD_SEC_CCM; -	memcpy(tx_cmd->key, keyconf->key, keyconf->keylen); +	tx_cmd_params->sec_ctl = TX_CMD_SEC_CCM; +	memcpy(tx_cmd_params->key, keyconf->key, keyconf->keylen);  }  static inline void iwl_mvm_wait_for_async_handlers(struct iwl_mvm *mvm) @@ -2008,7 +2006,7 @@ int iwl_mvm_phy_send_rlc(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt,  void iwl_mvm_prepare_mac_removal(struct iwl_mvm *mvm,  				 struct ieee80211_vif *vif);  void iwl_mvm_set_fw_basic_rates(struct iwl_mvm *mvm, struct ieee80211_vif *vif, -				struct ieee80211_bss_conf *link_conf, +				struct iwl_mvm_vif_link_info *link_info,  				__le32 *cck_rates, __le32 *ofdm_rates);  void iwl_mvm_set_fw_protection_flags(struct iwl_mvm *mvm,  				     struct ieee80211_vif *vif, @@ -2067,6 +2065,8 @@ void iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm,  			     struct iwl_rx_cmd_buffer *rxb);  void iwl_mvm_rx_missed_beacons_notif(struct iwl_mvm *mvm,  				     struct iwl_rx_cmd_buffer *rxb); +void iwl_mvm_rx_missed_beacons_notif_legacy(struct iwl_mvm *mvm, +					    struct iwl_rx_cmd_buffer *rxb);  void iwl_mvm_rx_stored_beacon_notif(struct iwl_mvm *mvm,  				    struct iwl_rx_cmd_buffer *rxb);  void iwl_mvm_mu_mimo_grp_notif(struct iwl_mvm *mvm, @@ -2078,27 +2078,27 @@ void iwl_mvm_mac_ctxt_recalc_tsf_id(struct iwl_mvm *mvm,  				    struct ieee80211_vif *vif);  void iwl_mvm_probe_resp_data_notif(struct iwl_mvm *mvm,  				   struct iwl_rx_cmd_buffer *rxb); -void iwl_mvm_rx_missed_vap_notif(struct iwl_mvm *mvm, -				 struct iwl_rx_cmd_buffer *rxb);  void iwl_mvm_channel_switch_start_notif(struct iwl_mvm *mvm,  					struct iwl_rx_cmd_buffer *rxb);  void iwl_mvm_channel_switch_error_notif(struct iwl_mvm *mvm,  					struct iwl_rx_cmd_buffer *rxb); +void iwl_mvm_rx_beacon_filter_notif(struct iwl_mvm *mvm, +				    struct iwl_rx_cmd_buffer *rxb); +  /* Bindings */  int iwl_mvm_binding_add_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif);  int iwl_mvm_binding_remove_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif);  u32 iwl_mvm_get_lmac_id(struct iwl_mvm *mvm, enum nl80211_band band);  /* Links */ -int iwl_mvm_set_link_mapping(struct iwl_mvm *mvm, struct ieee80211_vif *vif, -			     struct ieee80211_bss_conf *link_conf); +void iwl_mvm_init_link(struct iwl_mvm_vif_link_info *link); +void iwl_mvm_set_link_fw_id(struct iwl_mvm *mvm, struct ieee80211_vif *vif, +			    struct ieee80211_bss_conf *link_conf);  int iwl_mvm_add_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif,  		     struct ieee80211_bss_conf *link_conf);  int iwl_mvm_link_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif,  			 struct ieee80211_bss_conf *link_conf,  			 u32 changes, bool active); -int iwl_mvm_unset_link_mapping(struct iwl_mvm *mvm, struct ieee80211_vif *vif, -			       struct ieee80211_bss_conf *link_conf);  int iwl_mvm_remove_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif,  			struct ieee80211_bss_conf *link_conf);  int iwl_mvm_disable_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif, @@ -2122,6 +2122,9 @@ bool iwl_mvm_mld_valid_link_pair(struct ieee80211_vif *vif,  				 const struct iwl_mvm_link_sel_data *b);  s8 iwl_mvm_average_dbm_values(const struct iwl_umac_scan_channel_survey_notif *notif); + +extern const struct iwl_hcmd_arr iwl_mvm_groups[]; +extern const unsigned int iwl_mvm_groups_size;  #endif  /* AP and IBSS */ @@ -2296,7 +2299,7 @@ void iwl_mvm_ipv6_addr_change(struct ieee80211_hw *hw,  void iwl_mvm_set_default_unicast_key(struct ieee80211_hw *hw,  				     struct ieee80211_vif *vif, int idx);  extern const struct file_operations iwl_dbgfs_d3_test_ops; -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  void iwl_mvm_set_last_nonqos_seq(struct iwl_mvm *mvm,  				 struct ieee80211_vif *vif);  void iwl_mvm_fast_suspend(struct iwl_mvm *mvm); @@ -2317,7 +2320,7 @@ static inline int iwl_mvm_fast_resume(struct iwl_mvm *mvm)  }  #endif  void iwl_mvm_set_wowlan_qos_seq(struct iwl_mvm_sta *mvm_ap_sta, -				struct iwl_wowlan_config_cmd *cmd); +				struct iwl_wowlan_config_cmd_v6 *cmd);  int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm,  			       struct ieee80211_vif *vif,  			       bool disable_offloading, @@ -2327,6 +2330,8 @@ int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm,  /* BT Coex */  int iwl_mvm_send_bt_init_conf(struct iwl_mvm *mvm); +void iwl_mvm_rx_bt_coex_old_notif(struct iwl_mvm *mvm, +				  struct iwl_rx_cmd_buffer *rxb);  void iwl_mvm_rx_bt_coex_notif(struct iwl_mvm *mvm,  			      struct iwl_rx_cmd_buffer *rxb);  void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif, @@ -2441,7 +2446,7 @@ void iwl_mvm_vif_set_low_latency(struct iwl_mvm_vif *mvmvif, bool set,   */  static inline u32 iwl_mvm_flushable_queues(struct iwl_mvm *mvm)  { -	return ((BIT(mvm->trans->trans_cfg->base_params->num_of_queues) - 1) & +	return ((BIT(mvm->trans->mac_cfg->base->num_of_queues) - 1) &  		~BIT(IWL_MVM_DQA_CMD_QUEUE));  } @@ -2500,14 +2505,6 @@ void iwl_mvm_ftm_restart_responder(struct iwl_mvm *mvm,  				   struct ieee80211_bss_conf *bss_conf);  void iwl_mvm_ftm_responder_stats(struct iwl_mvm *mvm,  				 struct iwl_rx_cmd_buffer *rxb); -#if defined(__linux__) -int iwl_mvm_ftm_resp_remove_pasn_sta(struct iwl_mvm *mvm, -				     struct ieee80211_vif *vif, u8 *addr); -int iwl_mvm_ftm_respoder_add_pasn_sta(struct iwl_mvm *mvm, -				      struct ieee80211_vif *vif, -				      u8 *addr, u32 cipher, u8 *tk, u32 tk_len, -				      u8 *hltk, u32 hltk_len); -#endif  void iwl_mvm_ftm_responder_clear(struct iwl_mvm *mvm,  				 struct ieee80211_vif *vif); @@ -2522,10 +2519,6 @@ int iwl_mvm_ftm_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif,  void iwl_mvm_ftm_abort(struct iwl_mvm *mvm, struct cfg80211_pmsr_request *req);  void iwl_mvm_ftm_initiator_smooth_config(struct iwl_mvm *mvm);  void iwl_mvm_ftm_initiator_smooth_stop(struct iwl_mvm *mvm); -int iwl_mvm_ftm_add_pasn_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif, -			     u8 *addr, u32 cipher, u8 *tk, u32 tk_len, -			     u8 *hltk, u32 hltk_len); -void iwl_mvm_ftm_remove_pasn_sta(struct iwl_mvm *mvm, u8 *addr);  /* TDLS */ @@ -2575,10 +2568,8 @@ void iwl_mvm_tcm_add_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif);  void iwl_mvm_tcm_rm_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif);  u8 iwl_mvm_tcm_load_percentage(u32 airtime, u32 elapsed); -void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error);  unsigned int iwl_mvm_get_wd_timeout(struct iwl_mvm *mvm, -				    struct ieee80211_vif *vif, -				    bool tdls, bool cmd_q); +				    struct ieee80211_vif *vif);  void iwl_mvm_connection_loss(struct iwl_mvm *mvm, struct ieee80211_vif *vif,  			     const char *errmsg);  void iwl_mvm_event_frame_timeout_callback(struct iwl_mvm *mvm, @@ -2864,13 +2855,16 @@ void iwl_mvm_mac_wake_tx_queue(struct ieee80211_hw *hw,  int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw,  			     struct ieee80211_vif *vif,  			     struct ieee80211_ampdu_params *params); -int iwl_mvm_op_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant); -int iwl_mvm_op_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant); +int iwl_mvm_op_get_antenna(struct ieee80211_hw *hw, int radio_idx, u32 *tx_ant, +			   u32 *rx_ant); +int iwl_mvm_op_set_antenna(struct ieee80211_hw *hw, int radio_idx, u32 tx_ant, +			   u32 rx_ant);  int iwl_mvm_mac_start(struct ieee80211_hw *hw);  void iwl_mvm_mac_reconfig_complete(struct ieee80211_hw *hw,  				   enum ieee80211_reconfig_type reconfig_type);  void iwl_mvm_mac_stop(struct ieee80211_hw *hw, bool suspend); -static inline int iwl_mvm_mac_config(struct ieee80211_hw *hw, u32 changed) +static inline int iwl_mvm_mac_config(struct ieee80211_hw *hw, int radio_idx, +				     u32 changed)  {  	return 0;  } @@ -2903,9 +2897,10 @@ iwl_mvm_mac_release_buffered_frames(struct ieee80211_hw *hw,  				    int num_frames,  				    enum ieee80211_frame_release_type reason,  				    bool more_data); -int iwl_mvm_mac_set_rts_threshold(struct ieee80211_hw *hw, u32 value); +int iwl_mvm_mac_set_rts_threshold(struct ieee80211_hw *hw, int radio_idx, +				  u32 value);  void iwl_mvm_sta_rc_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif, -			   struct ieee80211_sta *sta, u32 changed); +			   struct ieee80211_link_sta *link_sta, u32 changed);  void iwl_mvm_mac_mgd_prepare_tx(struct ieee80211_hw *hw,  				struct ieee80211_vif *vif,  				struct ieee80211_prep_tx_info *info); @@ -2973,25 +2968,19 @@ void iwl_mvm_abort_pmsr(struct ieee80211_hw *hw, struct ieee80211_vif *vif,  bool iwl_mvm_have_links_same_channel(struct iwl_mvm_vif *vif1,  				     struct iwl_mvm_vif *vif2);  bool iwl_mvm_vif_is_active(struct iwl_mvm_vif *mvmvif); -int iwl_mvm_set_tx_power(struct iwl_mvm *mvm, struct ieee80211_vif *vif, +int iwl_mvm_set_tx_power(struct iwl_mvm *mvm, +			 struct ieee80211_bss_conf *bss_conf,  			 s16 tx_power);  int iwl_mvm_set_hw_timestamp(struct ieee80211_hw *hw,  			     struct ieee80211_vif *vif,  			     struct cfg80211_set_hw_timestamp *hwts);  int iwl_mvm_update_mu_groups(struct iwl_mvm *mvm, struct ieee80211_vif *vif);  bool iwl_mvm_enable_fils(struct iwl_mvm *mvm, +			 struct ieee80211_vif *vif,  			 struct ieee80211_chanctx_conf *ctx); -bool iwl_mvm_is_ftm_responder_chanctx(struct iwl_mvm *mvm, -				      struct ieee80211_chanctx_conf *ctx); - -static inline struct cfg80211_chan_def * -iwl_mvm_chanctx_def(struct iwl_mvm *mvm, struct ieee80211_chanctx_conf *ctx) -{ -	bool use_def = iwl_mvm_is_ftm_responder_chanctx(mvm, ctx) || -		iwl_mvm_enable_fils(mvm, ctx); -	return use_def ? &ctx->def : &ctx->min_def; -} +struct cfg80211_chan_def * +iwl_mvm_chanctx_def(struct iwl_mvm *mvm, struct ieee80211_chanctx_conf *ctx);  void iwl_mvm_roc_duration_and_delay(struct ieee80211_vif *vif,  				    u32 duration_ms, @@ -3033,4 +3022,12 @@ iwl_mvm_send_ap_tx_power_constraint_cmd(struct iwl_mvm *mvm,  					struct ieee80211_vif *vif,  					struct ieee80211_bss_conf *bss_conf,  					bool is_ap); + +void iwl_mvm_smps_workaround(struct iwl_mvm *mvm, struct ieee80211_vif *vif, +			     bool update); + +/* rate_n_flags conversion */ +u32 iwl_mvm_v3_rate_from_fw(__le32 rate, u8 rate_ver); +__le32 iwl_mvm_v3_rate_to_fw(u32 rate, u8 rate_ver); +  #endif /* __IWL_MVM_H__ */ diff --git a/sys/contrib/dev/iwlwifi/mvm/nvm.c b/sys/contrib/dev/iwlwifi/mvm/nvm.c index 9083089f2e68..f01d5836fce6 100644 --- a/sys/contrib/dev/iwlwifi/mvm/nvm.c +++ b/sys/contrib/dev/iwlwifi/mvm/nvm.c @@ -1,6 +1,6 @@  // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause  /* - * Copyright (C) 2012-2014, 2018-2019, 2021-2024 Intel Corporation + * Copyright (C) 2012-2014, 2018-2019, 2021-2025 Intel Corporation   * Copyright (C) 2013-2015 Intel Mobile Communications GmbH   * Copyright (C) 2016-2017 Intel Deutschland GmbH   */ @@ -122,7 +122,7 @@ static int iwl_nvm_read_chunk(struct iwl_mvm *mvm, u16 section,  		} else {  			IWL_DEBUG_EEPROM(mvm->trans->dev,  					 "NVM access command failed with status %d (device: %s)\n", -					 ret, mvm->trans->name); +					 ret, mvm->trans->info.name);  			ret = -ENODATA;  		}  		goto exit; @@ -193,7 +193,7 @@ static int iwl_nvm_read_section(struct iwl_mvm *mvm, u16 section,  	while (ret == length) {  		/* Check no memory assumptions fail and cause an overflow */  		if ((size_read + offset + length) > -		    mvm->trans->trans_cfg->base_params->eeprom_size) { +		    mvm->trans->mac_cfg->base->eeprom_size) {  			IWL_ERR(mvm, "EEPROM size is too small for NVM\n");  			return -ENOBUFS;  		} @@ -208,7 +208,7 @@ static int iwl_nvm_read_section(struct iwl_mvm *mvm, u16 section,  		offset += ret;  	} -	iwl_nvm_fixups(mvm->trans->hw_id, section, data, offset); +	iwl_nvm_fixups(mvm->trans->info.hw_id, section, data, offset);  	IWL_DEBUG_EEPROM(mvm->trans->dev,  			 "NVM section %d read completed\n", section); @@ -228,7 +228,7 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm)  	/* Checking for required sections */  	if (mvm->trans->cfg->nvm_type == IWL_NVM) {  		if (!mvm->nvm_sections[NVM_SECTION_TYPE_SW].data || -		    !mvm->nvm_sections[mvm->cfg->nvm_hw_section_num].data) { +		    !mvm->nvm_sections[mvm->trans->mac_cfg->base->nvm_hw_section_num].data) {  			IWL_ERR(mvm, "Can't parse empty OTP/NVM sections\n");  			return NULL;  		} @@ -246,7 +246,7 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm)  			return NULL;  		}  		/* MAC_OVERRIDE or at least HW section must exist */ -		if (!mvm->nvm_sections[mvm->cfg->nvm_hw_section_num].data && +		if (!mvm->nvm_sections[mvm->trans->mac_cfg->base->nvm_hw_section_num].data &&  		    !mvm->nvm_sections[NVM_SECTION_TYPE_MAC_OVERRIDE].data) {  			IWL_ERR(mvm,  				"Can't parse mac_address, empty sections\n"); @@ -262,7 +262,7 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm)  		}  	} -	hw = (const __be16 *)sections[mvm->cfg->nvm_hw_section_num].data; +	hw = (const __be16 *)sections[mvm->trans->mac_cfg->base->nvm_hw_section_num].data;  	sw = (const __le16 *)sections[NVM_SECTION_TYPE_SW].data;  	calib = (const __le16 *)sections[NVM_SECTION_TYPE_CALIBRATION].data;  	mac_override = @@ -310,16 +310,15 @@ int iwl_nvm_init(struct iwl_mvm *mvm)  	int ret, section;  	u32 size_read = 0;  	u8 *nvm_buffer, *temp; -	const char *nvm_file_C = mvm->cfg->default_nvm_file_C_step; -	if (WARN_ON_ONCE(mvm->cfg->nvm_hw_section_num >= NVM_MAX_NUM_SECTIONS)) +	if (WARN_ON_ONCE(mvm->trans->mac_cfg->base->nvm_hw_section_num >= NVM_MAX_NUM_SECTIONS))  		return -EINVAL;  	/* load NVM values from nic */  	/* Read From FW NVM */  	IWL_DEBUG_EEPROM(mvm->trans->dev, "Read from NVM\n"); -	nvm_buffer = kmalloc(mvm->trans->trans_cfg->base_params->eeprom_size, +	nvm_buffer = kmalloc(mvm->trans->mac_cfg->base->eeprom_size,  			     GFP_KERNEL);  	if (!nvm_buffer)  		return -ENOMEM; @@ -340,7 +339,7 @@ int iwl_nvm_init(struct iwl_mvm *mvm)  			break;  		} -		iwl_nvm_fixups(mvm->trans->hw_id, section, temp, ret); +		iwl_nvm_fixups(mvm->trans->info.hw_id, section, temp, ret);  		mvm->nvm_sections[section].data = temp;  		mvm->nvm_sections[section].length = ret; @@ -369,7 +368,7 @@ int iwl_nvm_init(struct iwl_mvm *mvm)  			mvm->nvm_reg_blob.size  = ret;  			break;  		default: -			if (section == mvm->cfg->nvm_hw_section_num) { +			if (section == mvm->trans->mac_cfg->base->nvm_hw_section_num) {  				mvm->nvm_hw_blob.data = temp;  				mvm->nvm_hw_blob.size = ret;  				break; @@ -386,21 +385,8 @@ int iwl_nvm_init(struct iwl_mvm *mvm)  		/* read External NVM file from the mod param */  		ret = iwl_read_external_nvm(mvm->trans, mvm->nvm_file_name,  					    mvm->nvm_sections); -		if (ret) { -			mvm->nvm_file_name = nvm_file_C; - -			if ((ret == -EFAULT || ret == -ENOENT) && -			    mvm->nvm_file_name) { -				/* in case nvm file was failed try again */ -				ret = iwl_read_external_nvm(mvm->trans, -							    mvm->nvm_file_name, -							    mvm->nvm_sections); -				if (ret) -					return ret; -			} else { -				return ret; -			} -		} +		if (ret) +			return ret;  	}  	/* parse the relevant nvm sections */ @@ -556,7 +542,7 @@ int iwl_mvm_init_mcc(struct iwl_mvm *mvm)  	struct ieee80211_regdomain *regd;  	char mcc[3]; -	if (mvm->cfg->nvm_type == IWL_NVM_EXT) { +	if (mvm->trans->cfg->nvm_type == IWL_NVM_EXT) {  		tlv_lar = fw_has_capa(&mvm->fw->ucode_capa,  				      IWL_UCODE_TLV_CAPA_LAR_SUPPORT);  		nvm_lar = mvm->nvm_data->lar_enabled; @@ -613,6 +599,7 @@ void iwl_mvm_rx_chub_update_mcc(struct iwl_mvm *mvm,  	char mcc[3];  	struct ieee80211_regdomain *regd;  	int wgds_tbl_idx; +	bool changed = false;  	lockdep_assert_held(&mvm->mutex); @@ -632,10 +619,15 @@ void iwl_mvm_rx_chub_update_mcc(struct iwl_mvm *mvm,  	IWL_DEBUG_LAR(mvm,  		      "RX: received chub update mcc cmd (mcc '%s' src %d)\n",  		      mcc, src); -	regd = iwl_mvm_get_regdomain(mvm->hw->wiphy, mcc, src, NULL); +	regd = iwl_mvm_get_regdomain(mvm->hw->wiphy, mcc, src, &changed);  	if (IS_ERR_OR_NULL(regd))  		return; +	if (!changed) { +		IWL_DEBUG_LAR(mvm, "RX: No change in the regulatory data\n"); +		goto out; +	} +  	wgds_tbl_idx = iwl_mvm_get_sar_geo_profile(mvm);  	if (wgds_tbl_idx < 1)  		IWL_DEBUG_INFO(mvm, @@ -646,5 +638,7 @@ void iwl_mvm_rx_chub_update_mcc(struct iwl_mvm *mvm,  			       wgds_tbl_idx);  	regulatory_set_wiphy_regd(mvm->hw->wiphy, regd); + +out:  	kfree(regd);  } diff --git a/sys/contrib/dev/iwlwifi/mvm/offloading.c b/sys/contrib/dev/iwlwifi/mvm/offloading.c index 1eb21fe861e5..15d4369678a2 100644 --- a/sys/contrib/dev/iwlwifi/mvm/offloading.c +++ b/sys/contrib/dev/iwlwifi/mvm/offloading.c @@ -10,7 +10,7 @@  #include "mvm.h"  void iwl_mvm_set_wowlan_qos_seq(struct iwl_mvm_sta *mvm_ap_sta, -				struct iwl_wowlan_config_cmd *cmd) +				struct iwl_wowlan_config_cmd_v6 *cmd)  {  	int i; diff --git a/sys/contrib/dev/iwlwifi/mvm/ops.c b/sys/contrib/dev/iwlwifi/mvm/ops.c index 2d684f8e9030..912fb6677a0d 100644 --- a/sys/contrib/dev/iwlwifi/mvm/ops.c +++ b/sys/contrib/dev/iwlwifi/mvm/ops.c @@ -1,6 +1,6 @@  // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause  /* - * Copyright (C) 2012-2014, 2018-2024 Intel Corporation + * Copyright (C) 2012-2014, 2018-2025 Intel Corporation   * Copyright (C) 2013-2015 Intel Mobile Communications GmbH   * Copyright (C) 2016-2017 Intel Deutschland GmbH   */ @@ -43,7 +43,7 @@ MODULE_LICENSE("GPL");  MODULE_DESCRIPTION(DRV_DESCRIPTION);  MODULE_LICENSE("BSD");  #endif -MODULE_IMPORT_NS(IWLWIFI); +MODULE_IMPORT_NS("IWLWIFI");  static const struct iwl_op_mode_ops iwl_mvm_ops;  static const struct iwl_op_mode_ops iwl_mvm_ops_mq; @@ -74,8 +74,10 @@ static int __init iwl_mvm_init(void)  	}  	ret = iwl_opmode_register("iwlmvm", &iwl_mvm_ops); -	if (ret) +	if (ret) {  		pr_err("Unable to register MVM op_mode: %d\n", ret); +		iwl_mvm_rate_control_unregister(); +	}  	return ret;  } @@ -109,11 +111,11 @@ static void iwl_mvm_nic_config(struct iwl_op_mode *op_mode)  	IWL_DEBUG_INFO(mvm, "Radio type=0x%x-0x%x-0x%x\n", radio_cfg_type,  		       radio_cfg_step, radio_cfg_dash); -	if (mvm->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) +	if (mvm->trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_AX210)  		return;  	/* SKU control */ -	reg_val = CSR_HW_REV_STEP_DASH(mvm->trans->hw_rev); +	reg_val = CSR_HW_REV_STEP_DASH(mvm->trans->info.hw_rev);  	/* radio configuration */  	reg_val |= radio_cfg_type << CSR_HW_IF_CONFIG_REG_POS_PHY_TYPE; @@ -131,7 +133,7 @@ static void iwl_mvm_nic_config(struct iwl_op_mode *op_mode)  	 * unrelated errors. Need to further investigate this, but for now  	 * we'll separate cases.  	 */ -	if (mvm->trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_8000) +	if (mvm->trans->mac_cfg->device_family < IWL_DEVICE_FAMILY_8000)  		reg_val |= CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI;  	if (iwl_fw_dbg_is_d3_debug_enabled(&mvm->fwrt)) @@ -152,7 +154,7 @@ static void iwl_mvm_nic_config(struct iwl_op_mode *op_mode)  	 * (PCIe power is lost before PERST# is asserted), causing ME FW  	 * to lose ownership and not being able to obtain it back.  	 */ -	if (!mvm->trans->cfg->apmg_not_supported) +	if (!mvm->trans->mac_cfg->base->apmg_not_supported)  		iwl_set_bits_mask_prph(mvm->trans, APMG_PS_CTRL_REG,  				       APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS,  				       ~APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS); @@ -162,7 +164,7 @@ static void iwl_mvm_rx_esr_mode_notif(struct iwl_mvm *mvm,  				      struct iwl_rx_cmd_buffer *rxb)  {  	struct iwl_rx_packet *pkt = rxb_addr(rxb); -	struct iwl_mvm_esr_mode_notif *notif = (void *)pkt->data; +	struct iwl_esr_mode_notif *notif = (void *)pkt->data;  	struct ieee80211_vif *vif = iwl_mvm_get_bss_vif(mvm);  	/* FW recommendations is only for entering EMLSR */ @@ -188,7 +190,8 @@ static void iwl_mvm_rx_monitor_notif(struct iwl_mvm *mvm,  	if (notif->type != cpu_to_le32(IWL_DP_MON_NOTIF_TYPE_EXT_CCA))  		return; -	vif = iwl_mvm_get_vif_by_macid(mvm, notif->mac_id); +	/* FIXME: should fetch the link and not the vif */ +	vif = iwl_mvm_get_vif_by_macid(mvm, notif->link_id);  	if (!vif || vif->type != NL80211_IFTYPE_STATION)  		return; @@ -278,6 +281,12 @@ static void iwl_mvm_rx_thermal_dual_chain_req(struct iwl_mvm *mvm,  	struct iwl_rx_packet *pkt = rxb_addr(rxb);  	struct iwl_thermal_dual_chain_request *req = (void *)pkt->data; +	/* firmware is expected to handle that in RLC offload mode */ +	if (IWL_FW_CHECK(mvm, iwl_mvm_has_rlc_offload(mvm), +			 "Got THERMAL_DUAL_CHAIN_REQUEST (0x%x) in RLC offload mode\n", +			 req->event)) +		return; +  	/*  	 * We could pass it to the iterator data, but also need to remember  	 * it for new interfaces that are added while in this state. @@ -342,7 +351,7 @@ struct iwl_rx_handlers {   */  static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = {  	RX_HANDLER(TX_CMD, iwl_mvm_rx_tx_cmd, RX_HANDLER_SYNC, -		   struct iwl_mvm_tx_resp), +		   struct iwl_tx_resp),  	RX_HANDLER(BA_NOTIF, iwl_mvm_rx_ba_notif, RX_HANDLER_SYNC,  		   struct iwl_mvm_ba_notif), @@ -350,9 +359,12 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = {  		       iwl_mvm_tlc_update_notif, RX_HANDLER_SYNC,  		       struct iwl_tlc_update_notif), -	RX_HANDLER(BT_PROFILE_NOTIFICATION, iwl_mvm_rx_bt_coex_notif, +	RX_HANDLER(BT_PROFILE_NOTIFICATION, iwl_mvm_rx_bt_coex_old_notif,  		   RX_HANDLER_ASYNC_LOCKED_WIPHY, -		   struct iwl_bt_coex_profile_notif), +		   struct iwl_bt_coex_prof_old_notif), +	RX_HANDLER_GRP(BT_COEX_GROUP, PROFILE_NOTIF, iwl_mvm_rx_bt_coex_notif, +		       RX_HANDLER_ASYNC_LOCKED_WIPHY, +		       struct iwl_bt_coex_profile_notif),  	RX_HANDLER_NO_SIZE(BEACON_NOTIFICATION, iwl_mvm_rx_beacon_notif,  			   RX_HANDLER_ASYNC_LOCKED),  	RX_HANDLER_NO_SIZE(STATISTICS_NOTIFICATION, iwl_mvm_rx_statistics, @@ -379,7 +391,7 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = {  		   RX_HANDLER_SYNC, struct iwl_time_event_notif),  	RX_HANDLER_GRP(MAC_CONF_GROUP, SESSION_PROTECTION_NOTIF,  		       iwl_mvm_rx_session_protect_notif, RX_HANDLER_SYNC, -		       struct iwl_mvm_session_prot_notif), +		       struct iwl_session_prot_notif),  	RX_HANDLER(MCC_CHUB_UPDATE_CMD, iwl_mvm_rx_chub_update_mcc,  		   RX_HANDLER_ASYNC_LOCKED, struct iwl_mcc_chub_notif), @@ -402,10 +414,15 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = {  		   iwl_mvm_rx_umac_scan_iter_complete_notif, RX_HANDLER_SYNC,  		   struct iwl_umac_scan_iter_complete_notif), -	RX_HANDLER(MISSED_BEACONS_NOTIFICATION, iwl_mvm_rx_missed_beacons_notif, +	RX_HANDLER(MISSED_BEACONS_NOTIFICATION, +		   iwl_mvm_rx_missed_beacons_notif_legacy,  		   RX_HANDLER_ASYNC_LOCKED_WIPHY, -		   struct iwl_missed_beacons_notif), +		   struct iwl_missed_beacons_notif_v4), +	RX_HANDLER_GRP(MAC_CONF_GROUP, MISSED_BEACONS_NOTIF, +		       iwl_mvm_rx_missed_beacons_notif, +		       RX_HANDLER_ASYNC_LOCKED_WIPHY, +		       struct iwl_missed_beacons_notif),  	RX_HANDLER(REPLY_ERROR, iwl_mvm_rx_fw_error, RX_HANDLER_SYNC,  		   struct iwl_error_resp),  	RX_HANDLER(PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION, @@ -460,7 +477,7 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = {  	RX_HANDLER_GRP(DATA_PATH_GROUP, ESR_MODE_NOTIF,  		       iwl_mvm_rx_esr_mode_notif,  		       RX_HANDLER_ASYNC_LOCKED_WIPHY, -		       struct iwl_mvm_esr_mode_notif), +		       struct iwl_esr_mode_notif),  	RX_HANDLER_GRP(DATA_PATH_GROUP, MONITOR_NOTIF,  		       iwl_mvm_rx_monitor_notif, RX_HANDLER_ASYNC_LOCKED, @@ -489,6 +506,11 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = {  	RX_HANDLER_GRP(SCAN_GROUP, CHANNEL_SURVEY_NOTIF,  		       iwl_mvm_rx_channel_survey_notif, RX_HANDLER_ASYNC_LOCKED,  		       struct iwl_umac_scan_channel_survey_notif), +	RX_HANDLER_GRP(DATA_PATH_GROUP, BEACON_FILTER_IN_NOTIF, +		       iwl_mvm_rx_beacon_filter_notif, +		       RX_HANDLER_ASYNC_LOCKED, +		       /* same size as v1 */ +		       struct iwl_beacon_filter_notif),  };  #undef RX_HANDLER  #undef RX_HANDLER_GRP @@ -659,6 +681,7 @@ static const struct iwl_hcmd_names iwl_mvm_data_path_names[] = {  	HCMD_NAME(ESR_MODE_NOTIF),  	HCMD_NAME(MONITOR_NOTIF),  	HCMD_NAME(THERMAL_DUAL_CHAIN_REQUEST), +	HCMD_NAME(BEACON_FILTER_IN_NOTIF),  	HCMD_NAME(STA_PM_NOTIF),  	HCMD_NAME(MU_GROUP_MGMT_NOTIF),  	HCMD_NAME(RX_QUEUES_NOTIFICATION), @@ -730,7 +753,15 @@ static const struct iwl_hcmd_names iwl_mvm_regulatory_and_nvm_names[] = {  	HCMD_NAME(TAS_CONFIG),  }; -static const struct iwl_hcmd_arr iwl_mvm_groups[] = { +/* Please keep this array *SORTED* by hex value. + * Access is done through binary search + */ +static const struct iwl_hcmd_names iwl_mvm_bt_coex_names[] = { +	HCMD_NAME(PROFILE_NOTIF), +}; + +VISIBLE_IF_IWLWIFI_KUNIT +const struct iwl_hcmd_arr iwl_mvm_groups[] = {  	[LEGACY_GROUP] = HCMD_ARR(iwl_mvm_legacy_names),  	[LONG_GROUP] = HCMD_ARR(iwl_mvm_legacy_names),  	[SYSTEM_GROUP] = HCMD_ARR(iwl_mvm_system_names), @@ -739,12 +770,18 @@ static const struct iwl_hcmd_arr iwl_mvm_groups[] = {  	[DATA_PATH_GROUP] = HCMD_ARR(iwl_mvm_data_path_names),  	[SCAN_GROUP] = HCMD_ARR(iwl_mvm_scan_names),  	[LOCATION_GROUP] = HCMD_ARR(iwl_mvm_location_names), +	[BT_COEX_GROUP] = HCMD_ARR(iwl_mvm_bt_coex_names),  	[PROT_OFFLOAD_GROUP] = HCMD_ARR(iwl_mvm_prot_offload_names),  	[REGULATORY_AND_NVM_GROUP] =  		HCMD_ARR(iwl_mvm_regulatory_and_nvm_names),  	[DEBUG_GROUP] = HCMD_ARR(iwl_mvm_debug_names),  	[STATISTICS_GROUP] = HCMD_ARR(iwl_mvm_statistics_names),  }; +EXPORT_SYMBOL_IF_IWLWIFI_KUNIT(iwl_mvm_groups); +#if IS_ENABLED(CONFIG_IWLWIFI_KUNIT_TESTS) +const unsigned int iwl_mvm_groups_size = ARRAY_SIZE(iwl_mvm_groups); +EXPORT_SYMBOL_IF_IWLWIFI_KUNIT(iwl_mvm_groups_size); +#endif  /* this forward declaration can avoid to export the function */  static void iwl_mvm_async_handlers_wk(struct work_struct *wk); @@ -1228,13 +1265,12 @@ static void iwl_mvm_trig_link_selection(struct wiphy *wiphy,  }  static struct iwl_op_mode * -iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, +iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_rf_cfg *cfg,  		      const struct iwl_fw *fw, struct dentry *dbgfs_dir)  {  	struct ieee80211_hw *hw;  	struct iwl_op_mode *op_mode;  	struct iwl_mvm *mvm; -	struct iwl_trans_config trans_cfg = {};  	static const u8 no_reclaim_cmds[] = {  		TX_CMD,  	}; @@ -1242,14 +1278,16 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,  	size_t scan_size;  	u32 min_backoff;  	struct iwl_mvm_csme_conn_info *csme_conn_info __maybe_unused; +	int ratecheck; +	int err;  	/* -	 * We use IWL_MVM_STATION_COUNT_MAX to check the validity of the station +	 * We use IWL_STATION_COUNT_MAX to check the validity of the station  	 * index all over the driver - check that its value corresponds to the  	 * array size.  	 */  	BUILD_BUG_ON(ARRAY_SIZE(mvm->fw_id_to_mac_id) != -		     IWL_MVM_STATION_COUNT_MAX); +		     IWL_STATION_COUNT_MAX);  	/********************************  	 * 1. Allocating and configuring HW data @@ -1259,20 +1297,15 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,  				iwl_mvm_has_mld_api(fw) ? &iwl_mvm_mld_hw_ops :  				&iwl_mvm_hw_ops);  	if (!hw) -		return NULL; +		return ERR_PTR(-ENOMEM); -	if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_BZ) +	if (trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_BZ)  		max_agg = 512;  	else  		max_agg = IEEE80211_MAX_AMPDU_BUF_HE;  	hw->max_rx_aggregation_subframes = max_agg; -	if (cfg->max_tx_agg_size) -		hw->max_tx_aggregation_subframes = cfg->max_tx_agg_size; -	else -		hw->max_tx_aggregation_subframes = max_agg; -  	op_mode = hw->priv;  	mvm = IWL_OP_MODE_GET_MVM(op_mode); @@ -1288,27 +1321,67 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,  	iwl_mvm_get_bios_tables(mvm);  	iwl_uefi_get_sgom_table(trans, &mvm->fwrt);  	iwl_uefi_get_step_table(trans); +	iwl_bios_setup_step(trans, &mvm->fwrt);  	mvm->init_status = 0; +	/* start with v1 rates */ +	mvm->fw_rates_ver = 1; + +	/* check for rates version 2 */ +	ratecheck = +		(iwl_fw_lookup_cmd_ver(mvm->fw, TX_CMD, 0) >= 8) + +		(iwl_fw_lookup_notif_ver(mvm->fw, DATA_PATH_GROUP, +					 TLC_MNG_UPDATE_NOTIF, 0) >= 3) + +		(iwl_fw_lookup_notif_ver(mvm->fw, LEGACY_GROUP, +					 REPLY_RX_MPDU_CMD, 0) >= 4) + +		(iwl_fw_lookup_notif_ver(mvm->fw, LONG_GROUP, TX_CMD, 0) >= 6); +	if (ratecheck != 0 && ratecheck != 4) { +		IWL_ERR(mvm, "Firmware has inconsistent rates\n"); +		err = -EINVAL; +		goto out_free; +	} +	if (ratecheck == 4) +		mvm->fw_rates_ver = 2; + +	/* check for rates version 3 */ +	ratecheck = +		(iwl_fw_lookup_cmd_ver(mvm->fw, TX_CMD, 0) >= 11) + +		(iwl_fw_lookup_notif_ver(mvm->fw, DATA_PATH_GROUP, +					 TLC_MNG_UPDATE_NOTIF, 0) >= 4) + +		(iwl_fw_lookup_notif_ver(mvm->fw, LEGACY_GROUP, +					 REPLY_RX_MPDU_CMD, 0) >= 6) + +		(iwl_fw_lookup_notif_ver(mvm->fw, DATA_PATH_GROUP, +					 RX_NO_DATA_NOTIF, 0) >= 4) + +		(iwl_fw_lookup_notif_ver(mvm->fw, LONG_GROUP, TX_CMD, 0) >= 9); +	if (ratecheck != 0 && ratecheck != 5) { +		IWL_ERR(mvm, "Firmware has inconsistent rates\n"); +		err = -EINVAL; +		goto out_free; +	} +	if (ratecheck == 5) +		mvm->fw_rates_ver = 3; + +	trans->conf.rx_mpdu_cmd = REPLY_RX_MPDU_CMD; +  	if (iwl_mvm_has_new_rx_api(mvm)) {  		op_mode->ops = &iwl_mvm_ops_mq; -		trans->rx_mpdu_cmd_hdr_size = -			(trans->trans_cfg->device_family >= +		trans->conf.rx_mpdu_cmd_hdr_size = +			(trans->mac_cfg->device_family >=  			 IWL_DEVICE_FAMILY_AX210) ?  			sizeof(struct iwl_rx_mpdu_desc) :  			IWL_RX_DESC_SIZE_V1;  	} else {  		op_mode->ops = &iwl_mvm_ops; -		trans->rx_mpdu_cmd_hdr_size = +		trans->conf.rx_mpdu_cmd_hdr_size =  			sizeof(struct iwl_rx_mpdu_res_start); -		if (WARN_ON(trans->num_rx_queues > 1)) +		if (WARN_ON(trans->info.num_rxqs > 1)) { +			err = -EINVAL;  			goto out_free; +		}  	} -	mvm->fw_restart = iwlwifi_mod_params.fw_restart ? -1 : 0; -  	if (iwl_mvm_has_new_tx_api(mvm)) {  		/*  		 * If we have the new TX/queue allocation API initialize them @@ -1380,66 +1453,58 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,  		iwl_fw_lookup_notif_ver(mvm->fw, LOCATION_GROUP,  					TOF_RANGE_RESPONSE_NOTIF, 5);  	/* we only support up to version 9 */ -	if (WARN_ON_ONCE(mvm->cmd_ver.range_resp > 9)) +	if (WARN_ON_ONCE(mvm->cmd_ver.range_resp > 9)) { +		err = -EINVAL;  		goto out_free; +	}  	/*  	 * Populate the state variables that the transport layer needs  	 * to know about.  	 */ -	trans_cfg.op_mode = op_mode; -	trans_cfg.no_reclaim_cmds = no_reclaim_cmds; -	trans_cfg.n_no_reclaim_cmds = ARRAY_SIZE(no_reclaim_cmds); - -	trans_cfg.rx_buf_size = iwl_amsdu_size_to_rxb_size(); +	BUILD_BUG_ON(sizeof(no_reclaim_cmds) > +		     sizeof(trans->conf.no_reclaim_cmds)); +	memcpy(trans->conf.no_reclaim_cmds, no_reclaim_cmds, +	       sizeof(no_reclaim_cmds)); +	trans->conf.n_no_reclaim_cmds = ARRAY_SIZE(no_reclaim_cmds); -	trans->wide_cmd_header = true; -	trans_cfg.bc_table_dword = -		mvm->trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_AX210; +	trans->conf.rx_buf_size = iwl_amsdu_size_to_rxb_size(); -	trans_cfg.command_groups = iwl_mvm_groups; -	trans_cfg.command_groups_size = ARRAY_SIZE(iwl_mvm_groups); +	trans->conf.wide_cmd_header = true; -	trans_cfg.cmd_queue = IWL_MVM_DQA_CMD_QUEUE; -	trans_cfg.cmd_fifo = IWL_MVM_TX_FIFO_CMD; -	trans_cfg.scd_set_active = true; +	trans->conf.command_groups = iwl_mvm_groups; +	trans->conf.command_groups_size = ARRAY_SIZE(iwl_mvm_groups); -	trans_cfg.cb_data_offs = offsetof(struct ieee80211_tx_info, -					  driver_data[2]); +	trans->conf.cmd_queue = IWL_MVM_DQA_CMD_QUEUE; +	trans->conf.cmd_fifo = IWL_MVM_TX_FIFO_CMD; +	trans->conf.scd_set_active = true; -	/* Set a short watchdog for the command queue */ -	trans_cfg.cmd_q_wdg_timeout = -		iwl_mvm_get_wd_timeout(mvm, NULL, false, true); +	trans->conf.cb_data_offs = offsetof(struct ieee80211_tx_info, +					    driver_data[2]);  	snprintf(mvm->hw->wiphy->fw_version,  		 sizeof(mvm->hw->wiphy->fw_version),  		 "%.31s", fw->fw_version); -	trans_cfg.fw_reset_handshake = fw_has_capa(&mvm->fw->ucode_capa, -						   IWL_UCODE_TLV_CAPA_FW_RESET_HANDSHAKE); +	trans->conf.fw_reset_handshake = +		fw_has_capa(&mvm->fw->ucode_capa, +			    IWL_UCODE_TLV_CAPA_FW_RESET_HANDSHAKE); -	trans_cfg.queue_alloc_cmd_ver = +	trans->conf.queue_alloc_cmd_ver =  		iwl_fw_lookup_cmd_ver(mvm->fw,  				      WIDE_ID(DATA_PATH_GROUP,  					      SCD_QUEUE_CONFIG_CMD),  				      0);  	mvm->sta_remove_requires_queue_remove = -		trans_cfg.queue_alloc_cmd_ver > 0; +		trans->conf.queue_alloc_cmd_ver > 0;  	mvm->mld_api_is_used = iwl_mvm_has_mld_api(mvm->fw);  	/* Configure transport layer */ -	iwl_trans_configure(mvm->trans, &trans_cfg); +	iwl_trans_op_mode_enter(mvm->trans, op_mode); -	trans->rx_mpdu_cmd = REPLY_RX_MPDU_CMD;  	trans->dbg.dest_tlv = mvm->fw->dbg.dest_tlv;  	trans->dbg.n_dest_reg = mvm->fw->dbg.n_dest_reg; -	memcpy(trans->dbg.conf_tlv, mvm->fw->dbg.conf_tlv, -	       sizeof(trans->dbg.conf_tlv)); -	trans->dbg.trigger_tlv = mvm->fw->dbg.trigger_tlv; - -	trans->iml = mvm->fw->iml; -	trans->iml_len = mvm->fw->iml_len;  	/* set up notification wait support */  	iwl_notification_wait_init(&mvm->notif_wait); @@ -1448,6 +1513,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,  	mvm->phy_db = iwl_phy_db_init(trans);  	if (!mvm->phy_db) {  		IWL_ERR(mvm, "Cannot init phy_db\n"); +		err = -ENOMEM;  		goto out_free;  	} @@ -1460,13 +1526,15 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,  	scan_size = iwl_mvm_scan_size(mvm);  	mvm->scan_cmd = kmalloc(scan_size, GFP_KERNEL); -	if (!mvm->scan_cmd) +	if (!mvm->scan_cmd) { +		err = -ENOMEM;  		goto out_free; +	}  	mvm->scan_cmd_size = scan_size;  	/* invalidate ids to prevent accidental removal of sta_id 0 */ -	mvm->aux_sta.sta_id = IWL_MVM_INVALID_STA; -	mvm->snif_sta.sta_id = IWL_MVM_INVALID_STA; +	mvm->aux_sta.sta_id = IWL_INVALID_STA; +	mvm->snif_sta.sta_id = IWL_INVALID_STA;  	/* Set EBS as successful as long as not stated otherwise by the FW. */  	mvm->last_ebs_successful = true; @@ -1494,7 +1562,8 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,  	iwl_mvm_mei_scan_filter_init(&mvm->mei_scan_filter); -	if (iwl_mvm_start_get_nvm(mvm)) { +	err = iwl_mvm_start_get_nvm(mvm); +	if (err) {  		/*  		 * Getting NVM failed while CSME is the owner, but we are  		 * registered to MEI, we'll get the NVM later when it'll be @@ -1507,7 +1576,8 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,  	} -	if (iwl_mvm_start_post_nvm(mvm)) +	err = iwl_mvm_start_post_nvm(mvm); +	if (err)  		goto out_thermal_exit;  	return op_mode; @@ -1527,7 +1597,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,  	iwl_trans_op_mode_leave(trans);  	ieee80211_free_hw(mvm->hw); -	return NULL; +	return ERR_PTR(err);  }  void iwl_mvm_stop_device(struct iwl_mvm *mvm) @@ -1962,27 +2032,62 @@ static void iwl_mvm_free_skb(struct iwl_op_mode *op_mode, struct sk_buff *skb)  	ieee80211_free_txskb(mvm->hw, skb);  } -struct iwl_mvm_reprobe { -	struct device *dev; -	struct work_struct work; -}; +static void iwl_mvm_nic_error(struct iwl_op_mode *op_mode, +			      enum iwl_fw_error_type type) +{ +	struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); + +	iwl_abort_notification_waits(&mvm->notif_wait); +	iwl_dbg_tlv_del_timers(mvm->trans); + +	if (type == IWL_ERR_TYPE_CMD_QUEUE_FULL) +		IWL_ERR(mvm, "Command queue full!\n"); +	else if (!iwl_trans_is_dead(mvm->trans) && +		 !test_and_clear_bit(IWL_MVM_STATUS_SUPPRESS_ERROR_LOG_ONCE, +				     &mvm->status)) +		iwl_mvm_dump_nic_error_log(mvm); + +	/* +	 * This should be first thing before trying to collect any +	 * data to avoid endless loops if any HW error happens while +	 * collecting debug data. +	 * It might not actually be true that we'll restart, but the +	 * setting of the bit doesn't matter if we're going to be +	 * unbound either. +	 */ +	if (type != IWL_ERR_TYPE_RESET_HS_TIMEOUT) +		set_bit(IWL_MVM_STATUS_HW_RESTART_REQUESTED, &mvm->status); +} -static void iwl_mvm_reprobe_wk(struct work_struct *wk) +static void iwl_mvm_dump_error(struct iwl_op_mode *op_mode, +			       struct iwl_fw_error_dump_mode *mode)  { -	struct iwl_mvm_reprobe *reprobe; - -	reprobe = container_of(wk, struct iwl_mvm_reprobe, work); -	if (device_reprobe(reprobe->dev)) -		dev_err(reprobe->dev, "reprobe failed!\n"); -	put_device(reprobe->dev); -	kfree(reprobe); -	module_put(THIS_MODULE); +	struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); + +	/* if we come in from opmode we have the mutex held */ +	if (mode->context == IWL_ERR_CONTEXT_FROM_OPMODE) { +		lockdep_assert_held(&mvm->mutex); +		iwl_fw_error_collect(&mvm->fwrt); +	} else { +		mutex_lock(&mvm->mutex); +		if (mode->context != IWL_ERR_CONTEXT_ABORT) +			iwl_fw_error_collect(&mvm->fwrt); +		mutex_unlock(&mvm->mutex); +	}  } -void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error) +static bool iwl_mvm_sw_reset(struct iwl_op_mode *op_mode, +			     enum iwl_fw_error_type type)  { -	iwl_abort_notification_waits(&mvm->notif_wait); -	iwl_dbg_tlv_del_timers(mvm->trans); +	struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); + +	/* +	 * If the firmware crashes while we're already considering it +	 * to be dead then don't ask for a restart, that cannot do +	 * anything useful anyway. +	 */ +	if (!test_bit(IWL_MVM_STATUS_FIRMWARE_RUNNING, &mvm->status)) +		return false;  	/*  	 * This is a bit racy, but worst case we tell mac80211 about @@ -1997,52 +2102,11 @@ void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error)  	iwl_mvm_report_scan_aborted(mvm);  	/* -	 * If we're restarting already, don't cycle restarts.  	 * If INIT fw asserted, it will likely fail again.  	 * If WoWLAN fw asserted, don't restart either, mac80211  	 * can't recover this since we're already half suspended.  	 */ -	if (!mvm->fw_restart && fw_error) { -		iwl_fw_error_collect(&mvm->fwrt, false); -	} else if (test_bit(IWL_MVM_STATUS_STARTING, -			    &mvm->status)) { -		IWL_ERR(mvm, "Starting mac, retry will be triggered anyway\n"); -	} else if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) { -		struct iwl_mvm_reprobe *reprobe; - -		IWL_ERR(mvm, -			"Firmware error during reconfiguration - reprobe!\n"); - -		/* -		 * get a module reference to avoid doing this while unloading -		 * anyway and to avoid scheduling a work with code that's -		 * being removed. -		 */ -		if (!try_module_get(THIS_MODULE)) { -			IWL_ERR(mvm, "Module is being unloaded - abort\n"); -			return; -		} - -		reprobe = kzalloc(sizeof(*reprobe), GFP_ATOMIC); -		if (!reprobe) { -			module_put(THIS_MODULE); -			return; -		} -		reprobe->dev = get_device(mvm->trans->dev); -		INIT_WORK(&reprobe->work, iwl_mvm_reprobe_wk); -		schedule_work(&reprobe->work); -	} else if (test_bit(IWL_MVM_STATUS_HW_RESTART_REQUESTED, -			    &mvm->status)) { -		IWL_ERR(mvm, "HW restart already requested, but not started\n"); -	} else if (mvm->fwrt.cur_fw_img == IWL_UCODE_REGULAR && -		   mvm->hw_registered && -		   !test_bit(STATUS_TRANS_DEAD, &mvm->trans->status)) { -		/* This should be first thing before trying to collect any -		 * data to avoid endless loops if any HW error happens while -		 * collecting debug data. -		 */ -		set_bit(IWL_MVM_STATUS_HW_RESTART_REQUESTED, &mvm->status); - +	if (mvm->fwrt.cur_fw_img == IWL_UCODE_REGULAR && mvm->hw_registered) {  		if (mvm->fw->ucode_capa.error_log_size) {  			u32 src_size = mvm->fw->ucode_capa.error_log_size;  			u32 src_addr = mvm->fw->ucode_capa.error_log_addr; @@ -2057,81 +2121,55 @@ void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error)  			}  		} -		iwl_fw_error_collect(&mvm->fwrt, false); - -		if (fw_error && mvm->fw_restart > 0) { -			mvm->fw_restart--; -			ieee80211_restart_hw(mvm->hw); -		} else if (mvm->fwrt.trans->dbg.restart_required) { +		if (mvm->fwrt.trans->dbg.restart_required) {  			IWL_DEBUG_INFO(mvm, "FW restart requested after debug collection\n");  			mvm->fwrt.trans->dbg.restart_required = false;  			ieee80211_restart_hw(mvm->hw); -		} else if (mvm->trans->trans_cfg->device_family <= IWL_DEVICE_FAMILY_8000) { +			return true; +		} else if (mvm->trans->mac_cfg->device_family <= IWL_DEVICE_FAMILY_8000) {  			ieee80211_restart_hw(mvm->hw); +			return true;  		}  	} -} - -static void iwl_mvm_nic_error(struct iwl_op_mode *op_mode, bool sync) -{ -	struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); - -	if (!test_bit(STATUS_TRANS_DEAD, &mvm->trans->status) && -	    !test_and_clear_bit(IWL_MVM_STATUS_SUPPRESS_ERROR_LOG_ONCE, -				&mvm->status)) -		iwl_mvm_dump_nic_error_log(mvm); - -	if (sync) { -		iwl_fw_error_collect(&mvm->fwrt, true); -		/* -		 * Currently, the only case for sync=true is during -		 * shutdown, so just stop in this case. If/when that -		 * changes, we need to be a bit smarter here. -		 */ -		return; -	} -	/* -	 * If the firmware crashes while we're already considering it -	 * to be dead then don't ask for a restart, that cannot do -	 * anything useful anyway. -	 */ -	if (!test_bit(IWL_MVM_STATUS_FIRMWARE_RUNNING, &mvm->status)) -		return; - -	iwl_mvm_nic_restart(mvm, false); +	return false;  } -static void iwl_mvm_cmd_queue_full(struct iwl_op_mode *op_mode) +static void iwl_op_mode_mvm_time_point(struct iwl_op_mode *op_mode, +				       enum iwl_fw_ini_time_point tp_id, +				       union iwl_dbg_tlv_tp_data *tp_data)  {  	struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); -	WARN_ON(1); -	iwl_mvm_nic_restart(mvm, true); +	iwl_dbg_tlv_time_point(&mvm->fwrt, tp_id, tp_data);  } -static void iwl_op_mode_mvm_time_point(struct iwl_op_mode *op_mode, -				       enum iwl_fw_ini_time_point tp_id, -				       union iwl_dbg_tlv_tp_data *tp_data) +static void iwl_mvm_dump(struct iwl_op_mode *op_mode)  {  	struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); +	struct iwl_fw_runtime *fwrt = &mvm->fwrt; -	iwl_dbg_tlv_time_point(&mvm->fwrt, tp_id, tp_data); +	if (!iwl_trans_fw_running(fwrt->trans)) +		return; + +	iwl_dbg_tlv_time_point(fwrt, IWL_FW_INI_TIME_POINT_USER_TRIGGER, NULL);  } +#ifdef CONFIG_PM_SLEEP  static void iwl_op_mode_mvm_device_powered_off(struct iwl_op_mode *op_mode)  {  	struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode);  	mutex_lock(&mvm->mutex);  	clear_bit(IWL_MVM_STATUS_IN_D3, &mvm->status); -	mvm->trans->system_pm_mode = IWL_PLAT_PM_MODE_DISABLED;  	iwl_mvm_stop_device(mvm); -#ifdef CONFIG_PM  	mvm->fast_resume = false; -#endif  	mutex_unlock(&mvm->mutex);  } +#else +static void iwl_op_mode_mvm_device_powered_off(struct iwl_op_mode *op_mode) +{} +#endif  #define IWL_MVM_COMMON_OPS					\  	/* these could be differentiated */			\ @@ -2140,7 +2178,8 @@ static void iwl_op_mode_mvm_device_powered_off(struct iwl_op_mode *op_mode)  	.hw_rf_kill = iwl_mvm_set_hw_rfkill_state,		\  	.free_skb = iwl_mvm_free_skb,				\  	.nic_error = iwl_mvm_nic_error,				\ -	.cmd_queue_full = iwl_mvm_cmd_queue_full,		\ +	.dump_error = iwl_mvm_dump_error,			\ +	.sw_reset = iwl_mvm_sw_reset,				\  	.nic_config = iwl_mvm_nic_config,			\  	/* as we only register one, these MUST be common! */	\  	.start = iwl_op_mode_mvm_start,				\ @@ -2162,7 +2201,7 @@ static void iwl_mvm_rx_mq_rss(struct iwl_op_mode *op_mode,  	struct iwl_rx_packet *pkt = rxb_addr(rxb);  	u16 cmd = WIDE_ID(pkt->hdr.group_id, pkt->hdr.cmd); -	if (unlikely(queue >= mvm->trans->num_rx_queues)) +	if (unlikely(queue >= mvm->trans->info.num_rxqs))  		return;  	if (unlikely(cmd == WIDE_ID(LEGACY_GROUP, FRAME_RELEASE))) @@ -2178,4 +2217,5 @@ static const struct iwl_op_mode_ops iwl_mvm_ops_mq = {  	IWL_MVM_COMMON_OPS,  	.rx = iwl_mvm_rx_mq,  	.rx_rss = iwl_mvm_rx_mq_rss, +	.dump = iwl_mvm_dump,  }; diff --git a/sys/contrib/dev/iwlwifi/mvm/phy-ctxt.c b/sys/contrib/dev/iwlwifi/mvm/phy-ctxt.c index ce264b386029..5e7e2926be0c 100644 --- a/sys/contrib/dev/iwlwifi/mvm/phy-ctxt.c +++ b/sys/contrib/dev/iwlwifi/mvm/phy-ctxt.c @@ -31,7 +31,7 @@ u8 iwl_mvm_get_channel_width(const struct cfg80211_chan_def *chandef)  /*   * Maps the driver specific control channel position (relative to the center - * freq) definitions to the the fw values + * freq) definitions to the fw values   */  u8 iwl_mvm_get_ctrl_pos(const struct cfg80211_chan_def *chandef)  { @@ -159,7 +159,11 @@ int iwl_mvm_phy_send_rlc(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt,  		.phy_id = cpu_to_le32(ctxt->id),  	}; -	if (ctxt->rlc_disabled) +	/* From version 3, RLC is offloaded to firmware, so the driver no +	 * longer needs to send cmd.rlc, note that we are not using any +	 * other fields in the command - don't send it. +	 */ +	if (iwl_mvm_has_rlc_offload(mvm) || ctxt->rlc_disabled)  		return 0;  	if (iwl_fw_lookup_cmd_ver(mvm->fw, WIDE_ID(DATA_PATH_GROUP, diff --git a/sys/contrib/dev/iwlwifi/mvm/power.c b/sys/contrib/dev/iwlwifi/mvm/power.c index bc363e8427e4..610de29b7be0 100644 --- a/sys/contrib/dev/iwlwifi/mvm/power.c +++ b/sys/contrib/dev/iwlwifi/mvm/power.c @@ -1,6 +1,6 @@  // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause  /* - * Copyright (C) 2012-2014, 2018-2019, 2021-2024 Intel Corporation + * Copyright (C) 2012-2014, 2018-2019, 2021-2025 Intel Corporation   * Copyright (C) 2013-2014 Intel Mobile Communications GmbH   * Copyright (C) 2015-2017 Intel Deutschland GmbH   */ @@ -231,7 +231,6 @@ static void iwl_mvm_allow_uapsd_iterator(void *_data, u8 *mac,  	switch (vif->type) {  	case NL80211_IFTYPE_AP:  	case NL80211_IFTYPE_ADHOC: -	case NL80211_IFTYPE_NAN:  		data->allow_uapsd = false;  		break;  	case NL80211_IFTYPE_STATION: @@ -376,6 +375,9 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm,  	if (!vif->cfg.ps || !mvmvif->pm_enabled)  		return; +	if (iwl_fw_lookup_cmd_ver(mvm->fw, MAC_PM_POWER_TABLE, 0) >= 2) +		cmd->flags |= cpu_to_le16(POWER_FLAGS_ENABLE_SMPS_MSK); +  	if (iwl_mvm_vif_low_latency(mvmvif) && vif->p2p &&  	    (!fw_has_capa(&mvm->fw->ucode_capa,  			 IWL_UCODE_TLV_CAPA_SHORT_PM_TIMEOUTS) || @@ -567,7 +569,7 @@ struct iwl_power_vifs {  	bool monitor_active;  }; -static void iwl_mvm_power_disable_pm_iterator(void *_data, u8* mac, +static void iwl_mvm_power_disable_pm_iterator(void *_data, u8 *mac,  					      struct ieee80211_vif *vif)  {  	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); @@ -575,7 +577,7 @@ static void iwl_mvm_power_disable_pm_iterator(void *_data, u8* mac,  	mvmvif->pm_enabled = false;  } -static void iwl_mvm_power_ps_disabled_iterator(void *_data, u8* mac, +static void iwl_mvm_power_ps_disabled_iterator(void *_data, u8 *mac,  					       struct ieee80211_vif *vif)  {  	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); diff --git a/sys/contrib/dev/iwlwifi/mvm/ptp.c b/sys/contrib/dev/iwlwifi/mvm/ptp.c index e89259de6f4c..06a4c9f74797 100644 --- a/sys/contrib/dev/iwlwifi/mvm/ptp.c +++ b/sys/contrib/dev/iwlwifi/mvm/ptp.c @@ -1,6 +1,6 @@  // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause  /* - * Copyright (C) 2021 - 2023 Intel Corporation + * Copyright (C) 2021 - 2023, 2025 Intel Corporation   */  #include "mvm.h" @@ -298,9 +298,9 @@ void iwl_mvm_ptp_init(struct iwl_mvm *mvm)  			PTR_ERR(mvm->ptp_data.ptp_clock));  		mvm->ptp_data.ptp_clock = NULL;  	} else if (mvm->ptp_data.ptp_clock) { -		IWL_INFO(mvm, "Registered PHC clock: %s, with index: %d\n", -			 mvm->ptp_data.ptp_clock_info.name, -			 ptp_clock_index(mvm->ptp_data.ptp_clock)); +		IWL_DEBUG_INFO(mvm, "Registered PHC clock: %s, with index: %d\n", +			       mvm->ptp_data.ptp_clock_info.name, +			       ptp_clock_index(mvm->ptp_data.ptp_clock));  	}  } @@ -312,9 +312,9 @@ void iwl_mvm_ptp_init(struct iwl_mvm *mvm)  void iwl_mvm_ptp_remove(struct iwl_mvm *mvm)  {  	if (mvm->ptp_data.ptp_clock) { -		IWL_INFO(mvm, "Unregistering PHC clock: %s, with index: %d\n", -			 mvm->ptp_data.ptp_clock_info.name, -			 ptp_clock_index(mvm->ptp_data.ptp_clock)); +		IWL_DEBUG_INFO(mvm, "Unregistering PHC clock: %s, with index: %d\n", +			       mvm->ptp_data.ptp_clock_info.name, +			       ptp_clock_index(mvm->ptp_data.ptp_clock));  		ptp_clock_unregister(mvm->ptp_data.ptp_clock);  		mvm->ptp_data.ptp_clock = NULL; diff --git a/sys/contrib/dev/iwlwifi/mvm/quota.c b/sys/contrib/dev/iwlwifi/mvm/quota.c index aad2614af9ad..798a7e4bea83 100644 --- a/sys/contrib/dev/iwlwifi/mvm/quota.c +++ b/sys/contrib/dev/iwlwifi/mvm/quota.c @@ -1,6 +1,6 @@  // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause  /* - * Copyright (C) 2012-2014, 2018, 2021-2022 Intel Corporation + * Copyright (C) 2012-2014, 2018, 2021-2022, 2025 Intel Corporation   * Copyright (C) 2013-2014 Intel Mobile Communications GmbH   * Copyright (C) 2016-2017 Intel Deutschland GmbH   */ @@ -86,45 +86,6 @@ static void iwl_mvm_quota_iterator(void *_data, u8 *mac,  	}  } -static void iwl_mvm_adjust_quota_for_noa(struct iwl_mvm *mvm, -					 struct iwl_time_quota_cmd *cmd) -{ -#ifdef CONFIG_NL80211_TESTMODE -	struct iwl_mvm_vif *mvmvif; -	int i, phy_id = -1, beacon_int = 0; - -	if (!mvm->noa_duration || !mvm->noa_vif) -		return; - -	mvmvif = iwl_mvm_vif_from_mac80211(mvm->noa_vif); -	if (!mvmvif->ap_ibss_active) -		return; - -	phy_id = mvmvif->deflink.phy_ctxt->id; -	beacon_int = mvm->noa_vif->bss_conf.beacon_int; - -	for (i = 0; i < MAX_BINDINGS; i++) { -		struct iwl_time_quota_data *data = -					iwl_mvm_quota_cmd_get_quota(mvm, cmd, -								    i); -		u32 id_n_c = le32_to_cpu(data->id_and_color); -		u32 id = (id_n_c & FW_CTXT_ID_MSK) >> FW_CTXT_ID_POS; -		u32 quota = le32_to_cpu(data->quota); - -		if (id != phy_id) -			continue; - -		quota *= (beacon_int - mvm->noa_duration); -		quota /= beacon_int; - -		IWL_DEBUG_QUOTA(mvm, "quota: adjust for NoA from %d to %d\n", -				le32_to_cpu(data->quota), quota); - -		data->quota = cpu_to_le32(quota); -	} -#endif -} -  int iwl_mvm_update_quotas(struct iwl_mvm *mvm,  			  bool force_update,  			  struct ieee80211_vif *disabled_vif) @@ -260,8 +221,6 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm,  		}  	} -	iwl_mvm_adjust_quota_for_noa(mvm, &cmd); -  	/* check that we have non-zero quota for all valid bindings */  	for (i = 0; i < MAX_BINDINGS; i++) {  		qdata = iwl_mvm_quota_cmd_get_quota(mvm, &cmd, i); diff --git a/sys/contrib/dev/iwlwifi/mvm/rs-fw.c b/sys/contrib/dev/iwlwifi/mvm/rs-fw.c index 74c2cbf60c1b..23a9f1a59ad3 100644 --- a/sys/contrib/dev/iwlwifi/mvm/rs-fw.c +++ b/sys/contrib/dev/iwlwifi/mvm/rs-fw.c @@ -1,7 +1,7 @@  // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause  /*   * Copyright (C) 2017 Intel Deutschland GmbH - * Copyright (C) 2018-2024 Intel Corporation + * Copyright (C) 2018-2025 Intel Corporation   */  #include "rs.h"  #include "fw-api.h" @@ -72,7 +72,7 @@ static u16 rs_fw_get_config_flags(struct iwl_mvm *mvm,  	u16 flags = 0;  	/* get STBC flags */ -	if (mvm->cfg->ht_params->stbc && +	if (mvm->cfg->ht_params.stbc &&  	    (num_of_ant(iwl_mvm_get_valid_tx_ant(mvm)) > 1)) {  		if (he_cap->has_he && he_cap->he_cap_elem.phy_cap_info[2] &  				      IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ) @@ -83,7 +83,7 @@ static u16 rs_fw_get_config_flags(struct iwl_mvm *mvm,  			flags |= IWL_TLC_MNG_CFG_FLAGS_STBC_MSK;  	} -	if (mvm->cfg->ht_params->ldpc && +	if (mvm->cfg->ht_params.ldpc &&  	    ((ht_cap->cap & IEEE80211_HT_CAP_LDPC_CODING) ||  	     (vht_ena && (vht_cap->cap & IEEE80211_VHT_CAP_RXLDPC))))  		flags |= IWL_TLC_MNG_CFG_FLAGS_LDPC_MSK; @@ -440,12 +440,6 @@ void iwl_mvm_tlc_update_notif(struct iwl_mvm *mvm,  	mvmsta = iwl_mvm_sta_from_mac80211(sta); -	if (!mvmsta) { -		IWL_ERR(mvm, "Invalid sta id (%d) in FW TLC notification\n", -			notif->sta_id); -		goto out; -	} -  	flags = le32_to_cpu(notif->flags);  	mvm_link_sta = rcu_dereference(mvmsta->link[link_sta->link_id]); @@ -460,22 +454,11 @@ void iwl_mvm_tlc_update_notif(struct iwl_mvm *mvm,  	if (flags & IWL_TLC_NOTIF_FLAG_RATE) {  		char pretty_rate[100]; -		if (iwl_fw_lookup_notif_ver(mvm->fw, DATA_PATH_GROUP, -					    TLC_MNG_UPDATE_NOTIF, 0) < 3) { -			rs_pretty_print_rate_v1(pretty_rate, -						sizeof(pretty_rate), -						le32_to_cpu(notif->rate)); -			IWL_DEBUG_RATE(mvm, -				       "Got rate in old format. Rate: %s. Converting.\n", -				       pretty_rate); -			lq_sta->last_rate_n_flags = -				iwl_new_rate_from_v1(le32_to_cpu(notif->rate)); -		} else { -			lq_sta->last_rate_n_flags = le32_to_cpu(notif->rate); -		} +		lq_sta->last_rate_n_flags = +			iwl_mvm_v3_rate_from_fw(notif->rate, mvm->fw_rates_ver);  		rs_pretty_print_rate(pretty_rate, sizeof(pretty_rate),  				     lq_sta->last_rate_n_flags); -		IWL_DEBUG_RATE(mvm, "new rate: %s\n", pretty_rate); +		IWL_DEBUG_RATE(mvm, "rate: %s\n", pretty_rate);  	}  	if (flags & IWL_TLC_NOTIF_FLAG_AMSDU && !mvm_link_sta->orig_amsdu_len) { @@ -618,11 +601,8 @@ void iwl_mvm_rs_fw_rate_init(struct iwl_mvm *mvm,  	int cmd_ver;  	int ret; -	/* Enable external EHT LTF only for GL device and if there's -	 * mutual support by AP and client -	 */ -	if (CSR_HW_REV_TYPE(mvm->trans->hw_rev) == IWL_CFG_MAC_TYPE_GL && -	    sband_eht_cap && +	/* Enable extra EHT LTF if there's mutual support by AP and client */ +	if (sband_eht_cap &&  	    sband_eht_cap->eht_cap_elem.phy_cap_info[5] &  		IEEE80211_EHT_PHY_CAP5_SUPP_EXTRA_EHT_LTF &&  	    link_sta->eht_cap.has_eht && diff --git a/sys/contrib/dev/iwlwifi/mvm/rx.c b/sys/contrib/dev/iwlwifi/mvm/rx.c index 0802887fb261..f6127c0b5344 100644 --- a/sys/contrib/dev/iwlwifi/mvm/rx.c +++ b/sys/contrib/dev/iwlwifi/mvm/rx.c @@ -1,10 +1,10 @@  // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause  /* - * Copyright (C) 2012-2014, 2018-2024 Intel Corporation + * Copyright (C) 2012-2014, 2018-2025 Intel Corporation   * Copyright (C) 2013-2015 Intel Mobile Communications GmbH   * Copyright (C) 2016-2017 Intel Deutschland GmbH   */ -#include <asm/unaligned.h> +#include <linux/unaligned.h>  #include <linux/etherdevice.h>  #include <linux/skbuff.h>  #include "iwl-trans.h" @@ -499,8 +499,6 @@ void iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct napi_struct *napi,  	if (!(rate_n_flags & RATE_MCS_CCK_MSK_V1) &&  	    rate_n_flags & RATE_MCS_SGI_MSK_V1)  		rx_status->enc_flags |= RX_ENC_FLAG_SHORT_GI; -	if (rate_n_flags & RATE_HT_MCS_GF_MSK) -		rx_status->enc_flags |= RX_ENC_FLAG_HT_GF;  	if (rate_n_flags & RATE_MCS_LDPC_MSK_V1)  		rx_status->enc_flags |= RX_ENC_FLAG_LDPC;  	if (rate_n_flags & RATE_MCS_HT_MSK_V1) { @@ -569,7 +567,8 @@ static void iwl_mvm_update_link_sig(struct ieee80211_vif *vif, int sig,  				    struct iwl_mvm_vif_link_info *link_info,  				    struct ieee80211_bss_conf *bss_conf)  { -	struct iwl_mvm *mvm = iwl_mvm_vif_from_mac80211(vif)->mvm; +	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); +	struct iwl_mvm *mvm = mvmvif->mvm;  	int thold = bss_conf->cqm_rssi_thold;  	int hyst = bss_conf->cqm_rssi_hyst;  	int last_event; @@ -634,6 +633,13 @@ static void iwl_mvm_update_link_sig(struct ieee80211_vif *vif, int sig,  	if (!vif->cfg.assoc || !ieee80211_vif_is_mld(vif))  		return; +	/* We're not in EMLSR and our signal is bad, try to switch link maybe */ +	if (sig < IWL_MVM_LOW_RSSI_MLO_SCAN_THRESH && !mvmvif->esr_active) { +		iwl_mvm_int_mlo_scan(mvm, vif); +		return; +	} + +	/* We are in EMLSR, check if we need to exit */  	exit_esr_thresh =  		iwl_mvm_get_esr_rssi_thresh(mvm,  					    &bss_conf->chanreq.oper, @@ -751,8 +757,8 @@ static void iwl_mvm_stats_energy_iter(void *_data,  	u8 *energy = _data;  	u32 sta_id = mvmsta->deflink.sta_id; -	if (WARN_ONCE(sta_id >= IWL_MVM_STATION_COUNT_MAX, "sta_id %d >= %d", -		      sta_id, IWL_MVM_STATION_COUNT_MAX)) +	if (WARN_ONCE(sta_id >= IWL_STATION_COUNT_MAX, "sta_id %d >= %d", +		      sta_id, IWL_STATION_COUNT_MAX))  		return;  	if (energy[sta_id]) @@ -794,6 +800,8 @@ static void iwl_mvm_handle_per_phy_stats(struct iwl_mvm *mvm,  			continue;  		mvm->phy_ctxts[i].channel_load_by_us =  			le32_to_cpu(per_phy[i].channel_load_by_us); +		mvm->phy_ctxts[i].channel_load_not_by_us = +			le32_to_cpu(per_phy[i].channel_load_not_by_us);  	}  } @@ -882,28 +890,28 @@ iwl_mvm_stat_iterator_all_links(struct iwl_mvm *mvm,  	u32 rx_bytes[MAC_INDEX_AUX] = {};  	int fw_link_id; -	for (fw_link_id = 0; fw_link_id < ARRAY_SIZE(mvm->link_id_to_link_conf); +	/* driver uses link ID == MAC ID */ +	for (fw_link_id = 0; fw_link_id < ARRAY_SIZE(mvm->vif_id_to_mac);  	     fw_link_id++) {  		struct iwl_stats_ntfy_per_link *link_stats; -		struct ieee80211_bss_conf *bss_conf; -		struct iwl_mvm_vif *mvmvif;  		struct iwl_mvm_vif_link_info *link_info; +		struct iwl_mvm_vif *mvmvif; +		struct ieee80211_vif *vif;  		int link_id;  		int sig; -		bss_conf = iwl_mvm_rcu_fw_link_id_to_link_conf(mvm, fw_link_id, -							       false); -		if (!bss_conf) +		vif = iwl_mvm_rcu_dereference_vif_id(mvm, fw_link_id, false); +		if (!vif)  			continue; -		if (bss_conf->vif->type != NL80211_IFTYPE_STATION) +		if (vif->type != NL80211_IFTYPE_STATION)  			continue; -		link_id = bss_conf->link_id; +		link_id = vif->bss_conf.link_id;  		if (link_id >= ARRAY_SIZE(mvmvif->link))  			continue; -		mvmvif = iwl_mvm_vif_from_mac80211(bss_conf->vif); +		mvmvif = iwl_mvm_vif_from_mac80211(vif);  		link_info = mvmvif->link[link_id];  		if (!link_info)  			continue; @@ -921,8 +929,7 @@ iwl_mvm_stat_iterator_all_links(struct iwl_mvm *mvm,  		if (link_info->phy_ctxt &&  		    link_info->phy_ctxt->channel->band == NL80211_BAND_2GHZ) -			iwl_mvm_bt_coex_update_link_esr(mvm, bss_conf->vif, -							link_id); +			iwl_mvm_bt_coex_update_link_esr(mvm, vif, link_id);  		/* make sure that beacon statistics don't go backwards with TCM  		 * request to clear statistics @@ -932,8 +939,7 @@ iwl_mvm_stat_iterator_all_links(struct iwl_mvm *mvm,  				mvmvif->link[link_id]->beacon_stats.num_beacons;  		sig = -le32_to_cpu(link_stats->beacon_filter_average_energy); -		iwl_mvm_update_link_sig(bss_conf->vif, sig, link_info, -					bss_conf); +		iwl_mvm_update_link_sig(vif, sig, link_info, &vif->bss_conf);  		if (WARN_ONCE(mvmvif->id >= MAC_INDEX_AUX,  			      "invalid mvmvif id: %d", mvmvif->id)) @@ -967,6 +973,9 @@ iwl_mvm_stat_iterator_all_links(struct iwl_mvm *mvm,  #define SEC_LINK_MIN_TX 3000  #define SEC_LINK_MIN_RX 400 +/* Accept a ~20% short window to avoid issues due to jitter */ +#define IWL_MVM_TPT_MIN_COUNT_WINDOW (IWL_MVM_TPT_COUNT_WINDOW_SEC * HZ * 4 / 5) +  static void iwl_mvm_update_esr_mode_tpt(struct iwl_mvm *mvm)  {  	struct ieee80211_vif *bss_vif = iwl_mvm_get_bss_vif(mvm); @@ -976,6 +985,7 @@ static void iwl_mvm_update_esr_mode_tpt(struct iwl_mvm *mvm)  	unsigned long sec_link_tx = 0, sec_link_rx = 0;  	u8 sec_link_tx_perc, sec_link_rx_perc;  	u8 sec_link; +	bool skip = false;  	lockdep_assert_held(&mvm->mutex); @@ -1000,11 +1010,11 @@ static void iwl_mvm_update_esr_mode_tpt(struct iwl_mvm *mvm)  	sec_link = mvmvif->link[sec_link]->fw_link_id;  	/* Sum up RX and TX MPDUs from the different queues/links */ -	for (int q = 0; q < mvm->trans->num_rx_queues; q++) { +	for (int q = 0; q < mvm->trans->info.num_rxqs; q++) {  		spin_lock_bh(&mvmsta->mpdu_counters[q].lock);  		/* The link IDs that doesn't exist will contain 0 */ -		for (int link = 0; link < IWL_MVM_FW_MAX_LINK_ID; link++) { +		for (int link = 0; link < IWL_FW_MAX_LINK_ID; link++) {  			total_tx += mvmsta->mpdu_counters[q].per_link[link].tx;  			total_rx += mvmsta->mpdu_counters[q].per_link[link].rx;  		} @@ -1015,15 +1025,27 @@ static void iwl_mvm_update_esr_mode_tpt(struct iwl_mvm *mvm)  		/*  		 * In EMLSR we have statistics every 5 seconds, so we can reset  		 * the counters upon every statistics notification. +		 * The FW sends the notification regularly, but it will be +		 * misaligned at the start. Skipping the measurement if it is +		 * short will synchronize us.  		 */ +		if (jiffies - mvmsta->mpdu_counters[q].window_start < +		    IWL_MVM_TPT_MIN_COUNT_WINDOW) +			skip = true; +		mvmsta->mpdu_counters[q].window_start = jiffies;  		memset(mvmsta->mpdu_counters[q].per_link, 0,  		       sizeof(mvmsta->mpdu_counters[q].per_link));  		spin_unlock_bh(&mvmsta->mpdu_counters[q].lock);  	} -	IWL_DEBUG_STATS(mvm, "total Tx MPDUs: %ld. total Rx MPDUs: %ld\n", -			total_tx, total_rx); +	if (skip) { +		IWL_DEBUG_INFO(mvm, "MPDU statistics window was short\n"); +		return; +	} + +	IWL_DEBUG_INFO(mvm, "total Tx MPDUs: %ld. total Rx MPDUs: %ld\n", +		       total_tx, total_rx);  	/* If we don't have enough MPDUs - exit EMLSR */  	if (total_tx < IWL_MVM_ENTER_ESR_TPT_THRESH && @@ -1033,6 +1055,9 @@ static void iwl_mvm_update_esr_mode_tpt(struct iwl_mvm *mvm)  		return;  	} +	IWL_DEBUG_INFO(mvm, "Secondary Link %d: Tx MPDUs: %ld. Rx MPDUs: %ld\n", +		       sec_link, sec_link_tx, sec_link_rx); +  	/* Calculate the percentage of the secondary link TX/RX */  	sec_link_tx_perc = total_tx ? sec_link_tx * 100 / total_tx : 0;  	sec_link_rx_perc = total_rx ? sec_link_rx * 100 / total_rx : 0; @@ -1052,7 +1077,7 @@ static void iwl_mvm_update_esr_mode_tpt(struct iwl_mvm *mvm)  void iwl_mvm_handle_rx_system_oper_stats(struct iwl_mvm *mvm,  					 struct iwl_rx_cmd_buffer *rxb)  { -	u8 average_energy[IWL_MVM_STATION_COUNT_MAX]; +	u8 average_energy[IWL_STATION_COUNT_MAX];  	struct iwl_rx_packet *pkt = rxb_addr(rxb);  	struct iwl_system_statistics_notif_oper *stats;  	int i; @@ -1111,7 +1136,7 @@ static void  iwl_mvm_handle_rx_statistics_tlv(struct iwl_mvm *mvm,  				 struct iwl_rx_packet *pkt)  { -	u8 average_energy[IWL_MVM_STATION_COUNT_MAX]; +	u8 average_energy[IWL_STATION_COUNT_MAX];  	__le32 air_time[MAC_INDEX_AUX];  	__le32 rx_bytes[MAC_INDEX_AUX];  	__le32 flags = 0; diff --git a/sys/contrib/dev/iwlwifi/mvm/rxmq.c b/sys/contrib/dev/iwlwifi/mvm/rxmq.c index cb2f6b347303..71210b8b9edd 100644 --- a/sys/contrib/dev/iwlwifi/mvm/rxmq.c +++ b/sys/contrib/dev/iwlwifi/mvm/rxmq.c @@ -1,6 +1,6 @@  // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause  /* - * Copyright (C) 2012-2014, 2018-2024 Intel Corporation + * Copyright (C) 2012-2014, 2018-2025 Intel Corporation   * Copyright (C) 2013-2015 Intel Mobile Communications GmbH   * Copyright (C) 2015-2017 Intel Deutschland GmbH   */ @@ -174,7 +174,7 @@ static int iwl_mvm_create_skb(struct iwl_mvm *mvm, struct sk_buff *skb,  			      shdr->type != htons(ETH_P_PAE) &&  			      shdr->type != htons(ETH_P_TDLS))))  			skb->ip_summed = CHECKSUM_NONE; -		else if (mvm->trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_BZ) +		else if (mvm->trans->mac_cfg->device_family < IWL_DEVICE_FAMILY_BZ)  			/* mac80211 assumes full CSUM including SNAP header */  			skb_postpush_rcsum(skb, shdr, sizeof(*shdr));  	} @@ -249,13 +249,62 @@ static void iwl_mvm_pass_packet_to_mac80211(struct iwl_mvm *mvm,  	ieee80211_rx_napi(mvm->hw, sta, skb, napi);  } +static bool iwl_mvm_used_average_energy(struct iwl_mvm *mvm, +					struct iwl_rx_mpdu_desc *desc, +					struct ieee80211_hdr *hdr, +					struct ieee80211_rx_status *rx_status) +{ +	struct iwl_mvm_vif *mvm_vif; +	struct ieee80211_vif *vif; +	u32 id; + +	if (unlikely(!hdr || !desc)) +		return false; + +	if (likely(!ieee80211_is_beacon(hdr->frame_control))) +		return false; + +	/* for the link conf lookup */ +	guard(rcu)(); + +	/* MAC or link ID depending on FW, but driver has them equal */ +	id = u8_get_bits(desc->mac_phy_band, +			 IWL_RX_MPDU_MAC_PHY_BAND_MAC_MASK); + +	/* >= means AUX MAC/link ID, no energy correction needed then */ +	if (id >= ARRAY_SIZE(mvm->vif_id_to_mac)) +		return false; + +	vif = iwl_mvm_rcu_dereference_vif_id(mvm, id, true); +	if (!vif) +		return false; + +	mvm_vif = iwl_mvm_vif_from_mac80211(vif); + +	/* +	 * If we know the MAC by MAC or link ID then the frame was +	 * received for the link, so by filtering it means it was +	 * from the AP the link is connected to. +	 */ + +	/* skip also in case we don't have it (yet) */ +	if (!mvm_vif->deflink.average_beacon_energy) +		return false; + +	IWL_DEBUG_STATS(mvm, "energy override by average %d\n", +			mvm_vif->deflink.average_beacon_energy); +	rx_status->signal = -mvm_vif->deflink.average_beacon_energy; +	return true; +} +  static void iwl_mvm_get_signal_strength(struct iwl_mvm *mvm, +					struct iwl_rx_mpdu_desc *desc, +					struct ieee80211_hdr *hdr,  					struct ieee80211_rx_status *rx_status,  					u32 rate_n_flags, int energy_a,  					int energy_b)  {  	int max_energy; -	u32 rate_flags = rate_n_flags;  	energy_a = energy_a ? -energy_a : S8_MIN;  	energy_b = energy_b ? -energy_b : S8_MIN; @@ -264,9 +313,11 @@ static void iwl_mvm_get_signal_strength(struct iwl_mvm *mvm,  	IWL_DEBUG_STATS(mvm, "energy In A %d B %d, and max %d\n",  			energy_a, energy_b, max_energy); +	if (iwl_mvm_used_average_energy(mvm, desc, hdr, rx_status)) +		return; +  	rx_status->signal = max_energy; -	rx_status->chains = -		(rate_flags & RATE_MCS_ANT_AB_MSK) >> RATE_MCS_ANT_POS; +	rx_status->chains = u32_get_bits(rate_n_flags, RATE_MCS_ANT_AB_MSK);  	rx_status->chain_signal[0] = energy_a;  	rx_status->chain_signal[1] = energy_b;  } @@ -418,7 +469,7 @@ static int iwl_mvm_rx_crypto(struct iwl_mvm *mvm, struct ieee80211_sta *sta,  		    !(status & IWL_RX_MPDU_RES_STATUS_TTAK_OK))  			return 0; -		if (mvm->trans->trans_cfg->gen2 && +		if (mvm->trans->mac_cfg->gen2 &&  		    !(status & RX_MPDU_RES_STATUS_MIC_OK))  			stats->flag |= RX_FLAG_MMIC_ERROR; @@ -435,7 +486,7 @@ static int iwl_mvm_rx_crypto(struct iwl_mvm *mvm, struct ieee80211_sta *sta,  		if (pkt_flags & FH_RSCSR_RADA_EN) {  			stats->flag |= RX_FLAG_ICV_STRIPPED; -			if (mvm->trans->trans_cfg->gen2) +			if (mvm->trans->mac_cfg->gen2)  				stats->flag |= RX_FLAG_MMIC_STRIPPED;  		} @@ -475,7 +526,7 @@ static void iwl_mvm_rx_csum(struct iwl_mvm *mvm,  {  	struct iwl_rx_mpdu_desc *desc = (void *)pkt->data; -	if (mvm->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) { +	if (mvm->trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) {  		if (pkt->len_n_flags & cpu_to_le32(FH_RSCSR_RPA_EN)) {  			u16 hwsum = be16_to_cpu(desc->v3.raw_xsum); @@ -649,15 +700,21 @@ static void iwl_mvm_release_frames_from_notif(struct iwl_mvm *mvm,  	IWL_DEBUG_HT(mvm, "Frame release notification for BAID %u, NSSN %d\n",  		     baid, nssn); -	if (WARN_ON_ONCE(baid == IWL_RX_REORDER_DATA_INVALID_BAID || -			 baid >= ARRAY_SIZE(mvm->baid_map))) +	if (IWL_FW_CHECK(mvm, +			 baid == IWL_RX_REORDER_DATA_INVALID_BAID || +			 baid >= ARRAY_SIZE(mvm->baid_map), +			 "invalid BAID from FW: %d\n", baid))  		return;  	rcu_read_lock();  	ba_data = rcu_dereference(mvm->baid_map[baid]); -	if (WARN(!ba_data, "BAID %d not found in map\n", baid)) +	if (!ba_data) { +		IWL_DEBUG_RX(mvm, +			     "Got valid BAID %d but not allocated, invalid frame release!\n", +			     baid);  		goto out; +	}  	/* pick any STA ID to find the pointer */  	sta_id = ffs(ba_data->sta_mask) - 1; @@ -746,8 +803,6 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm,  #elif defined(__FreeBSD__)  	u8 tid;  #endif -	u8 sub_frame_idx = desc->amsdu_info & -			   IWL_RX_MPDU_AMSDU_SUBFRAME_IDX_MASK;  	struct iwl_mvm_reorder_buf_entry *entries;  	u32 sta_mask;  	int index; @@ -757,7 +812,7 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm,  	baid = (reorder & IWL_RX_MPDU_REORDER_BAID_MASK) >>  		IWL_RX_MPDU_REORDER_BAID_SHIFT; -	if (mvm->trans->trans_cfg->device_family == IWL_DEVICE_FAMILY_9000) +	if (mvm->trans->mac_cfg->device_family == IWL_DEVICE_FAMILY_9000)  		return false;  	/* @@ -795,9 +850,7 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm,  #if defined(__FreeBSD__)  	tid = ieee80211_get_tid(hdr);  #endif -	rcu_read_lock();  	sta_mask = iwl_mvm_sta_fw_id_mask(mvm, sta, -1); -	rcu_read_unlock();  	if (IWL_FW_CHECK(mvm,  			 tid != baid_data->tid || @@ -836,7 +889,7 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm,  	if (!buffer->num_stored && ieee80211_sn_less(sn, nssn)) {  		if (!amsdu || last_subframe)  			buffer->head_sn = nssn; -		/* No need to update AMSDU last SN - we are moving the head */ +  		spin_unlock_bh(&buffer->lock);  		return false;  	} @@ -853,7 +906,6 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm,  		if (!amsdu || last_subframe)  			buffer->head_sn = ieee80211_sn_inc(buffer->head_sn); -		/* No need to update AMSDU last SN - we are moving the head */  		spin_unlock_bh(&buffer->lock);  		return false;  	} @@ -863,11 +915,6 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm,  	__skb_queue_tail(&entries[index].frames, skb);  	buffer->num_stored++; -	if (amsdu) { -		buffer->last_amsdu = sn; -		buffer->last_sub_index = sub_frame_idx; -	} -  	/*  	 * We cannot trust NSSN for AMSDU sub-frames that are not the last.  	 * The reason is that NSSN advances on the first sub-frame, and may @@ -878,10 +925,15 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm,  	 * already ahead and it will be dropped.  	 * If the last sub-frame is not on this queue - we will get frame  	 * release notification with up to date NSSN. +	 * If this is the first frame that is stored in the buffer, the head_sn +	 * may be outdated. Update it based on the last NSSN to make sure it +	 * will be released when the frame release notification arrives.  	 */  	if (!amsdu || last_subframe)  		iwl_mvm_release_frames(mvm, sta, napi, baid_data,  				       buffer, nssn); +	else if (buffer->num_stored == 1) +		buffer->head_sn = nssn;  	spin_unlock_bh(&buffer->lock);  	return true; @@ -1019,7 +1071,7 @@ iwl_mvm_decode_he_phy_ru_alloc(struct iwl_mvm_rx_phy_data *phy_data,  	 */  	u8 ru = le32_get_bits(phy_data->d1, IWL_RX_PHY_DATA1_HE_RU_ALLOC_MASK);  	u32 rate_n_flags = phy_data->rate_n_flags; -	u32 he_type = rate_n_flags & RATE_MCS_HE_TYPE_MSK_V1; +	u32 he_type = rate_n_flags & RATE_MCS_HE_TYPE_MSK;  	u8 offs = 0;  	rx_status->bw = RATE_INFO_BW_HE_RU; @@ -1074,13 +1126,13 @@ iwl_mvm_decode_he_phy_ru_alloc(struct iwl_mvm_rx_phy_data *phy_data,  	if (he_mu)  		he_mu->flags2 |= -			le16_encode_bits(FIELD_GET(RATE_MCS_CHAN_WIDTH_MSK_V1, +			le16_encode_bits(FIELD_GET(RATE_MCS_CHAN_WIDTH_MSK,  						   rate_n_flags),  					 IEEE80211_RADIOTAP_HE_MU_FLAGS2_BW_FROM_SIG_A_BW); -	else if (he_type == RATE_MCS_HE_TYPE_TRIG_V1) +	else if (he_type == RATE_MCS_HE_TYPE_TRIG)  		he->data6 |=  			cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA6_TB_PPDU_BW_KNOWN) | -			le16_encode_bits(FIELD_GET(RATE_MCS_CHAN_WIDTH_MSK_V1, +			le16_encode_bits(FIELD_GET(RATE_MCS_CHAN_WIDTH_MSK,  						   rate_n_flags),  					 IEEE80211_RADIOTAP_HE_DATA6_TB_PPDU_BW);  } @@ -1930,8 +1982,11 @@ static void iwl_mvm_rx_get_sta_block_tx(void *data, struct ieee80211_sta *sta)  /*   * Note: requires also rx_status->band to be prefilled, as well   * as phy_data (apart from phy_data->info_type) + * Note: desc/hdr may be NULL   */  static void iwl_mvm_rx_fill_status(struct iwl_mvm *mvm, +				   struct iwl_rx_mpdu_desc *desc, +				   struct ieee80211_hdr *hdr,  				   struct sk_buff *skb,  				   struct iwl_mvm_rx_phy_data *phy_data,  				   int queue) @@ -1968,7 +2023,7 @@ static void iwl_mvm_rx_fill_status(struct iwl_mvm *mvm,  	}  	/* must be before L-SIG data */ -	if (format == RATE_MCS_HE_MSK) +	if (format == RATE_MCS_MOD_TYPE_HE)  		iwl_mvm_rx_he(mvm, skb, phy_data, queue);  	iwl_mvm_decode_lsig(skb, phy_data); @@ -1986,49 +2041,49 @@ static void iwl_mvm_rx_fill_status(struct iwl_mvm *mvm,  	rx_status->freq = ieee80211_channel_to_frequency(phy_data->channel,  							 rx_status->band); -	iwl_mvm_get_signal_strength(mvm, rx_status, rate_n_flags, +	iwl_mvm_get_signal_strength(mvm, desc, hdr, rx_status, rate_n_flags,  				    phy_data->energy_a, phy_data->energy_b);  	/* using TLV format and must be after all fixed len fields */ -	if (format == RATE_MCS_EHT_MSK) +	if (format == RATE_MCS_MOD_TYPE_EHT)  		iwl_mvm_rx_eht(mvm, skb, phy_data, queue);  	if (unlikely(mvm->monitor_on))  		iwl_mvm_add_rtap_sniffer_config(mvm, skb); -	is_sgi = format == RATE_MCS_HE_MSK ? +	is_sgi = format == RATE_MCS_MOD_TYPE_HE ?  		iwl_he_is_sgi(rate_n_flags) :  		rate_n_flags & RATE_MCS_SGI_MSK; -	if (!(format == RATE_MCS_CCK_MSK) && is_sgi) +	if (!(format == RATE_MCS_MOD_TYPE_CCK) && is_sgi)  		rx_status->enc_flags |= RX_ENC_FLAG_SHORT_GI;  	if (rate_n_flags & RATE_MCS_LDPC_MSK)  		rx_status->enc_flags |= RX_ENC_FLAG_LDPC;  	switch (format) { -	case RATE_MCS_VHT_MSK: +	case RATE_MCS_MOD_TYPE_VHT:  		rx_status->encoding = RX_ENC_VHT;  		break; -	case RATE_MCS_HE_MSK: +	case RATE_MCS_MOD_TYPE_HE:  		rx_status->encoding = RX_ENC_HE;  		rx_status->he_dcm =  			!!(rate_n_flags & RATE_HE_DUAL_CARRIER_MODE_MSK);  		break; -	case RATE_MCS_EHT_MSK: +	case RATE_MCS_MOD_TYPE_EHT:  		rx_status->encoding = RX_ENC_EHT;  		break;  	}  	switch (format) { -	case RATE_MCS_HT_MSK: +	case RATE_MCS_MOD_TYPE_HT:  		rx_status->encoding = RX_ENC_HT;  		rx_status->rate_idx = RATE_HT_MCS_INDEX(rate_n_flags);  		rx_status->enc_flags |= stbc << RX_ENC_FLAG_STBC_SHIFT;  		break; -	case RATE_MCS_VHT_MSK: -	case RATE_MCS_HE_MSK: -	case RATE_MCS_EHT_MSK: +	case RATE_MCS_MOD_TYPE_VHT: +	case RATE_MCS_MOD_TYPE_HE: +	case RATE_MCS_MOD_TYPE_EHT:  		rx_status->nss =  			u32_get_bits(rate_n_flags, RATE_MCS_NSS_MSK) + 1;  		rx_status->rate_idx = rate_n_flags & RATE_MCS_CODE_MSK; @@ -2072,7 +2127,7 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,  	if (unlikely(test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)))  		return; -	if (mvm->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) +	if (mvm->trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_AX210)  		desc_size = sizeof(*desc);  	else  		desc_size = IWL_RX_DESC_SIZE_V1; @@ -2082,8 +2137,10 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,  		return;  	} -	if (mvm->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) { -		phy_data.rate_n_flags = le32_to_cpu(desc->v3.rate_n_flags); +	if (mvm->trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) { +		phy_data.rate_n_flags = +			iwl_mvm_v3_rate_from_fw(desc->v3.rate_n_flags, +						mvm->fw_rates_ver);  		phy_data.channel = desc->v3.channel;  		phy_data.gp2_on_air_rise = le32_to_cpu(desc->v3.gp2_on_air_rise);  		phy_data.energy_a = desc->v3.energy_a; @@ -2096,7 +2153,9 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,  		phy_data.eht_d4 = desc->phy_eht_data4;  		phy_data.d5 = desc->v3.phy_data5;  	} else { -		phy_data.rate_n_flags = le32_to_cpu(desc->v1.rate_n_flags); +		phy_data.rate_n_flags = +			iwl_mvm_v3_rate_from_fw(desc->v1.rate_n_flags, +						mvm->fw_rates_ver);  		phy_data.channel = desc->v1.channel;  		phy_data.gp2_on_air_rise = le32_to_cpu(desc->v1.gp2_on_air_rise);  		phy_data.energy_a = desc->v1.energy_a; @@ -2108,13 +2167,6 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,  		phy_data.d3 = desc->v1.phy_data3;  	} -	if (iwl_fw_lookup_notif_ver(mvm->fw, LEGACY_GROUP, -				    REPLY_RX_MPDU_CMD, 0) < 4) { -		phy_data.rate_n_flags = iwl_new_rate_from_v1(phy_data.rate_n_flags); -		IWL_DEBUG_DROP(mvm, "Got old format rate, converting. New rate: 0x%x\n", -			       phy_data.rate_n_flags); -	} -  	format = phy_data.rate_n_flags & RATE_MCS_MOD_TYPE_MSK;  	len = le16_to_cpu(desc->mpdu_len); @@ -2162,14 +2214,14 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,  	}  	/* set the preamble flag if appropriate */ -	if (format == RATE_MCS_CCK_MSK && +	if (format == RATE_MCS_MOD_TYPE_CCK &&  	    phy_data.phy_info & IWL_RX_MPDU_PHY_SHORT_PREAMBLE)  		rx_status->enc_flags |= RX_ENC_FLAG_SHORTPRE;  	if (likely(!(phy_data.phy_info & IWL_RX_MPDU_PHY_TSF_OVERLOAD))) {  		u64 tsf_on_air_rise; -		if (mvm->trans->trans_cfg->device_family >= +		if (mvm->trans->mac_cfg->device_family >=  		    IWL_DEVICE_FAMILY_AX210)  			tsf_on_air_rise = le64_to_cpu(desc->v3.tsf_on_air_rise);  		else @@ -2181,7 +2233,8 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,  	}  	if (iwl_mvm_is_band_in_rx_supported(mvm)) { -		u8 band = BAND_IN_RX_STATUS(desc->mac_phy_idx); +		u8 band = u8_get_bits(desc->mac_phy_band, +				      IWL_RX_MPDU_MAC_PHY_BAND_BAND_MASK);  		rx_status->band = iwl_mvm_nl80211_band_from_phy(band);  	} else { @@ -2241,7 +2294,7 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,  		goto out;  	} -	iwl_mvm_rx_fill_status(mvm, skb, &phy_data, queue); +	iwl_mvm_rx_fill_status(mvm, desc, hdr, skb, &phy_data, queue);  	if (sta) {  		struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); @@ -2331,7 +2384,7 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,  			*qc &= ~IEEE80211_QOS_CTL_A_MSDU_PRESENT; -			if (mvm->trans->trans_cfg->device_family == +			if (mvm->trans->mac_cfg->device_family ==  			    IWL_DEVICE_FAMILY_9000) {  				iwl_mvm_flip_address(hdr->addr3); @@ -2377,7 +2430,7 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,  	if (!iwl_mvm_reorder(mvm, napi, queue, sta, skb, desc) &&  	    likely(!iwl_mvm_time_sync_frame(mvm, skb, hdr->addr2)) &&  	    likely(!iwl_mvm_mei_filter_scan(mvm, skb))) { -		if (mvm->trans->trans_cfg->device_family == IWL_DEVICE_FAMILY_9000 && +		if (mvm->trans->mac_cfg->device_family == IWL_DEVICE_FAMILY_9000 &&  		    (desc->mac_flags2 & IWL_RX_MPDU_MFLG2_AMSDU) &&  		    !(desc->amsdu_info & IWL_RX_MPDU_AMSDU_LAST_SUBFRAME))  			rx_status->flag |= RX_FLAG_AMSDU_MORE; @@ -2411,7 +2464,6 @@ void iwl_mvm_rx_monitor_no_data(struct iwl_mvm *mvm, struct napi_struct *napi,  	phy_data.d1 = desc->phy_info[1];  	phy_data.phy_info = IWL_RX_MPDU_PHY_TSF_OVERLOAD;  	phy_data.gp2_on_air_rise = le32_to_cpu(desc->on_air_rise_time); -	phy_data.rate_n_flags = le32_to_cpu(desc->rate);  	phy_data.energy_a = u32_get_bits(rssi, RX_NO_DATA_CHAIN_A_MSK);  	phy_data.energy_b = u32_get_bits(rssi, RX_NO_DATA_CHAIN_B_MSK);  	phy_data.channel = u32_get_bits(rssi, RX_NO_DATA_CHANNEL_MSK); @@ -2419,14 +2471,8 @@ void iwl_mvm_rx_monitor_no_data(struct iwl_mvm *mvm, struct napi_struct *napi,  	phy_data.rx_vec[0] = desc->rx_vec[0];  	phy_data.rx_vec[1] = desc->rx_vec[1]; -	if (iwl_fw_lookup_notif_ver(mvm->fw, DATA_PATH_GROUP, -				    RX_NO_DATA_NOTIF, 0) < 2) { -		IWL_DEBUG_DROP(mvm, "Got an old rate format. Old rate: 0x%x\n", -			       phy_data.rate_n_flags); -		phy_data.rate_n_flags = iwl_new_rate_from_v1(phy_data.rate_n_flags); -		IWL_DEBUG_DROP(mvm, " Rate after conversion to the new format: 0x%x\n", -			       phy_data.rate_n_flags); -	} +	phy_data.rate_n_flags = iwl_mvm_v3_rate_from_fw(desc->rate, +							mvm->fw_rates_ver);  	format = phy_data.rate_n_flags & RATE_MCS_MOD_TYPE_MSK; @@ -2439,7 +2485,7 @@ void iwl_mvm_rx_monitor_no_data(struct iwl_mvm *mvm, struct napi_struct *napi,  		phy_data.rx_vec[2] = desc->rx_vec[2];  		phy_data.rx_vec[3] = desc->rx_vec[3];  	} else { -		if (format == RATE_MCS_EHT_MSK) +		if (format == RATE_MCS_MOD_TYPE_EHT)  			/* no support for EHT before version 3 API */  			return;  	} @@ -2482,7 +2528,7 @@ void iwl_mvm_rx_monitor_no_data(struct iwl_mvm *mvm, struct napi_struct *napi,  	rx_status->band = phy_data.channel > 14 ? NL80211_BAND_5GHZ :  		NL80211_BAND_2GHZ; -	iwl_mvm_rx_fill_status(mvm, skb, &phy_data, queue); +	iwl_mvm_rx_fill_status(mvm, NULL, NULL, skb, &phy_data, queue);  	/* no more radio tap info should be put after this point.  	 * @@ -2500,17 +2546,17 @@ void iwl_mvm_rx_monitor_no_data(struct iwl_mvm *mvm, struct napi_struct *napi,  	 * may be up to 8 spatial streams.  	 */  	switch (format) { -	case RATE_MCS_VHT_MSK: +	case RATE_MCS_MOD_TYPE_VHT:  		rx_status->nss =  			le32_get_bits(desc->rx_vec[0],  				      RX_NO_DATA_RX_VEC0_VHT_NSTS_MSK) + 1;  		break; -	case RATE_MCS_HE_MSK: +	case RATE_MCS_MOD_TYPE_HE:  		rx_status->nss =  			le32_get_bits(desc->rx_vec[0],  				      RX_NO_DATA_RX_VEC0_HE_NSTS_MSK) + 1;  		break; -	case RATE_MCS_EHT_MSK: +	case RATE_MCS_MOD_TYPE_EHT:  		rx_status->nss =  			le32_get_bits(desc->rx_vec[2],  				      RX_NO_DATA_RX_VEC2_EHT_NSTS_MSK) + 1; @@ -2540,19 +2586,24 @@ void iwl_mvm_rx_bar_frame_release(struct iwl_mvm *mvm, struct napi_struct *napi,  {  	struct iwl_rx_packet *pkt = rxb_addr(rxb);  	struct iwl_bar_frame_release *release = (void *)pkt->data; -	unsigned int baid = le32_get_bits(release->ba_info, -					  IWL_BAR_FRAME_RELEASE_BAID_MASK); -	unsigned int nssn = le32_get_bits(release->ba_info, -					  IWL_BAR_FRAME_RELEASE_NSSN_MASK); -	unsigned int sta_id = le32_get_bits(release->sta_tid, -					    IWL_BAR_FRAME_RELEASE_STA_MASK); -	unsigned int tid = le32_get_bits(release->sta_tid, -					 IWL_BAR_FRAME_RELEASE_TID_MASK);  	struct iwl_mvm_baid_data *baid_data; +	u32 pkt_len = iwl_rx_packet_payload_len(pkt); +	unsigned int baid, nssn, sta_id, tid; -	if (unlikely(iwl_rx_packet_payload_len(pkt) < sizeof(*release))) +	if (IWL_FW_CHECK(mvm, pkt_len < sizeof(*release), +			 "Unexpected frame release notif size %d (expected %zu)\n", +			 pkt_len, sizeof(*release)))  		return; +	baid = le32_get_bits(release->ba_info, +			     IWL_BAR_FRAME_RELEASE_BAID_MASK); +	nssn = le32_get_bits(release->ba_info, +			     IWL_BAR_FRAME_RELEASE_NSSN_MASK); +	sta_id = le32_get_bits(release->sta_tid, +			       IWL_BAR_FRAME_RELEASE_STA_MASK); +	tid = le32_get_bits(release->sta_tid, +			    IWL_BAR_FRAME_RELEASE_TID_MASK); +  	if (WARN_ON_ONCE(baid == IWL_RX_REORDER_DATA_INVALID_BAID ||  			 baid >= ARRAY_SIZE(mvm->baid_map)))  		return; @@ -2566,7 +2617,7 @@ void iwl_mvm_rx_bar_frame_release(struct iwl_mvm *mvm, struct napi_struct *napi,  		goto out;  	} -	if (WARN(tid != baid_data->tid || sta_id > IWL_MVM_STATION_COUNT_MAX || +	if (WARN(tid != baid_data->tid || sta_id > IWL_STATION_COUNT_MAX ||  		 !(baid_data->sta_mask & BIT(sta_id)),  		 "baid 0x%x is mapped to sta_mask:0x%x tid:%d, but BAR release received for sta:%d tid:%d\n",  		 baid, baid_data->sta_mask, baid_data->tid, sta_id, @@ -2580,3 +2631,28 @@ void iwl_mvm_rx_bar_frame_release(struct iwl_mvm *mvm, struct napi_struct *napi,  out:  	rcu_read_unlock();  } + +void iwl_mvm_rx_beacon_filter_notif(struct iwl_mvm *mvm, +				    struct iwl_rx_cmd_buffer *rxb) +{ +	struct iwl_rx_packet *pkt = rxb_addr(rxb); +	/* MAC or link ID in v1/v2, but driver has the IDs equal */ +	struct iwl_beacon_filter_notif *notif = (void *)pkt->data; +	u32 id = le32_to_cpu(notif->link_id); +	struct iwl_mvm_vif *mvm_vif; +	struct ieee80211_vif *vif; + +	/* >= means AUX MAC/link ID, no energy correction needed then */ +	if (IWL_FW_CHECK(mvm, id >= ARRAY_SIZE(mvm->vif_id_to_mac), +			 "invalid link ID %d\n", id)) +		return; + +	vif = iwl_mvm_rcu_dereference_vif_id(mvm, id, false); +	if (!vif) +		return; + +	mvm_vif = iwl_mvm_vif_from_mac80211(vif); + +	mvm_vif->deflink.average_beacon_energy = +		le32_to_cpu(notif->average_energy); +} diff --git a/sys/contrib/dev/iwlwifi/mvm/scan.c b/sys/contrib/dev/iwlwifi/mvm/scan.c index 0b705e497343..9ce1ce0dab34 100644 --- a/sys/contrib/dev/iwlwifi/mvm/scan.c +++ b/sys/contrib/dev/iwlwifi/mvm/scan.c @@ -1,6 +1,6 @@  // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause  /* - * Copyright (C) 2012-2014, 2018-2024 Intel Corporation + * Copyright (C) 2012-2014, 2018-2025 Intel Corporation   * Copyright (C) 2013-2015 Intel Mobile Communications GmbH   * Copyright (C) 2016-2017 Intel Deutschland GmbH   */ @@ -11,6 +11,7 @@  #include "mvm.h"  #include "fw/api/scan.h"  #include "iwl-io.h" +#include "iwl-utils.h"  #define IWL_DENSE_EBS_SCAN_RATIO 5  #define IWL_SPARSE_EBS_SCAN_RATIO 1 @@ -462,11 +463,7 @@ static int iwl_ssid_exist(u8 *ssid, u8 ssid_len, struct iwl_ssid_ie *ssid_list)  		if (!ssid_list[i].len)  			break;  		if (ssid_list[i].len == ssid_len && -#if defined(__linux__) -		    !memcmp(ssid_list->ssid, ssid, ssid_len)) -#elif defined(__FreeBSD__)  		    !memcmp(ssid_list[i].ssid, ssid, ssid_len)) -#endif  			return i;  	}  	return -1; @@ -839,7 +836,7 @@ static inline bool iwl_mvm_scan_fits(struct iwl_mvm *mvm, int n_ssids,  				     int n_channels)  {  	return ((n_ssids <= PROBE_OPTION_MAX) && -		(n_channels <= mvm->fw->ucode_capa.n_scan_channels) & +		(n_channels <= mvm->fw->ucode_capa.n_scan_channels) &&  		(ies->common_ie_len +  		 ies->len[NL80211_BAND_2GHZ] + ies->len[NL80211_BAND_5GHZ] +  		 ies->len[NL80211_BAND_6GHZ] <= @@ -1598,7 +1595,7 @@ iwl_mvm_umac_scan_cfg_channels(struct iwl_mvm *mvm,  	for (i = 0; i < n_channels; i++) {  		channel_cfg[i].flags = cpu_to_le32(flags); -		channel_cfg[i].v1.channel_num = channels[i]->hw_value; +		channel_cfg[i].channel_num = channels[i]->hw_value;  		if (iwl_mvm_is_scan_ext_chan_supported(mvm)) {  			enum nl80211_band band = channels[i]->band; @@ -1630,13 +1627,13 @@ iwl_mvm_umac_scan_cfg_channels_v4(struct iwl_mvm *mvm,  			&cp->channel_config[i];  		cfg->flags = cpu_to_le32(flags); -		cfg->v2.channel_num = channels[i]->hw_value; +		cfg->channel_num = channels[i]->hw_value;  		cfg->v2.band = iwl_mvm_phy_band_from_nl80211(band);  		cfg->v2.iter_count = 1;  		cfg->v2.iter_interval = 0;  		iwl_mvm_scan_ch_add_n_aps_override(vif_type, -						   cfg->v2.channel_num, +						   cfg->channel_num,  						   cfg->v2.band, bitmap,  						   bitmap_n_entries);  	} @@ -1660,7 +1657,7 @@ iwl_mvm_umac_scan_cfg_channels_v7(struct iwl_mvm *mvm,  		u8 iwl_band = iwl_mvm_phy_band_from_nl80211(band);  		cfg->flags = cpu_to_le32(flags | n_aps_flag); -		cfg->v2.channel_num = channels[i]->hw_value; +		cfg->channel_num = channels[i]->hw_value;  		if (cfg80211_channel_is_psc(channels[i]))  			cfg->flags = 0; @@ -1778,7 +1775,7 @@ iwl_mvm_umac_scan_cfg_channels_v7_6g(struct iwl_mvm *mvm,  			&cp->channel_config[ch_cnt];  		u32 s_ssid_bitmap = 0, bssid_bitmap = 0, flags = 0; -		u8 j, k, n_s_ssids = 0, n_bssids = 0; +		u8 k, n_s_ssids = 0, n_bssids = 0;  		u8 max_s_ssids, max_bssids;  		bool force_passive = false, found = false, allow_passive = true,  		     unsolicited_probe_on_chan = false, psc_no_listen = false; @@ -1793,7 +1790,7 @@ iwl_mvm_umac_scan_cfg_channels_v7_6g(struct iwl_mvm *mvm,  		    !params->n_6ghz_params && params->n_ssids)  			continue; -		cfg->v1.channel_num = params->channels[i]->hw_value; +		cfg->channel_num = params->channels[i]->hw_value;  		if (version < 17)  			cfg->v2.band = PHY_BAND_6;  		else @@ -1803,7 +1800,7 @@ iwl_mvm_umac_scan_cfg_channels_v7_6g(struct iwl_mvm *mvm,  		cfg->v5.iter_count = 1;  		cfg->v5.iter_interval = 0; -		for (j = 0; j < params->n_6ghz_params; j++) { +		for (u32 j = 0; j < params->n_6ghz_params; j++) {  			s8 tmp_psd_20;  			if (!(scan_6ghz_params[j].channel_idx == i)) @@ -1877,7 +1874,7 @@ iwl_mvm_umac_scan_cfg_channels_v7_6g(struct iwl_mvm *mvm,  		 * SSID.  		 * TODO: improve this logic  		 */ -		for (j = 0; j < params->n_6ghz_params; j++) { +		for (u32 j = 0; j < params->n_6ghz_params; j++) {  			if (!(scan_6ghz_params[j].channel_idx == i))  				continue; @@ -2481,7 +2478,7 @@ iwl_mvm_scan_umac_fill_ch_p_v7(struct iwl_mvm *mvm,  			if (!cfg80211_channel_is_psc(channel))  				continue; -			cfg->v5.channel_num = channel->hw_value; +			cfg->channel_num = channel->hw_value;  			cfg->v5.iter_count = 1;  			cfg->v5.iter_interval = 0; @@ -3317,13 +3314,23 @@ void iwl_mvm_rx_umac_scan_iter_complete_notif(struct iwl_mvm *mvm,  		       mvm->scan_start);  } -static int iwl_mvm_umac_scan_abort(struct iwl_mvm *mvm, int type) +static int iwl_mvm_umac_scan_abort(struct iwl_mvm *mvm, int type, bool *wait)  { -	struct iwl_umac_scan_abort cmd = {}; +	struct iwl_umac_scan_abort abort_cmd = {}; +	struct iwl_host_cmd cmd = { +		.id = WIDE_ID(IWL_ALWAYS_LONG_GROUP, SCAN_ABORT_UMAC), +		.len = { sizeof(abort_cmd), }, +		.data = { &abort_cmd, }, +		.flags = CMD_SEND_IN_RFKILL, +	}; +  	int uid, ret; +	u32 status = IWL_UMAC_SCAN_ABORT_STATUS_NOT_FOUND;  	lockdep_assert_held(&mvm->mutex); +	*wait = true; +  	/* We should always get a valid index here, because we already  	 * checked that this type of scan was running in the generic  	 * code. @@ -3332,17 +3339,28 @@ static int iwl_mvm_umac_scan_abort(struct iwl_mvm *mvm, int type)  	if (WARN_ON_ONCE(uid < 0))  		return uid; -	cmd.uid = cpu_to_le32(uid); +	abort_cmd.uid = cpu_to_le32(uid);  	IWL_DEBUG_SCAN(mvm, "Sending scan abort, uid %u\n", uid); -	ret = iwl_mvm_send_cmd_pdu(mvm, -				   WIDE_ID(IWL_ALWAYS_LONG_GROUP, SCAN_ABORT_UMAC), -				   CMD_SEND_IN_RFKILL, sizeof(cmd), &cmd); +	ret = iwl_mvm_send_cmd_status(mvm, &cmd, &status); + +	IWL_DEBUG_SCAN(mvm, "Scan abort: ret=%d, status=%u\n", ret, status);  	if (!ret)  		mvm->scan_uid_status[uid] = type << IWL_MVM_SCAN_STOPPING_SHIFT; -	IWL_DEBUG_SCAN(mvm, "Scan abort: ret=%d\n", ret); +	/* Handle the case that the FW is no longer familiar with the scan that +	 * is to be stopped. In such a case, it is expected that the scan +	 * complete notification was already received but not yet processed. +	 * In such a case, there is no need to wait for a scan complete +	 * notification and the flow should continue similar to the case that +	 * the scan was really aborted. +	 */ +	if (status == IWL_UMAC_SCAN_ABORT_STATUS_NOT_FOUND) { +		mvm->scan_uid_status[uid] = type << IWL_MVM_SCAN_STOPPING_SHIFT; +		*wait = false; +	} +  	return ret;  } @@ -3352,6 +3370,7 @@ static int iwl_mvm_scan_stop_wait(struct iwl_mvm *mvm, int type)  	static const u16 scan_done_notif[] = { SCAN_COMPLETE_UMAC,  					      SCAN_OFFLOAD_COMPLETE, };  	int ret; +	bool wait = true;  	lockdep_assert_held(&mvm->mutex); @@ -3363,7 +3382,7 @@ static int iwl_mvm_scan_stop_wait(struct iwl_mvm *mvm, int type)  	IWL_DEBUG_SCAN(mvm, "Preparing to stop scan, type %x\n", type);  	if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_UMAC_SCAN)) -		ret = iwl_mvm_umac_scan_abort(mvm, type); +		ret = iwl_mvm_umac_scan_abort(mvm, type, &wait);  	else  		ret = iwl_mvm_lmac_scan_abort(mvm); @@ -3371,6 +3390,10 @@ static int iwl_mvm_scan_stop_wait(struct iwl_mvm *mvm, int type)  		IWL_DEBUG_SCAN(mvm, "couldn't stop scan type %d\n", type);  		iwl_remove_notification(&mvm->notif_wait, &wait_scan_done);  		return ret; +	} else if (!wait) { +		IWL_DEBUG_SCAN(mvm, "no need to wait for scan type %d\n", type); +		iwl_remove_notification(&mvm->notif_wait, &wait_scan_done); +		return 0;  	}  	return iwl_wait_notification(&mvm->notif_wait, &wait_scan_done, @@ -3455,7 +3478,7 @@ void iwl_mvm_report_scan_aborted(struct iwl_mvm *mvm)  			 * restart_hw, so do not report if FW is about to be  			 * restarted.  			 */ -			if (!mvm->fw_restart) +			if (!iwlwifi_mod_params.fw_restart)  				ieee80211_sched_scan_stopped(mvm->hw);  			mvm->sched_scan_pass_all = SCHED_SCAN_PASS_ALL_DISABLED;  			mvm->scan_uid_status[uid] = 0; @@ -3506,7 +3529,7 @@ void iwl_mvm_report_scan_aborted(struct iwl_mvm *mvm)  		 * restarted.  		 */  		if ((mvm->scan_status & IWL_MVM_SCAN_SCHED) && -		    !mvm->fw_restart) { +		    !iwlwifi_mod_params.fw_restart) {  			ieee80211_sched_scan_stopped(mvm->hw);  			mvm->sched_scan_pass_all = SCHED_SCAN_PASS_ALL_DISABLED;  		} @@ -3524,7 +3547,7 @@ int iwl_mvm_scan_stop(struct iwl_mvm *mvm, int type, bool notify)  	if (!(mvm->scan_status & type))  		return 0; -	if (!test_bit(STATUS_DEVICE_ENABLED, &mvm->trans->status)) { +	if (!iwl_trans_device_enabled(mvm->trans)) {  		ret = 0;  		goto out;  	} @@ -3575,7 +3598,8 @@ static int iwl_mvm_int_mlo_scan_start(struct iwl_mvm *mvm,  	IWL_DEBUG_SCAN(mvm, "Starting Internal MLO scan: n_channels=%zu\n",  		       n_channels); -	if (!vif->cfg.assoc || !ieee80211_vif_is_mld(vif)) +	if (!vif->cfg.assoc || !ieee80211_vif_is_mld(vif) || +	    hweight16(vif->valid_links) == 1)  		return -EINVAL;  	size = struct_size(req, channels, n_channels); @@ -3662,117 +3686,6 @@ static int iwl_mvm_chanidx_from_phy(struct iwl_mvm *mvm,  	return -EINVAL;  } -static u32 iwl_mvm_div_by_db(u32 value, u8 db) -{ -	/* -	 * 2^32 * 10**(i / 10) for i = [1, 10], skipping 0 and simply stopping -	 * at 10 dB and looping instead of using a much larger table. -	 * -	 * Using 64 bit math is overkill, but means the helper does not require -	 * a limit on the input range. -	 */ -	static const u32 db_to_val[] = { -		0xcb59185e, 0xa1866ba8, 0x804dce7a, 0x65ea59fe, 0x50f44d89, -		0x404de61f, 0x331426af, 0x2892c18b, 0x203a7e5b, 0x1999999a, -	}; - -	while (value && db > 0) { -		u8 change = min_t(u8, db, ARRAY_SIZE(db_to_val)); - -		value = (((u64)value) * db_to_val[change - 1]) >> 32; - -		db -= change; -	} - -	return value; -} - -VISIBLE_IF_IWLWIFI_KUNIT s8 -iwl_mvm_average_dbm_values(const struct iwl_umac_scan_channel_survey_notif *notif) -{ -	s8 average_magnitude; -	u32 average_factor; -	s8 sum_magnitude = -128; -	u32 sum_factor = 0; -	int i, count = 0; - -	/* -	 * To properly average the decibel values (signal values given in dBm) -	 * we need to do the math in linear space.  Doing a linear average of -	 * dB (dBm) values is a bit annoying though due to the large range of -	 * at least -10 to -110 dBm that will not fit into a 32 bit integer. -	 * -	 * A 64 bit integer should be sufficient, but then we still have the -	 * problem that there are no directly usable utility functions -	 * available. -	 * -	 * So, lets not deal with that and instead do much of the calculation -	 * with a 16.16 fixed point integer along with a base in dBm. 16.16 bit -	 * gives us plenty of head-room for adding up a few values and even -	 * doing some math on it. And the tail should be accurate enough too -	 * (1/2^16 is somewhere around -48 dB, so effectively zero). -	 * -	 * i.e. the real value of sum is: -	 *      sum = sum_factor / 2^16 * 10^(sum_magnitude / 10) mW -	 * -	 * However, that does mean we need to be able to bring two values to -	 * a common base, so we need a helper for that. -	 * -	 * Note that this function takes an input with unsigned negative dBm -	 * values but returns a signed dBm (i.e. a negative value). -	 */ - -	for (i = 0; i < ARRAY_SIZE(notif->noise); i++) { -		s8 val_magnitude; -		u32 val_factor; - -		if (notif->noise[i] == 0xff) -			continue; - -		val_factor = 0x10000; -		val_magnitude = -notif->noise[i]; - -		if (val_magnitude <= sum_magnitude) { -			u8 div_db = sum_magnitude - val_magnitude; - -			val_factor = iwl_mvm_div_by_db(val_factor, div_db); -			val_magnitude = sum_magnitude; -		} else { -			u8 div_db = val_magnitude - sum_magnitude; - -			sum_factor = iwl_mvm_div_by_db(sum_factor, div_db); -			sum_magnitude = val_magnitude; -		} - -		sum_factor += val_factor; -		count++; -	} - -	/* No valid noise measurement, return a very high noise level */ -	if (count == 0) -		return 0; - -	average_magnitude = sum_magnitude; -	average_factor = sum_factor / count; - -	/* -	 * average_factor will be a number smaller than 1.0 (0x10000) at this -	 * point. What we need to do now is to adjust average_magnitude so that -	 * average_factor is between -0.5 dB and 0.5 dB. -	 * -	 * Just do -1 dB steps and find the point where -	 *   -0.5 dB * -i dB = 0x10000 * 10^(-0.5/10) / i dB -	 *                   = div_by_db(0xe429, i) -	 * is smaller than average_factor. -	 */ -	for (i = 0; average_factor < iwl_mvm_div_by_db(0xe429, i); i++) { -		/* nothing */ -	} - -	return average_magnitude - i; -} -EXPORT_SYMBOL_IF_IWLWIFI_KUNIT(iwl_mvm_average_dbm_values); -  void iwl_mvm_rx_channel_survey_notif(struct iwl_mvm *mvm,  				     struct iwl_rx_cmd_buffer *rxb)  { @@ -3830,5 +3743,6 @@ void iwl_mvm_rx_channel_survey_notif(struct iwl_mvm *mvm,  	info->time_busy = le32_to_cpu(notif->busy_time);  	info->time_rx = le32_to_cpu(notif->rx_time);  	info->time_tx = le32_to_cpu(notif->tx_time); -	info->noise = iwl_mvm_average_dbm_values(notif); +	info->noise = +		iwl_average_neg_dbm(notif->noise, ARRAY_SIZE(notif->noise));  } diff --git a/sys/contrib/dev/iwlwifi/mvm/sta.c b/sys/contrib/dev/iwlwifi/mvm/sta.c index f47b3f6b8f64..3fc774c2ca39 100644 --- a/sys/contrib/dev/iwlwifi/mvm/sta.c +++ b/sys/contrib/dev/iwlwifi/mvm/sta.c @@ -1,6 +1,6 @@  // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause  /* - * Copyright (C) 2012-2015, 2018-2024 Intel Corporation + * Copyright (C) 2012-2015, 2018-2025 Intel Corporation   * Copyright (C) 2013-2015 Intel Mobile Communications GmbH   * Copyright (C) 2016-2017 Intel Deutschland GmbH   */ @@ -32,7 +32,7 @@ int iwl_mvm_find_free_sta_id(struct iwl_mvm *mvm, enum nl80211_iftype iftype)  	int sta_id;  	u32 reserved_ids = 0; -	BUILD_BUG_ON(IWL_MVM_STATION_COUNT_MAX > 32); +	BUILD_BUG_ON(IWL_STATION_COUNT_MAX > 32);  	WARN_ON_ONCE(test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status));  	lockdep_assert_held(&mvm->mutex); @@ -50,7 +50,7 @@ int iwl_mvm_find_free_sta_id(struct iwl_mvm *mvm, enum nl80211_iftype iftype)  					       lockdep_is_held(&mvm->mutex)))  			return sta_id;  	} -	return IWL_MVM_INVALID_STA; +	return IWL_INVALID_STA;  }  /* Calculate the ampdu density and max size */ @@ -256,7 +256,7 @@ int iwl_mvm_sta_send_to_fw(struct iwl_mvm *mvm, struct ieee80211_sta *sta,  static void iwl_mvm_rx_agg_session_expired(struct timer_list *t)  {  	struct iwl_mvm_baid_data *data = -		from_timer(data, t, session_timer); +		timer_container_of(data, t, session_timer);  	struct iwl_mvm_baid_data __rcu **rcu_ptr = data->rcu_ptr;  	struct iwl_mvm_baid_data *ba_data;  	struct ieee80211_sta *sta; @@ -794,10 +794,10 @@ static int iwl_mvm_find_free_queue(struct iwl_mvm *mvm, u8 sta_id,  	lockdep_assert_held(&mvm->mutex); -	if (WARN(maxq >= mvm->trans->trans_cfg->base_params->num_of_queues, +	if (WARN(maxq >= mvm->trans->mac_cfg->base->num_of_queues,  		 "max queue %d >= num_of_queues (%d)", maxq, -		 mvm->trans->trans_cfg->base_params->num_of_queues)) -		maxq = mvm->trans->trans_cfg->base_params->num_of_queues - 1; +		 mvm->trans->mac_cfg->base->num_of_queues)) +		maxq = mvm->trans->mac_cfg->base->num_of_queues - 1;  	/* This should not be hit with new TX path */  	if (WARN_ON(iwl_mvm_has_new_tx_api(mvm))) @@ -855,7 +855,7 @@ int iwl_mvm_tvqm_enable_txq(struct iwl_mvm *mvm,  	if (tid == IWL_MAX_TID_COUNT) {  		tid = IWL_MGMT_TID;  		size = max_t(u32, IWL_MGMT_QUEUE_SIZE, -			     mvm->trans->cfg->min_txq_size); +			     mvm->trans->mac_cfg->base->min_txq_size);  	} else {  		size = iwl_mvm_get_queue_size(sta);  	} @@ -903,7 +903,7 @@ static int iwl_mvm_sta_alloc_queue_tvqm(struct iwl_mvm *mvm,  	struct iwl_mvm_txq *mvmtxq =  		iwl_mvm_txq_from_tid(sta, tid);  	unsigned int wdg_timeout = -		iwl_mvm_get_wd_timeout(mvm, mvmsta->vif, false, false); +		iwl_mvm_get_wd_timeout(mvm, mvmsta->vif);  	int queue = -1;  	lockdep_assert_held(&mvm->mutex); @@ -1083,7 +1083,7 @@ static void iwl_mvm_unshare_queue(struct iwl_mvm *mvm, int queue)  		return;  	mvmsta = iwl_mvm_sta_from_mac80211(sta); -	wdg_timeout = iwl_mvm_get_wd_timeout(mvm, mvmsta->vif, false, false); +	wdg_timeout = iwl_mvm_get_wd_timeout(mvm, mvmsta->vif);  	ssn = IEEE80211_SEQ_TO_SN(mvmsta->tid_data[tid].seq_number); @@ -1219,7 +1219,7 @@ static bool iwl_mvm_remove_inactive_tids(struct iwl_mvm *mvm,   * can be unshared and finding one (and only one) that can be   * reused.   * This function is also invoked as a sort of clean-up task, - * in which case @alloc_for_sta is IWL_MVM_INVALID_STA. + * in which case @alloc_for_sta is IWL_INVALID_STA.   *   * Returns the queue number, or -ENOSPC.   */ @@ -1312,7 +1312,7 @@ static int iwl_mvm_inactivity_check(struct iwl_mvm *mvm, u8 alloc_for_sta)  	rcu_read_unlock(); -	if (free_queue >= 0 && alloc_for_sta != IWL_MVM_INVALID_STA) { +	if (free_queue >= 0 && alloc_for_sta != IWL_INVALID_STA) {  		ret = iwl_mvm_free_inactive_queue(mvm, free_queue, queue_owner,  						  alloc_for_sta);  		if (ret) @@ -1333,7 +1333,7 @@ static int iwl_mvm_sta_alloc_queue(struct iwl_mvm *mvm,  		.frame_limit = IWL_FRAME_LIMIT,  	};  	unsigned int wdg_timeout = -		iwl_mvm_get_wd_timeout(mvm, mvmsta->vif, false, false); +		iwl_mvm_get_wd_timeout(mvm, mvmsta->vif);  	int queue = -1;  	u16 queue_tmp;  	unsigned long disable_agg_tids = 0; @@ -1523,9 +1523,14 @@ void iwl_mvm_add_new_dqa_stream_wk(struct work_struct *wk)  	struct iwl_mvm *mvm = container_of(wk, struct iwl_mvm,  					   add_stream_wk); -	mutex_lock(&mvm->mutex); +	guard(mvm)(mvm); -	iwl_mvm_inactivity_check(mvm, IWL_MVM_INVALID_STA); +	/* will reschedule to run after restart */ +	if (test_bit(IWL_MVM_STATUS_HW_RESTART_REQUESTED, &mvm->status) || +	    test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) +		return; + +	iwl_mvm_inactivity_check(mvm, IWL_INVALID_STA);  	while (!list_empty(&mvm->add_stream_txqs)) {  		struct iwl_mvm_txq *mvmtxq; @@ -1567,8 +1572,6 @@ void iwl_mvm_add_new_dqa_stream_wk(struct work_struct *wk)  		iwl_mvm_mac_itxq_xmit(mvm->hw, txq);  		local_bh_enable();  	} - -	mutex_unlock(&mvm->mutex);  }  static int iwl_mvm_reserve_sta_stream(struct iwl_mvm *mvm, @@ -1583,7 +1586,7 @@ static int iwl_mvm_reserve_sta_stream(struct iwl_mvm *mvm,  		return 0;  	/* run the general cleanup/unsharing of queues */ -	iwl_mvm_inactivity_check(mvm, IWL_MVM_INVALID_STA); +	iwl_mvm_inactivity_check(mvm, IWL_INVALID_STA);  	/* Make sure we have free resources for this STA */  	if (vif_type == NL80211_IFTYPE_STATION && !sta->tdls && @@ -1625,7 +1628,7 @@ void iwl_mvm_realloc_queues_after_restart(struct iwl_mvm *mvm,  {  	struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);  	unsigned int wdg = -		iwl_mvm_get_wd_timeout(mvm, mvm_sta->vif, false, false); +		iwl_mvm_get_wd_timeout(mvm, mvm_sta->vif);  	int i;  	struct iwl_trans_txq_scd_cfg cfg = {  		.sta_id = mvm_sta->deflink.sta_id, @@ -1759,13 +1762,13 @@ int iwl_mvm_sta_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif,  	 * this function  	 */  	if (!mvm->mld_api_is_used) { -		if (WARN_ON(sta_id == IWL_MVM_INVALID_STA)) +		if (WARN_ON(sta_id == IWL_INVALID_STA))  			return -EINVAL;  		mvm_sta->deflink.sta_id = sta_id;  		rcu_assign_pointer(mvm_sta->link[0], &mvm_sta->deflink); -		if (!mvm->trans->trans_cfg->gen2) +		if (!mvm->trans->mac_cfg->gen2)  			mvm_sta->deflink.lq_sta.rs_drv.pers.max_agg_bufsize =  				LINK_QUAL_AGG_FRAME_LIMIT_DEF;  		else @@ -1798,7 +1801,7 @@ int iwl_mvm_sta_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif,  	if (iwl_mvm_has_new_rx_api(mvm)) {  		int q; -		dup_data = kcalloc(mvm->trans->num_rx_queues, +		dup_data = kcalloc(mvm->trans->info.num_rxqs,  				   sizeof(*dup_data), GFP_KERNEL);  		if (!dup_data)  			return -ENOMEM; @@ -1811,7 +1814,7 @@ int iwl_mvm_sta_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif,  		 * This thus allows receiving a packet with seqno 0 and the  		 * retry bit set as the very first packet on a new TID.  		 */ -		for (q = 0; q < mvm->trans->num_rx_queues; q++) +		for (q = 0; q < mvm->trans->info.num_rxqs; q++)  			memset(dup_data[q].last_seq, 0xff,  			       sizeof(dup_data[q].last_seq));  		mvm_sta->dup_data = dup_data; @@ -1839,11 +1842,11 @@ int iwl_mvm_sta_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif,  	if (vif->type == NL80211_IFTYPE_STATION && !vif->p2p &&  	    !sta->tdls && ieee80211_vif_is_mld(vif)) {  		mvm_sta->mpdu_counters = -			kcalloc(mvm->trans->num_rx_queues, +			kcalloc(mvm->trans->info.num_rxqs,  				sizeof(*mvm_sta->mpdu_counters),  				GFP_KERNEL);  		if (mvm_sta->mpdu_counters) -			for (int q = 0; q < mvm->trans->num_rx_queues; q++) +			for (int q = 0; q < mvm->trans->info.num_rxqs; q++)  				spin_lock_init(&mvm_sta->mpdu_counters[q].lock);  	} @@ -1868,7 +1871,7 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm,  	else  		sta_id = mvm_sta->deflink.sta_id; -	if (sta_id == IWL_MVM_INVALID_STA) +	if (sta_id == IWL_INVALID_STA)  		return -ENOSPC;  	spin_lock_init(&mvm_sta->lock); @@ -1906,10 +1909,10 @@ update_fw:  	if (vif->type == NL80211_IFTYPE_STATION) {  		if (!sta->tdls) { -			WARN_ON(mvmvif->deflink.ap_sta_id != IWL_MVM_INVALID_STA); +			WARN_ON(mvmvif->deflink.ap_sta_id != IWL_INVALID_STA);  			mvmvif->deflink.ap_sta_id = sta_id;  		} else { -			WARN_ON(mvmvif->deflink.ap_sta_id == IWL_MVM_INVALID_STA); +			WARN_ON(mvmvif->deflink.ap_sta_id == IWL_INVALID_STA);  		}  	} @@ -2053,9 +2056,9 @@ int iwl_mvm_wait_sta_queues_empty(struct iwl_mvm *mvm,   * Returns if we're done with removing the station, either   * with error or success   */ -bool iwl_mvm_sta_del(struct iwl_mvm *mvm, struct ieee80211_vif *vif, +void iwl_mvm_sta_del(struct iwl_mvm *mvm, struct ieee80211_vif *vif,  		     struct ieee80211_sta *sta, -		     struct ieee80211_link_sta *link_sta, int *ret) +		     struct ieee80211_link_sta *link_sta)  {  	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);  	struct iwl_mvm_vif_link_info *mvm_link = @@ -2071,39 +2074,13 @@ bool iwl_mvm_sta_del(struct iwl_mvm *mvm, struct ieee80211_vif *vif,  					  lockdep_is_held(&mvm->mutex));  	sta_id = mvm_link_sta->sta_id; -	/* If there is a TXQ still marked as reserved - free it */ -	if (mvm_sta->reserved_queue != IEEE80211_INVAL_HW_QUEUE) { -		u8 reserved_txq = mvm_sta->reserved_queue; -		enum iwl_mvm_queue_status *status; - -		/* -		 * If no traffic has gone through the reserved TXQ - it -		 * is still marked as IWL_MVM_QUEUE_RESERVED, and -		 * should be manually marked as free again -		 */ -		status = &mvm->queue_info[reserved_txq].status; -		if (WARN((*status != IWL_MVM_QUEUE_RESERVED) && -			 (*status != IWL_MVM_QUEUE_FREE), -			 "sta_id %d reserved txq %d status %d", -			 sta_id, reserved_txq, *status)) { -			*ret = -EINVAL; -			return true; -		} - -		*status = IWL_MVM_QUEUE_FREE; -	} -  	if (vif->type == NL80211_IFTYPE_STATION &&  	    mvm_link->ap_sta_id == sta_id) { -		/* if associated - we can't remove the AP STA now */ -		if (vif->cfg.assoc) -			return true; -  		/* first remove remaining keys */ -		iwl_mvm_sec_key_remove_ap(mvm, vif, mvm_link, 0); +		iwl_mvm_sec_key_remove_ap(mvm, vif, mvm_link, +					  link_sta->link_id); -		/* unassoc - go ahead - remove the AP STA now */ -		mvm_link->ap_sta_id = IWL_MVM_INVALID_STA; +		mvm_link->ap_sta_id = IWL_INVALID_STA;  	}  	/* @@ -2111,11 +2088,9 @@ bool iwl_mvm_sta_del(struct iwl_mvm *mvm, struct ieee80211_vif *vif,  	 * before the STA is removed.  	 */  	if (WARN_ON_ONCE(mvm->tdls_cs.peer.sta_id == sta_id)) { -		mvm->tdls_cs.peer.sta_id = IWL_MVM_INVALID_STA; +		mvm->tdls_cs.peer.sta_id = IWL_INVALID_STA;  		cancel_delayed_work(&mvm->tdls_cs.dwork);  	} - -	return false;  }  int iwl_mvm_rm_sta(struct iwl_mvm *mvm, @@ -2151,8 +2126,27 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm,  	iwl_mvm_disable_sta_queues(mvm, vif, sta); -	if (iwl_mvm_sta_del(mvm, vif, sta, &sta->deflink, &ret)) -		return ret; +	/* If there is a TXQ still marked as reserved - free it */ +	if (mvm_sta->reserved_queue != IEEE80211_INVAL_HW_QUEUE) { +		u8 reserved_txq = mvm_sta->reserved_queue; +		enum iwl_mvm_queue_status *status; + +		/* +		 * If no traffic has gone through the reserved TXQ - it +		 * is still marked as IWL_MVM_QUEUE_RESERVED, and +		 * should be manually marked as free again +		 */ +		status = &mvm->queue_info[reserved_txq].status; +		if (WARN((*status != IWL_MVM_QUEUE_RESERVED) && +			 (*status != IWL_MVM_QUEUE_FREE), +			 "sta_id %d reserved txq %d status %d", +			 mvm_sta->deflink.sta_id, reserved_txq, *status)) +			return -EINVAL; + +		*status = IWL_MVM_QUEUE_FREE; +	} + +	iwl_mvm_sta_del(mvm, vif, sta, &sta->deflink);  	ret = iwl_mvm_rm_sta_common(mvm, mvm_sta->deflink.sta_id);  	RCU_INIT_POINTER(mvm->fw_id_to_mac_id[mvm_sta->deflink.sta_id], NULL); @@ -2178,9 +2172,9 @@ int iwl_mvm_allocate_int_sta(struct iwl_mvm *mvm,  			     u8 type)  {  	if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) || -	    sta->sta_id == IWL_MVM_INVALID_STA) { +	    sta->sta_id == IWL_INVALID_STA) {  		sta->sta_id = iwl_mvm_find_free_sta_id(mvm, iftype); -		if (WARN_ON_ONCE(sta->sta_id == IWL_MVM_INVALID_STA)) +		if (WARN_ON_ONCE(sta->sta_id == IWL_INVALID_STA))  			return -ENOSPC;  	} @@ -2196,14 +2190,14 @@ void iwl_mvm_dealloc_int_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *sta)  {  	RCU_INIT_POINTER(mvm->fw_id_to_mac_id[sta->sta_id], NULL);  	memset(sta, 0, sizeof(struct iwl_mvm_int_sta)); -	sta->sta_id = IWL_MVM_INVALID_STA; +	sta->sta_id = IWL_INVALID_STA;  }  static void iwl_mvm_enable_aux_snif_queue(struct iwl_mvm *mvm, u16 queue,  					  u8 sta_id, u8 fifo)  {  	unsigned int wdg_timeout = -		mvm->trans->trans_cfg->base_params->wd_timeout; +		mvm->trans->mac_cfg->base->wd_timeout;  	struct iwl_trans_txq_scd_cfg cfg = {  		.fifo = fifo,  		.sta_id = sta_id, @@ -2220,7 +2214,7 @@ static void iwl_mvm_enable_aux_snif_queue(struct iwl_mvm *mvm, u16 queue,  static int iwl_mvm_enable_aux_snif_queue_tvqm(struct iwl_mvm *mvm, u8 sta_id)  {  	unsigned int wdg_timeout = -		mvm->trans->trans_cfg->base_params->wd_timeout; +		mvm->trans->mac_cfg->base->wd_timeout;  	WARN_ON(!iwl_mvm_has_new_tx_api(mvm)); @@ -2314,7 +2308,7 @@ int iwl_mvm_rm_snif_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)  	lockdep_assert_held(&mvm->mutex); -	if (WARN_ON_ONCE(mvm->snif_sta.sta_id == IWL_MVM_INVALID_STA)) +	if (WARN_ON_ONCE(mvm->snif_sta.sta_id == IWL_INVALID_STA))  		return -EINVAL;  	iwl_mvm_disable_txq(mvm, NULL, mvm->snif_sta.sta_id, @@ -2332,7 +2326,7 @@ int iwl_mvm_rm_aux_sta(struct iwl_mvm *mvm)  	lockdep_assert_held(&mvm->mutex); -	if (WARN_ON_ONCE(mvm->aux_sta.sta_id == IWL_MVM_INVALID_STA)) +	if (WARN_ON_ONCE(mvm->aux_sta.sta_id == IWL_INVALID_STA))  		return -EINVAL;  	iwl_mvm_disable_txq(mvm, NULL, mvm->aux_sta.sta_id, @@ -2367,7 +2361,7 @@ int iwl_mvm_send_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)  	int queue;  	int ret;  	unsigned int wdg_timeout = -		iwl_mvm_get_wd_timeout(mvm, vif, false, false); +		iwl_mvm_get_wd_timeout(mvm, vif);  	struct iwl_trans_txq_scd_cfg cfg = {  		.fifo = IWL_MVM_TX_FIFO_VO,  		.sta_id = mvmvif->deflink.bcast_sta.sta_id, @@ -2397,7 +2391,7 @@ int iwl_mvm_send_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)  	if (vif->type == NL80211_IFTYPE_ADHOC)  		baddr = vif->bss_conf.bssid; -	if (WARN_ON_ONCE(bsta->sta_id == IWL_MVM_INVALID_STA)) +	if (WARN_ON_ONCE(bsta->sta_id == IWL_INVALID_STA))  		return -ENOSPC;  	ret = iwl_mvm_add_int_sta_common(mvm, bsta, baddr, @@ -2475,7 +2469,7 @@ void iwl_mvm_free_bcast_sta_queues(struct iwl_mvm *mvm,  	mvmvif->deflink.bcast_sta.tfd_queue_msk &= ~BIT(queue);  } -/* Send the FW a request to remove the station from it's internal data +/* Send the FW a request to remove the station from its internal data   * structures, but DO NOT remove the entry from the local data structures. */  int iwl_mvm_send_rm_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)  { @@ -2538,7 +2532,7 @@ void iwl_mvm_dealloc_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)  }  /* - * Send the FW a request to remove the station from it's internal data + * Send the FW a request to remove the station from its internal data   * structures, and in addition remove it from the local data structure.   */  int iwl_mvm_rm_p2p_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) @@ -2576,7 +2570,7 @@ int iwl_mvm_add_mcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)  		.aggregate = false,  		.frame_limit = IWL_FRAME_LIMIT,  	}; -	unsigned int timeout = iwl_mvm_get_wd_timeout(mvm, vif, false, false); +	unsigned int timeout = iwl_mvm_get_wd_timeout(mvm, vif);  	int ret;  	lockdep_assert_held(&mvm->mutex); @@ -2652,7 +2646,7 @@ static int __iwl_mvm_remove_sta_key(struct iwl_mvm *mvm, u8 sta_id,  	u32 status;  	/* This is a valid situation for GTK removal */ -	if (sta_id == IWL_MVM_INVALID_STA) +	if (sta_id == IWL_INVALID_STA)  		return 0;  	key_flags = cpu_to_le16((keyconf->keyidx << STA_KEY_FLG_KEYID_POS) & @@ -2691,7 +2685,7 @@ static int __iwl_mvm_remove_sta_key(struct iwl_mvm *mvm, u8 sta_id,  }  /* - * Send the FW a request to remove the station from it's internal data + * Send the FW a request to remove the station from its internal data   * structures, and in addition remove it from the local data structure.   */  int iwl_mvm_rm_mcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) @@ -2731,7 +2725,7 @@ static void iwl_mvm_free_reorder(struct iwl_mvm *mvm,  	iwl_mvm_sync_rxq_del_ba(mvm, data->baid); -	for (i = 0; i < mvm->trans->num_rx_queues; i++) { +	for (i = 0; i < mvm->trans->info.num_rxqs; i++) {  		int j;  		struct iwl_mvm_reorder_buffer *reorder_buf =  			&data->reorder_buf[i]; @@ -2764,7 +2758,7 @@ static void iwl_mvm_init_reorder_buffer(struct iwl_mvm *mvm,  {  	int i; -	for (i = 0; i < mvm->trans->num_rx_queues; i++) { +	for (i = 0; i < mvm->trans->info.num_rxqs; i++) {  		struct iwl_mvm_reorder_buffer *reorder_buf =  			&data->reorder_buf[i];  		struct iwl_mvm_reorder_buf_entry *entries = @@ -2920,7 +2914,7 @@ int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,  		/*  		 * The division below will be OK if either the cache line size  		 * can be divided by the entry size (ALIGN will round up) or if -		 * if the entry size can be divided by the cache line size, in +		 * the entry size can be divided by the cache line size, in  		 * which case the ALIGN() will do nothing.  		 */  		BUILD_BUG_ON(SMP_CACHE_BYTES % sizeof(baid_data->entries[0]) && @@ -2939,7 +2933,7 @@ int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,  		 * before starting the BA session in the firmware  		 */  		baid_data = kzalloc(sizeof(*baid_data) + -				    mvm->trans->num_rx_queues * +				    mvm->trans->info.num_rxqs *  				    reorder_buf_size,  				    GFP_KERNEL);  		if (!baid_data) @@ -3191,7 +3185,7 @@ int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif,  	 * to align the wrap around of ssn so we compare relevant values.  	 */  	normalized_ssn = tid_data->ssn; -	if (mvm->trans->trans_cfg->gen2) +	if (mvm->trans->mac_cfg->gen2)  		normalized_ssn &= 0xff;  	if (normalized_ssn == tid_data->next_reclaimed) { @@ -3215,7 +3209,7 @@ int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif,  	struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);  	struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid];  	unsigned int wdg_timeout = -		iwl_mvm_get_wd_timeout(mvm, vif, sta->tdls, false); +		iwl_mvm_get_wd_timeout(mvm, vif);  	int queue, ret;  	bool alloc_queue = true;  	enum iwl_mvm_queue_status queue_status; @@ -3522,7 +3516,7 @@ static struct iwl_mvm_sta *iwl_mvm_get_key_sta(struct iwl_mvm *mvm,  	 * station ID, then use AP's station ID.  	 */  	if (vif->type == NL80211_IFTYPE_STATION && -	    mvmvif->deflink.ap_sta_id != IWL_MVM_INVALID_STA) { +	    mvmvif->deflink.ap_sta_id != IWL_INVALID_STA) {  		u8 sta_id = mvmvif->deflink.ap_sta_id;  		sta = rcu_dereference_check(mvm->fw_id_to_mac_id[sta_id], @@ -3577,7 +3571,7 @@ static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm,  	int api_ver = iwl_fw_lookup_cmd_ver(mvm->fw, ADD_STA_KEY,  					    new_api ? 2 : 1); -	if (sta_id == IWL_MVM_INVALID_STA) +	if (sta_id == IWL_INVALID_STA)  		return -EINVAL;  	keyidx = (key->keyidx << STA_KEY_FLG_KEYID_POS) & @@ -3736,7 +3730,7 @@ static int iwl_mvm_send_sta_igtk(struct iwl_mvm *mvm,  	if (remove_key) {  		/* This is a valid situation for IGTK */ -		if (sta_id == IWL_MVM_INVALID_STA) +		if (sta_id == IWL_INVALID_STA)  			return 0;  		igtk_cmd.ctrl_flags |= cpu_to_le32(STA_KEY_NOT_VALID); @@ -3803,7 +3797,7 @@ static inline u8 *iwl_mvm_get_mac_addr(struct iwl_mvm *mvm,  		return sta->addr;  	if (vif->type == NL80211_IFTYPE_STATION && -	    mvmvif->deflink.ap_sta_id != IWL_MVM_INVALID_STA) { +	    mvmvif->deflink.ap_sta_id != IWL_INVALID_STA) {  		u8 sta_id = mvmvif->deflink.ap_sta_id;  		sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id],  						lockdep_is_held(&mvm->mutex)); @@ -3873,7 +3867,7 @@ int iwl_mvm_set_sta_key(struct iwl_mvm *mvm,  {  	bool mcast = !(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE);  	struct iwl_mvm_sta *mvm_sta; -	u8 sta_id = IWL_MVM_INVALID_STA; +	u8 sta_id = IWL_INVALID_STA;  	int ret;  	static const u8 __maybe_unused zero_addr[ETH_ALEN] = {0}; @@ -3974,7 +3968,7 @@ int iwl_mvm_remove_sta_key(struct iwl_mvm *mvm,  {  	bool mcast = !(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE);  	struct iwl_mvm_sta *mvm_sta; -	u8 sta_id = IWL_MVM_INVALID_STA; +	u8 sta_id = IWL_INVALID_STA;  	int ret, i;  	lockdep_assert_held(&mvm->mutex); @@ -4281,7 +4275,7 @@ void iwl_mvm_modify_all_sta_disable_tx(struct iwl_mvm *mvm,  		return;  	/* Need to block/unblock also multicast station */ -	if (mvmvif->deflink.mcast_sta.sta_id != IWL_MVM_INVALID_STA) +	if (mvmvif->deflink.mcast_sta.sta_id != IWL_INVALID_STA)  		iwl_mvm_int_sta_modify_disable_tx(mvm, mvmvif,  						  &mvmvif->deflink.mcast_sta,  						  disable); @@ -4290,7 +4284,7 @@ void iwl_mvm_modify_all_sta_disable_tx(struct iwl_mvm *mvm,  	 * Only unblock the broadcast station (FW blocks it for immediate  	 * quiet, not the driver)  	 */ -	if (!disable && mvmvif->deflink.bcast_sta.sta_id != IWL_MVM_INVALID_STA) +	if (!disable && mvmvif->deflink.bcast_sta.sta_id != IWL_INVALID_STA)  		iwl_mvm_int_sta_modify_disable_tx(mvm, mvmvif,  						  &mvmvif->deflink.bcast_sta,  						  disable); @@ -4319,72 +4313,12 @@ u16 iwl_mvm_tid_queued(struct iwl_mvm *mvm, struct iwl_mvm_tid_data *tid_data)  	 * In 22000 HW, the next_reclaimed index is only 8 bit, so we'll need  	 * to align the wrap around of ssn so we compare relevant values.  	 */ -	if (mvm->trans->trans_cfg->gen2) +	if (mvm->trans->mac_cfg->gen2)  		sn &= 0xff;  	return ieee80211_sn_sub(sn, tid_data->next_reclaimed);  } -#if defined(__linux__) -int iwl_mvm_add_pasn_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif, -			 struct iwl_mvm_int_sta *sta, u8 *addr, u32 cipher, -			 u8 *key, u32 key_len, -			 struct ieee80211_key_conf *keyconf) -{ -	int ret; -	u16 queue; -	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); -	unsigned int wdg_timeout = -		iwl_mvm_get_wd_timeout(mvm, vif, false, false); -	bool mld = iwl_mvm_has_mld_api(mvm->fw); -	u32 type = mld ? STATION_TYPE_PEER : IWL_STA_LINK; - -	ret = iwl_mvm_allocate_int_sta(mvm, sta, 0, -				       NL80211_IFTYPE_UNSPECIFIED, type); -	if (ret) -		return ret; - -	if (mld) -		ret = iwl_mvm_mld_add_int_sta_with_queue(mvm, sta, addr, -							 mvmvif->deflink.fw_link_id, -							 &queue, -							 IWL_MAX_TID_COUNT, -							 &wdg_timeout); -	else -		ret = iwl_mvm_add_int_sta_with_queue(mvm, mvmvif->id, -						     mvmvif->color, addr, sta, -						     &queue, -						     IWL_MVM_TX_FIFO_BE); -	if (ret) -		goto out; - -	keyconf->cipher = cipher; -	memcpy(keyconf->key, key, key_len); -	keyconf->keylen = key_len; -	keyconf->flags = IEEE80211_KEY_FLAG_PAIRWISE; - -	if (mld) { -		/* The MFP flag is set according to the station mfp field. Since -		 * we don't have a station, set it manually. -		 */ -		u32 key_flags = -			iwl_mvm_get_sec_flags(mvm, vif, NULL, keyconf) | -			IWL_SEC_KEY_FLAG_MFP; -		u32 sta_mask = BIT(sta->sta_id); - -		ret = iwl_mvm_mld_send_key(mvm, sta_mask, key_flags, keyconf); -	} else { -		ret = iwl_mvm_send_sta_key(mvm, sta->sta_id, keyconf, false, -					   0, NULL, 0, 0, true); -	} - -out: -	if (ret) -		iwl_mvm_dealloc_int_sta(mvm, sta); -	return ret; -} -#endif -  void iwl_mvm_cancel_channel_switch(struct iwl_mvm *mvm,  				   struct ieee80211_vif *vif,  				   u32 id) @@ -4465,10 +4399,10 @@ void iwl_mvm_count_mpdu(struct iwl_mvm_sta *mvm_sta, u8 fw_sta_id, u32 count,  		       sizeof(queue_counter->per_link));  		queue_counter->window_start = jiffies; -		IWL_DEBUG_STATS(mvm, "MPDU counters are cleared\n"); +		IWL_DEBUG_INFO(mvm, "MPDU counters are cleared\n");  	} -	for (int i = 0; i < IWL_MVM_FW_MAX_LINK_ID; i++) +	for (int i = 0; i < IWL_FW_MAX_LINK_ID; i++)  		total_mpdus += tx ? queue_counter->per_link[i].tx :  				    queue_counter->per_link[i].rx; diff --git a/sys/contrib/dev/iwlwifi/mvm/sta.h b/sys/contrib/dev/iwlwifi/mvm/sta.h index c1050fed0cc6..f6906061510b 100644 --- a/sys/contrib/dev/iwlwifi/mvm/sta.h +++ b/sys/contrib/dev/iwlwifi/mvm/sta.h @@ -1,6 +1,6 @@  /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */  /* - * Copyright (C) 2012-2014, 2018-2024 Intel Corporation + * Copyright (C) 2012-2014, 2018-2025 Intel Corporation   * Copyright (C) 2013-2014 Intel Mobile Communications GmbH   * Copyright (C) 2015-2016 Intel Deutschland GmbH   */ @@ -12,7 +12,7 @@  #include <linux/wait.h>  #include "iwl-trans.h" /* for IWL_MAX_TID_COUNT */ -#include "fw-api.h" /* IWL_MVM_STATION_COUNT_MAX */ +#include "fw-api.h" /* IWL_STATION_COUNT_MAX */  #include "rs.h"  struct iwl_mvm; @@ -133,7 +133,7 @@ struct iwl_mvm_vif;   * and no TID data as this is also not needed.   * One thing to note, is that these stations have an ID in the fw, but not   * in mac80211. In order to "reserve" them a sta_id in %fw_id_to_mac_id - * we fill ERR_PTR(EINVAL) in this mapping and all other dereferencing of + * we fill ERR_PTR(-EINVAL) in this mapping and all other dereferencing of   * pointers from this mapping need to check that the value is not error   * or NULL.   * @@ -214,7 +214,7 @@ struct iwl_mvm_vif;   */  /** - * enum iwl_mvm_agg_state + * enum iwl_mvm_agg_state - aggregation session state   *   * The state machine of the BA agreement establishment / tear down.   * These states relate to a specific RA / TID. @@ -225,8 +225,6 @@ struct iwl_mvm_vif;   * @IWL_AGG_ON: aggregation session is up   * @IWL_EMPTYING_HW_QUEUE_ADDBA: establishing a BA session - waiting for the   *	HW queue to be empty from packets for this RA /TID. - * @IWL_EMPTYING_HW_QUEUE_DELBA: tearing down a BA session - waiting for the - *	HW queue to be empty from packets for this RA /TID.   */  enum iwl_mvm_agg_state {  	IWL_AGG_OFF = 0, @@ -234,7 +232,6 @@ enum iwl_mvm_agg_state {  	IWL_AGG_STARTING,  	IWL_AGG_ON,  	IWL_EMPTYING_HW_QUEUE_ADDBA, -	IWL_EMPTYING_HW_QUEUE_DELBA,  };  /** @@ -262,7 +259,7 @@ struct iwl_mvm_tid_data {  	u16 seq_number;  	u16 next_reclaimed;  	/* The rest is Tx AGG related */ -	u32 rate_n_flags; +	__le32 rate_n_flags;  	u8 lq_color;  	bool amsdu_in_ampdu_allowed;  	enum iwl_mvm_agg_state state; @@ -361,7 +358,7 @@ struct iwl_mvm_mpdu_counter {   */  struct iwl_mvm_tpt_counter {  	spinlock_t lock; -	struct iwl_mvm_mpdu_counter per_link[IWL_MVM_FW_MAX_LINK_ID]; +	struct iwl_mvm_mpdu_counter per_link[IWL_FW_MAX_LINK_ID];  	unsigned long window_start;  } ____cacheline_aligned_in_smp; @@ -486,6 +483,7 @@ struct iwl_mvm_int_sta {   *	about. Otherwise (if this is a new STA), this should be false.   * @flags: if update==true, this marks what is being changed via ORs of values   *	from enum iwl_sta_modify_flag. Otherwise, this is ignored. + * Return: negative error code or 0 on success   */  int iwl_mvm_sta_send_to_fw(struct iwl_mvm *mvm, struct ieee80211_sta *sta,  			   bool update, unsigned int flags); @@ -507,9 +505,9 @@ void iwl_mvm_realloc_queues_after_restart(struct iwl_mvm *mvm,  					  struct ieee80211_sta *sta);  int iwl_mvm_wait_sta_queues_empty(struct iwl_mvm *mvm,  				  struct iwl_mvm_sta *mvm_sta); -bool iwl_mvm_sta_del(struct iwl_mvm *mvm, struct ieee80211_vif *vif, +void iwl_mvm_sta_del(struct iwl_mvm *mvm, struct ieee80211_vif *vif,  		     struct ieee80211_sta *sta, -		     struct ieee80211_link_sta *link_sta, int *ret); +		     struct ieee80211_link_sta *link_sta);  int iwl_mvm_rm_sta(struct iwl_mvm *mvm,  		   struct ieee80211_vif *vif,  		   struct ieee80211_sta *sta); @@ -597,12 +595,6 @@ void iwl_mvm_modify_all_sta_disable_tx(struct iwl_mvm *mvm,  void iwl_mvm_csa_client_absent(struct iwl_mvm *mvm, struct ieee80211_vif *vif);  int iwl_mvm_sta_ensure_queue(struct iwl_mvm *mvm, struct ieee80211_txq *txq);  void iwl_mvm_add_new_dqa_stream_wk(struct work_struct *wk); -#if defined(__linux__) -int iwl_mvm_add_pasn_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif, -			 struct iwl_mvm_int_sta *sta, u8 *addr, u32 cipher, -			 u8 *key, u32 key_len, -			 struct ieee80211_key_conf *key_conf_out); -#endif  void iwl_mvm_cancel_channel_switch(struct iwl_mvm *mvm,  				   struct ieee80211_vif *vif,  				   u32 id); @@ -667,8 +659,7 @@ int iwl_mvm_mld_rm_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,  void iwl_mvm_mld_free_sta_link(struct iwl_mvm *mvm,  			       struct iwl_mvm_sta *mvm_sta,  			       struct iwl_mvm_link_sta *mvm_sta_link, -			       unsigned int link_id, -			       bool is_in_fw); +			       unsigned int link_id);  int iwl_mvm_mld_rm_sta_id(struct iwl_mvm *mvm, u8 sta_id);  int iwl_mvm_mld_update_sta_links(struct iwl_mvm *mvm,  				 struct ieee80211_vif *vif, diff --git a/sys/contrib/dev/iwlwifi/mvm/tdls.c b/sys/contrib/dev/iwlwifi/mvm/tdls.c index 5977aa8b51bb..9a250b407f3a 100644 --- a/sys/contrib/dev/iwlwifi/mvm/tdls.c +++ b/sys/contrib/dev/iwlwifi/mvm/tdls.c @@ -27,7 +27,7 @@ void iwl_mvm_teardown_tdls_peers(struct iwl_mvm *mvm)  	for (i = 0; i < mvm->fw->ucode_capa.num_stations; i++) {  		sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i],  						lockdep_is_held(&mvm->mutex)); -		if (!sta || IS_ERR(sta) || !sta->tdls) +		if (IS_ERR_OR_NULL(sta) || !sta->tdls)  			continue;  		mvmsta = iwl_mvm_sta_from_mac80211(sta); @@ -50,7 +50,7 @@ int iwl_mvm_tdls_sta_count(struct iwl_mvm *mvm, struct ieee80211_vif *vif)  	for (i = 0; i < mvm->fw->ucode_capa.num_stations; i++) {  		sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i],  						lockdep_is_held(&mvm->mutex)); -		if (!sta || IS_ERR(sta) || !sta->tdls) +		if (IS_ERR_OR_NULL(sta) || !sta->tdls)  			continue;  		if (vif) { @@ -199,7 +199,7 @@ static void iwl_mvm_tdls_update_cs_state(struct iwl_mvm *mvm,  		mvm->tdls_cs.peer.sent_timestamp = iwl_mvm_get_systime(mvm);  	if (state == IWL_MVM_TDLS_SW_IDLE) -		mvm->tdls_cs.cur_sta_id = IWL_MVM_INVALID_STA; +		mvm->tdls_cs.cur_sta_id = IWL_INVALID_STA;  }  void iwl_mvm_rx_tdls_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) @@ -253,7 +253,7 @@ iwl_mvm_tdls_check_action(struct iwl_mvm *mvm,  	/* get the existing peer if it's there */  	if (mvm->tdls_cs.state != IWL_MVM_TDLS_SW_IDLE && -	    mvm->tdls_cs.cur_sta_id != IWL_MVM_INVALID_STA) { +	    mvm->tdls_cs.cur_sta_id != IWL_INVALID_STA) {  		struct ieee80211_sta *sta = rcu_dereference_protected(  				mvm->fw_id_to_mac_id[mvm->tdls_cs.cur_sta_id],  				lockdep_is_held(&mvm->mutex)); @@ -468,14 +468,14 @@ void iwl_mvm_tdls_ch_switch_work(struct work_struct *work)  	iwl_mvm_tdls_update_cs_state(mvm, IWL_MVM_TDLS_SW_IDLE);  	/* station might be gone, in that case do nothing */ -	if (mvm->tdls_cs.peer.sta_id == IWL_MVM_INVALID_STA) +	if (mvm->tdls_cs.peer.sta_id == IWL_INVALID_STA)  		return;  	sta = rcu_dereference_protected(  				mvm->fw_id_to_mac_id[mvm->tdls_cs.peer.sta_id],  				lockdep_is_held(&mvm->mutex));  	/* the station may not be here, but if it is, it must be a TDLS peer */ -	if (!sta || IS_ERR(sta) || WARN_ON(!sta->tdls)) +	if (IS_ERR_OR_NULL(sta) || WARN_ON(!sta->tdls))  		return;  	mvmsta = iwl_mvm_sta_from_mac80211(sta); @@ -515,7 +515,7 @@ iwl_mvm_tdls_channel_switch(struct ieee80211_hw *hw,  		       sta->addr, chandef->chan->center_freq, chandef->width);  	/* we only support a single peer for channel switching */ -	if (mvm->tdls_cs.peer.sta_id != IWL_MVM_INVALID_STA) { +	if (mvm->tdls_cs.peer.sta_id != IWL_INVALID_STA) {  		IWL_DEBUG_TDLS(mvm,  			       "Existing peer. Can't start switch with %pM\n",  			       sta->addr); @@ -569,7 +569,7 @@ void iwl_mvm_tdls_cancel_channel_switch(struct ieee80211_hw *hw,  	IWL_DEBUG_TDLS(mvm, "TDLS cancel channel switch with %pM\n", sta->addr);  	/* we only support a single peer for channel switching */ -	if (mvm->tdls_cs.peer.sta_id == IWL_MVM_INVALID_STA) { +	if (mvm->tdls_cs.peer.sta_id == IWL_INVALID_STA) {  		IWL_DEBUG_TDLS(mvm, "No ch switch peer - %pM\n", sta->addr);  		goto out;  	} @@ -590,7 +590,7 @@ void iwl_mvm_tdls_cancel_channel_switch(struct ieee80211_hw *hw,  	    mvm->tdls_cs.state != IWL_MVM_TDLS_SW_IDLE)  		wait_for_phy = true; -	mvm->tdls_cs.peer.sta_id = IWL_MVM_INVALID_STA; +	mvm->tdls_cs.peer.sta_id = IWL_INVALID_STA;  	dev_kfree_skb(mvm->tdls_cs.peer.skb);  	mvm->tdls_cs.peer.skb = NULL; @@ -637,7 +637,7 @@ iwl_mvm_tdls_recv_channel_switch(struct ieee80211_hw *hw,  	if (params->action_code == WLAN_TDLS_CHANNEL_SWITCH_RESPONSE &&  	    params->status != 0 &&  	    mvm->tdls_cs.state == IWL_MVM_TDLS_SW_REQ_SENT && -	    mvm->tdls_cs.cur_sta_id != IWL_MVM_INVALID_STA) { +	    mvm->tdls_cs.cur_sta_id != IWL_INVALID_STA) {  		struct ieee80211_sta *cur_sta;  		/* make sure it's the same peer */ diff --git a/sys/contrib/dev/iwlwifi/mvm/tests/hcmd.c b/sys/contrib/dev/iwlwifi/mvm/tests/hcmd.c new file mode 100644 index 000000000000..1fee0320c756 --- /dev/null +++ b/sys/contrib/dev/iwlwifi/mvm/tests/hcmd.c @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* + * KUnit tests for channel helper functions + * + * Copyright (C) 2025 Intel Corporation + */ +#include <kunit/test.h> + +#include <iwl-trans.h> +#include "../mvm.h" + +MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING"); + +static void test_hcmd_names_sorted(struct kunit *test) +{ +	for (int i = 0; i < iwl_mvm_groups_size; i++) { +		const struct iwl_hcmd_arr *arr = &iwl_mvm_groups[i]; + +		if (!arr->arr) +			continue; + +		for (int j = 0; j < arr->size - 1; j++) +			KUNIT_EXPECT_LE(test, arr->arr[j].cmd_id, +					arr->arr[j + 1].cmd_id); +	} +} + +static struct kunit_case hcmd_names_cases[] = { +	KUNIT_CASE(test_hcmd_names_sorted), +	{}, +}; + +static struct kunit_suite hcmd_names = { +	.name = "iwlmvm-hcmd-names", +	.test_cases = hcmd_names_cases, +}; + +kunit_test_suite(hcmd_names); diff --git a/sys/contrib/dev/iwlwifi/mvm/time-event.c b/sys/contrib/dev/iwlwifi/mvm/time-event.c index a8c42ce3b630..aa653782d6d7 100644 --- a/sys/contrib/dev/iwlwifi/mvm/time-event.c +++ b/sys/contrib/dev/iwlwifi/mvm/time-event.c @@ -1,6 +1,6 @@  // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause  /* - * Copyright (C) 2012-2014, 2018-2024 Intel Corporation + * Copyright (C) 2012-2014, 2018-2025 Intel Corporation   * Copyright (C) 2013-2015 Intel Mobile Communications GmbH   * Copyright (C) 2017 Intel Deutschland GmbH   */ @@ -114,16 +114,14 @@ static void iwl_mvm_cleanup_roc(struct iwl_mvm *mvm)  		iwl_mvm_flush_sta(mvm, mvm->aux_sta.sta_id,  				  mvm->aux_sta.tfd_queue_msk); -		if (mvm->mld_api_is_used) { -			iwl_mvm_mld_rm_aux_sta(mvm); -			mutex_unlock(&mvm->mutex); -			return; -		} -  		/* In newer version of this command an aux station is added only  		 * in cases of dedicated tx queue and need to be removed in end -		 * of use */ -		if (iwl_mvm_has_new_station_api(mvm->fw)) +		 * of use. For the even newer mld api, use the appropriate +		 * function. +		 */ +		if (mvm->mld_api_is_used) +			iwl_mvm_mld_rm_aux_sta(mvm); +		else if (iwl_mvm_has_new_station_api(mvm->fw))  			iwl_mvm_rm_aux_sta(mvm);  	} @@ -753,7 +751,7 @@ static void iwl_mvm_cancel_session_protection(struct iwl_mvm *mvm,  					      u32 id, s8 link_id)  {  	int mac_link_id = iwl_mvm_get_session_prot_id(mvm, vif, link_id); -	struct iwl_mvm_session_prot_cmd cmd = { +	struct iwl_session_prot_cmd cmd = {  		.id_and_color = cpu_to_le32(mac_link_id),  		.action = cpu_to_le32(FW_CTXT_ACTION_REMOVE),  		.conf_id = cpu_to_le32(id), @@ -777,11 +775,13 @@ static void iwl_mvm_roc_rm_cmd(struct iwl_mvm *mvm, u32 activity)  		.action = cpu_to_le32(FW_CTXT_ACTION_REMOVE),  		.activity = cpu_to_le32(activity),  	}; +	u8 ver = iwl_fw_lookup_cmd_ver(mvm->fw, WIDE_ID(MAC_CONF_GROUP, ROC_CMD), 0); +	u16 cmd_len = ver < 6 ? sizeof(struct iwl_roc_req_v5) : sizeof(roc_cmd);  	int ret;  	lockdep_assert_held(&mvm->mutex);  	ret = iwl_mvm_send_cmd_pdu(mvm, WIDE_ID(MAC_CONF_GROUP, ROC_CMD), 0, -				   sizeof(roc_cmd), &roc_cmd); +				   cmd_len, &roc_cmd);  	if (ret)  		IWL_ERR(mvm, "Couldn't send the ROC_CMD: %d\n", ret);  } @@ -957,41 +957,20 @@ void iwl_mvm_rx_session_protect_notif(struct iwl_mvm *mvm,  				      struct iwl_rx_cmd_buffer *rxb)  {  	struct iwl_rx_packet *pkt = rxb_addr(rxb); -	struct iwl_mvm_session_prot_notif *notif = (void *)pkt->data; -	unsigned int ver = -		iwl_fw_lookup_notif_ver(mvm->fw, MAC_CONF_GROUP, -					SESSION_PROTECTION_NOTIF, 2); +	struct iwl_session_prot_notif *notif = (void *)pkt->data;  	int id = le32_to_cpu(notif->mac_link_id);  	struct ieee80211_vif *vif;  	struct iwl_mvm_vif *mvmvif; -	unsigned int notif_link_id;  	rcu_read_lock(); -	if (ver <= 2) { -		vif = iwl_mvm_rcu_dereference_vif_id(mvm, id, true); -	} else { -		struct ieee80211_bss_conf *link_conf = -			iwl_mvm_rcu_fw_link_id_to_link_conf(mvm, id, true); - -		if (!link_conf) -			goto out_unlock; - -		notif_link_id = link_conf->link_id; -		vif = link_conf->vif; -	} - +	/* note we use link ID == MAC ID */ +	vif = iwl_mvm_rcu_dereference_vif_id(mvm, id, true);  	if (!vif)  		goto out_unlock;  	mvmvif = iwl_mvm_vif_from_mac80211(vif); -	if (WARN(ver > 2 && mvmvif->time_event_data.link_id >= 0 && -		 mvmvif->time_event_data.link_id != notif_link_id, -		 "SESSION_PROTECTION_NOTIF was received for link %u, while the current time event is on link %u\n", -		 notif_link_id, mvmvif->time_event_data.link_id)) -		goto out_unlock; -  	/* The vif is not a P2P_DEVICE, maintain its time_event_data */  	if (vif->type != NL80211_IFTYPE_P2P_DEVICE) {  		struct iwl_mvm_time_event_data *te_data = @@ -1032,6 +1011,8 @@ void iwl_mvm_rx_session_protect_notif(struct iwl_mvm *mvm,  		/* End TE, notify mac80211 */  		mvmvif->time_event_data.id = SESSION_PROTECT_CONF_MAX_ID;  		mvmvif->time_event_data.link_id = -1; +		/* set the bit so the ROC cleanup will actually clean up */ +		set_bit(IWL_MVM_STATUS_ROC_P2P_RUNNING, &mvm->status);  		iwl_mvm_roc_finished(mvm);  		ieee80211_remain_on_channel_expired(mvm->hw);  	} else if (le32_to_cpu(notif->start)) { @@ -1107,6 +1088,8 @@ int iwl_mvm_roc_add_cmd(struct iwl_mvm *mvm,  		.activity = cpu_to_le32(activity),  		.sta_id = cpu_to_le32(mvm->aux_sta.sta_id),  	}; +	u8 ver = iwl_fw_lookup_cmd_ver(mvm->fw, WIDE_ID(MAC_CONF_GROUP, ROC_CMD), 0); +	u16 cmd_len = ver < 6 ? sizeof(struct iwl_roc_req_v5) : sizeof(roc_req);  	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);  	lockdep_assert_held(&mvm->mutex); @@ -1136,7 +1119,7 @@ int iwl_mvm_roc_add_cmd(struct iwl_mvm *mvm,  	memcpy(roc_req.node_addr, vif->addr, ETH_ALEN);  	res = iwl_mvm_send_cmd_pdu(mvm, WIDE_ID(MAC_CONF_GROUP, ROC_CMD), -				   0, sizeof(roc_req), &roc_req); +				   0, cmd_len, &roc_req);  	if (!res)  		mvmvif->roc_activity = activity; @@ -1150,7 +1133,7 @@ iwl_mvm_start_p2p_roc_session_protection(struct iwl_mvm *mvm,  					 enum ieee80211_roc_type type)  {  	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); -	struct iwl_mvm_session_prot_cmd cmd = { +	struct iwl_session_prot_cmd cmd = {  		.id_and_color =  			cpu_to_le32(iwl_mvm_get_session_prot_id(mvm, vif, 0)),  		.action = cpu_to_le32(FW_CTXT_ACTION_ADD), @@ -1419,7 +1402,7 @@ static bool iwl_mvm_session_prot_notif(struct iwl_notif_wait_data *notif_wait,  {  	struct iwl_mvm *mvm =  		container_of(notif_wait, struct iwl_mvm, notif_wait); -	struct iwl_mvm_session_prot_notif *resp; +	struct iwl_session_prot_notif *resp;  	int resp_len = iwl_rx_packet_payload_len(pkt);  	if (WARN_ON(pkt->hdr.cmd != SESSION_PROTECTION_NOTIF || @@ -1451,7 +1434,7 @@ void iwl_mvm_schedule_session_protection(struct iwl_mvm *mvm,  	const u16 notif[] = { WIDE_ID(MAC_CONF_GROUP, SESSION_PROTECTION_NOTIF) };  	struct iwl_notification_wait wait_notif;  	int mac_link_id = iwl_mvm_get_session_prot_id(mvm, vif, (s8)link_id); -	struct iwl_mvm_session_prot_cmd cmd = { +	struct iwl_session_prot_cmd cmd = {  		.id_and_color = cpu_to_le32(mac_link_id),  		.action = cpu_to_le32(FW_CTXT_ACTION_ADD),  		.conf_id = cpu_to_le32(SESSION_PROTECT_CONF_ASSOC), diff --git a/sys/contrib/dev/iwlwifi/mvm/time-event.h b/sys/contrib/dev/iwlwifi/mvm/time-event.h index 49256ba4cf58..1ef8768756db 100644 --- a/sys/contrib/dev/iwlwifi/mvm/time-event.h +++ b/sys/contrib/dev/iwlwifi/mvm/time-event.h @@ -1,6 +1,6 @@  /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */  /* - * Copyright (C) 2012-2014, 2019-2020, 2023 Intel Corporation + * Copyright (C) 2012-2014, 2019-2020, 2023, 2025 Intel Corporation   * Copyright (C) 2013-2014 Intel Mobile Communications GmbH   */  #ifndef __time_event_h__ @@ -124,6 +124,8 @@ void iwl_mvm_rx_roc_notif(struct iwl_mvm *mvm,   * ROC request, it will issue a notification to the driver that it is on the   * requested channel. Once the FW completes the ROC request it will issue   * another notification to the driver. + * + * Return: negative error code or 0 on success   */  int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif,  			  int duration, enum ieee80211_roc_type type); @@ -179,6 +181,8 @@ void iwl_mvm_remove_csa_period(struct iwl_mvm *mvm,   *   * This function is used to schedule NoA time event and is used to perform   * the channel switch flow. + * + * Return: negative error code or 0 on success   */  int iwl_mvm_schedule_csa_period(struct iwl_mvm *mvm,  				struct ieee80211_vif *vif, @@ -188,7 +192,7 @@ int iwl_mvm_schedule_csa_period(struct iwl_mvm *mvm,   * iwl_mvm_te_scheduled - check if the fw received the TE cmd   * @te_data: the time event data that corresponds to that time event   * - * This function returns true iff this TE is added to the fw. + * Return: %true if this TE is added to the fw, %false otherwise   */  static inline bool  iwl_mvm_te_scheduled(struct iwl_mvm_time_event_data *te_data) diff --git a/sys/contrib/dev/iwlwifi/mvm/tt.c b/sys/contrib/dev/iwlwifi/mvm/tt.c index 95a5856cd239..1958f4ca4773 100644 --- a/sys/contrib/dev/iwlwifi/mvm/tt.c +++ b/sys/contrib/dev/iwlwifi/mvm/tt.c @@ -1,6 +1,6 @@  // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause  /* - * Copyright (C) 2012-2014, 2019-2022, 2024 Intel Corporation + * Copyright (C) 2012-2014, 2019-2022, 2024-2025 Intel Corporation   * Copyright (C) 2013-2014 Intel Mobile Communications GmbH   * Copyright (C) 2015-2016 Intel Deutschland GmbH   */ @@ -10,6 +10,9 @@  #include "mvm.h" +#define IWL_MVM_NUM_CTDP_STEPS		20 +#define IWL_MVM_MIN_CTDP_BUDGET_MW	150 +  #define IWL_MVM_TEMP_NOTIF_WAIT_TIMEOUT	HZ  void iwl_mvm_enter_ctkill(struct iwl_mvm *mvm) @@ -107,7 +110,7 @@ static bool iwl_mvm_temp_notif_wait(struct iwl_notif_wait_data *notif_wait,  void iwl_mvm_temp_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb)  {  	struct iwl_rx_packet *pkt = rxb_addr(rxb); -	struct iwl_dts_measurement_notif_v2 *notif_v2; +	struct iwl_dts_measurement_notif *notif_v2;  	int len = iwl_rx_packet_payload_len(pkt);  	int temp;  	u32 ths_crossed; @@ -481,43 +484,28 @@ static const struct iwl_tt_params iwl_mvm_default_tt_params = {  	.support_tx_backoff = true,  }; -/* budget in mWatt */ -static const u32 iwl_mvm_cdev_budgets[] = { -	2400,	/* cooling state 0 */ -	2000,	/* cooling state 1 */ -	1800,	/* cooling state 2 */ -	1600,	/* cooling state 3 */ -	1400,	/* cooling state 4 */ -	1200,	/* cooling state 5 */ -	1000,	/* cooling state 6 */ -	900,	/* cooling state 7 */ -	800,	/* cooling state 8 */ -	700,	/* cooling state 9 */ -	650,	/* cooling state 10 */ -	600,	/* cooling state 11 */ -	550,	/* cooling state 12 */ -	500,	/* cooling state 13 */ -	450,	/* cooling state 14 */ -	400,	/* cooling state 15 */ -	350,	/* cooling state 16 */ -	300,	/* cooling state 17 */ -	250,	/* cooling state 18 */ -	200,	/* cooling state 19 */ -	150,	/* cooling state 20 */ -}; -  int iwl_mvm_ctdp_command(struct iwl_mvm *mvm, u32 op, u32 state)  { -	struct iwl_mvm_ctdp_cmd cmd = { +	struct iwl_ctdp_cmd cmd = {  		.operation = cpu_to_le32(op), -		.budget = cpu_to_le32(iwl_mvm_cdev_budgets[state]),  		.window_size = 0,  	}; +	u32 budget;  	int ret;  	u32 status;  	lockdep_assert_held(&mvm->mutex); +	/* Do a linear scale from IWL_MVM_MIN_CTDP_BUDGET_MW to the configured +	 * maximum in the predefined number of steps. +	 */ +	budget = ((mvm->thermal_throttle.power_budget_mw - +		   IWL_MVM_MIN_CTDP_BUDGET_MW) * +		  (IWL_MVM_NUM_CTDP_STEPS - 1 - state)) / +		 (IWL_MVM_NUM_CTDP_STEPS - 1) + +		 IWL_MVM_MIN_CTDP_BUDGET_MW; +	cmd.budget = cpu_to_le32(budget); +  	status = 0;  	ret = iwl_mvm_send_cmd_pdu_status(mvm, WIDE_ID(PHY_OPS_GROUP,  						       CTDP_CONFIG_CMD), @@ -554,8 +542,8 @@ int iwl_mvm_ctdp_command(struct iwl_mvm *mvm, u32 op, u32 state)  #ifdef CONFIG_THERMAL  static int compare_temps(const void *a, const void *b)  { -	return ((s16)le16_to_cpu(*(__le16 *)a) - -		(s16)le16_to_cpu(*(__le16 *)b)); +	return ((s16)le16_to_cpu(*(const __le16 *)a) - +		(s16)le16_to_cpu(*(const __le16 *)b));  }  struct iwl_trip_walk_data { @@ -709,7 +697,7 @@ static void iwl_mvm_thermal_zone_register(struct iwl_mvm *mvm)  static int iwl_mvm_tcool_get_max_state(struct thermal_cooling_device *cdev,  				       unsigned long *state)  { -	*state = ARRAY_SIZE(iwl_mvm_cdev_budgets) - 1; +	*state = IWL_MVM_NUM_CTDP_STEPS - 1;  	return 0;  } @@ -735,7 +723,7 @@ static int iwl_mvm_tcool_set_cur_state(struct thermal_cooling_device *cdev,  	    mvm->fwrt.cur_fw_img != IWL_UCODE_REGULAR)  		return -EIO; -	if (new_state >= ARRAY_SIZE(iwl_mvm_cdev_budgets)) +	if (new_state >= IWL_MVM_NUM_CTDP_STEPS)  		return -EINVAL;  	return iwl_mvm_ctdp_command(mvm, CTDP_CMD_OPERATION_START, @@ -796,6 +784,47 @@ static void iwl_mvm_cooling_device_unregister(struct iwl_mvm *mvm)  }  #endif /* CONFIG_THERMAL */ +static u32 iwl_mvm_ctdp_get_max_budget(struct iwl_mvm *mvm) +{ +	u64 bios_power_budget = 0; +	u32 default_power_budget; + +	switch (CSR_HW_RFID_TYPE(mvm->trans->info.hw_rf_id)) { +	case IWL_CFG_RF_TYPE_JF2: +	case IWL_CFG_RF_TYPE_JF1: +		default_power_budget = 2000; +		break; +	case IWL_CFG_RF_TYPE_HR2: +	case IWL_CFG_RF_TYPE_HR1: +		default_power_budget = 2400; +		break; +	case IWL_CFG_RF_TYPE_GF: +		/* dual-radio devices have a higher budget */ +		if (CSR_HW_RFID_IS_CDB(mvm->trans->info.hw_rf_id)) +			default_power_budget = 5200; +		else +			default_power_budget = 2880; +		break; +	case IWL_CFG_RF_TYPE_FM: +		default_power_budget = 3450; +		break; +	default: +		default_power_budget = 5550; +		break; +	} + +	iwl_bios_get_pwr_limit(&mvm->fwrt, &bios_power_budget); + +	/* 32bit in UEFI, 16bit in ACPI; use BIOS value if it is in range */ +	if (bios_power_budget && +	    bios_power_budget != 0xffff && bios_power_budget != 0xffffffff && +	    bios_power_budget >= IWL_MVM_MIN_CTDP_BUDGET_MW && +	    bios_power_budget <= default_power_budget) +		return (u32)bios_power_budget; + +	return default_power_budget; +} +  void iwl_mvm_thermal_initialize(struct iwl_mvm *mvm, u32 min_backoff)  {  	struct iwl_mvm_tt_mgmt *tt = &mvm->thermal_throttle; @@ -807,6 +836,8 @@ void iwl_mvm_thermal_initialize(struct iwl_mvm *mvm, u32 min_backoff)  	else  		tt->params = iwl_mvm_default_tt_params; +	tt->power_budget_mw = iwl_mvm_ctdp_get_max_budget(mvm); +	IWL_DEBUG_TEMP(mvm, "cTDP power budget: %d mW\n", tt->power_budget_mw);  	tt->throttle = false;  	tt->dynamic_smps = false;  	tt->min_backoff = min_backoff; diff --git a/sys/contrib/dev/iwlwifi/mvm/tx.c b/sys/contrib/dev/iwlwifi/mvm/tx.c index fbbed0bd7678..2b6052a6f90a 100644 --- a/sys/contrib/dev/iwlwifi/mvm/tx.c +++ b/sys/contrib/dev/iwlwifi/mvm/tx.c @@ -1,6 +1,6 @@  // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause  /* - * Copyright (C) 2012-2014, 2018-2024 Intel Corporation + * Copyright (C) 2012-2014, 2018-2025 Intel Corporation   * Copyright (C) 2013-2015 Intel Mobile Communications GmbH   * Copyright (C) 2016-2017 Intel Deutschland GmbH   */ @@ -13,6 +13,7 @@  #include "iwl-trans.h"  #include "iwl-nvm-utils.h" +#include "iwl-utils.h"  #include "mvm.h"  #include "sta.h"  #include "time-sync.h" @@ -147,12 +148,12 @@ out:   * Sets most of the Tx cmd's fields   */  void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb, -			struct iwl_tx_cmd *tx_cmd, +			struct iwl_tx_cmd_v6_params *tx_cmd_params,  			struct ieee80211_tx_info *info, u8 sta_id)  {  	struct ieee80211_hdr *hdr = (void *)skb->data;  	__le16 fc = hdr->frame_control; -	u32 tx_flags = le32_to_cpu(tx_cmd->tx_flags); +	u32 tx_flags = le32_to_cpu(tx_cmd_params->tx_flags);  	u32 len = skb->len + FCS_LEN;  	bool amsdu = false;  	u8 ac; @@ -172,7 +173,7 @@ void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb,  	if (ieee80211_is_data_qos(fc)) {  		u8 *qc = ieee80211_get_qos_ctl(hdr); -		tx_cmd->tid_tspec = qc[0] & 0xf; +		tx_cmd_params->tid_tspec = qc[0] & 0xf;  		tx_flags &= ~TX_CMD_FLG_SEQ_CTL;  		amsdu = *qc & IEEE80211_QOS_CTL_A_MSDU_PRESENT;  	} else if (ieee80211_is_back_req(fc)) { @@ -181,17 +182,17 @@ void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb,  		u16 ssn = le16_to_cpu(bar->start_seq_num);  		tx_flags |= TX_CMD_FLG_ACK | TX_CMD_FLG_BAR; -		tx_cmd->tid_tspec = (control & +		tx_cmd_params->tid_tspec = (control &  				     IEEE80211_BAR_CTRL_TID_INFO_MASK) >>  			IEEE80211_BAR_CTRL_TID_INFO_SHIFT; -		WARN_ON_ONCE(tx_cmd->tid_tspec >= IWL_MAX_TID_COUNT); -		iwl_mvm_bar_check_trigger(mvm, bar->ra, tx_cmd->tid_tspec, +		WARN_ON_ONCE(tx_cmd_params->tid_tspec >= IWL_MAX_TID_COUNT); +		iwl_mvm_bar_check_trigger(mvm, bar->ra, tx_cmd_params->tid_tspec,  					  ssn);  	} else {  		if (ieee80211_is_data(fc)) -			tx_cmd->tid_tspec = IWL_TID_NON_QOS; +			tx_cmd_params->tid_tspec = IWL_TID_NON_QOS;  		else -			tx_cmd->tid_tspec = IWL_MAX_TID_COUNT; +			tx_cmd_params->tid_tspec = IWL_MAX_TID_COUNT;  		if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ)  			tx_flags |= TX_CMD_FLG_SEQ_CTL; @@ -200,8 +201,8 @@ void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb,  	}  	/* Default to 0 (BE) when tid_spec is set to IWL_MAX_TID_COUNT */ -	if (tx_cmd->tid_tspec < IWL_MAX_TID_COUNT) -		ac = tid_to_mac80211_ac[tx_cmd->tid_tspec]; +	if (tx_cmd_params->tid_tspec < IWL_MAX_TID_COUNT) +		ac = tid_to_mac80211_ac[tx_cmd_params->tid_tspec];  	else  		ac = tid_to_mac80211_ac[0]; @@ -210,20 +211,20 @@ void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb,  	if (ieee80211_is_mgmt(fc)) {  		if (ieee80211_is_assoc_req(fc) || ieee80211_is_reassoc_req(fc)) -			tx_cmd->pm_frame_timeout = cpu_to_le16(PM_FRAME_ASSOC); +			tx_cmd_params->pm_frame_timeout = cpu_to_le16(PM_FRAME_ASSOC);  		else if (ieee80211_is_action(fc)) -			tx_cmd->pm_frame_timeout = cpu_to_le16(PM_FRAME_NONE); +			tx_cmd_params->pm_frame_timeout = cpu_to_le16(PM_FRAME_NONE);  		else -			tx_cmd->pm_frame_timeout = cpu_to_le16(PM_FRAME_MGMT); +			tx_cmd_params->pm_frame_timeout = cpu_to_le16(PM_FRAME_MGMT);  		/* The spec allows Action frames in A-MPDU, we don't support  		 * it  		 */  		WARN_ON_ONCE(info->flags & IEEE80211_TX_CTL_AMPDU);  	} else if (info->control.flags & IEEE80211_TX_CTRL_PORT_CTRL_PROTO) { -		tx_cmd->pm_frame_timeout = cpu_to_le16(PM_FRAME_MGMT); +		tx_cmd_params->pm_frame_timeout = cpu_to_le16(PM_FRAME_MGMT);  	} else { -		tx_cmd->pm_frame_timeout = cpu_to_le16(PM_FRAME_NONE); +		tx_cmd_params->pm_frame_timeout = cpu_to_le16(PM_FRAME_NONE);  	}  	if (ieee80211_is_data(fc) && len > mvm->rts_threshold && @@ -235,13 +236,13 @@ void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb,  	    ieee80211_action_contains_tpc(skb))  		tx_flags |= TX_CMD_FLG_WRITE_TX_POWER; -	tx_cmd->tx_flags = cpu_to_le32(tx_flags); +	tx_cmd_params->tx_flags = cpu_to_le32(tx_flags);  	/* Total # bytes to be transmitted - PCIe code will adjust for A-MSDU */ -	tx_cmd->len = cpu_to_le16((u16)skb->len); -	tx_cmd->life_time = cpu_to_le32(TX_CMD_LIFE_TIME_INFINITE); -	tx_cmd->sta_id = sta_id; +	tx_cmd_params->len = cpu_to_le16((u16)skb->len); +	tx_cmd_params->life_time = cpu_to_le32(TX_CMD_LIFE_TIME_INFINITE); +	tx_cmd_params->sta_id = sta_id; -	tx_cmd->offload_assist = +	tx_cmd_params->offload_assist =  		cpu_to_le16(iwl_mvm_tx_csum(mvm, skb, info, amsdu));  } @@ -282,14 +283,10 @@ static u32 iwl_mvm_convert_rate_idx(struct iwl_mvm *mvm,  		 (rate_idx <= IWL_LAST_CCK_RATE);  	/* Set CCK or OFDM flag */ -	if (iwl_fw_lookup_cmd_ver(mvm->fw, TX_CMD, 0) > 8) { -		if (!is_cck) -			rate_flags |= RATE_MCS_LEGACY_OFDM_MSK; -		else -			rate_flags |= RATE_MCS_CCK_MSK; -	} else if (is_cck) { -		rate_flags |= RATE_MCS_CCK_MSK_V1; -	} +	if (!is_cck) +		rate_flags |= RATE_MCS_MOD_TYPE_LEGACY_OFDM; +	else +		rate_flags |= RATE_MCS_MOD_TYPE_CCK;  	return (u32)rate_plcp | rate_flags;  } @@ -302,45 +299,35 @@ static u32 iwl_mvm_get_inject_tx_rate(struct iwl_mvm *mvm,  	struct ieee80211_tx_rate *rate = &info->control.rates[0];  	u32 result; -	/* -	 * we only care about legacy/HT/VHT so far, so we can -	 * build in v1 and use iwl_new_rate_from_v1() -	 */ -  	if (rate->flags & IEEE80211_TX_RC_VHT_MCS) {  		u8 mcs = ieee80211_rate_get_vht_mcs(rate);  		u8 nss = ieee80211_rate_get_vht_nss(rate); -		result = RATE_MCS_VHT_MSK_V1; +		result = RATE_MCS_MOD_TYPE_VHT;  		result |= u32_encode_bits(mcs, RATE_VHT_MCS_RATE_CODE_MSK);  		result |= u32_encode_bits(nss, RATE_MCS_NSS_MSK);  		if (rate->flags & IEEE80211_TX_RC_SHORT_GI) -			result |= RATE_MCS_SGI_MSK_V1; +			result |= RATE_MCS_SGI_MSK;  		if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) -			result |= u32_encode_bits(1, RATE_MCS_CHAN_WIDTH_MSK_V1); +			result |= RATE_MCS_CHAN_WIDTH_40;  		else if (rate->flags & IEEE80211_TX_RC_80_MHZ_WIDTH) -			result |= u32_encode_bits(2, RATE_MCS_CHAN_WIDTH_MSK_V1); +			result |= RATE_MCS_CHAN_WIDTH_80;  		else if (rate->flags & IEEE80211_TX_RC_160_MHZ_WIDTH) -			result |= u32_encode_bits(3, RATE_MCS_CHAN_WIDTH_MSK_V1); - -		if (iwl_fw_lookup_notif_ver(mvm->fw, LONG_GROUP, TX_CMD, 0) > 6) -			result = iwl_new_rate_from_v1(result); +			result |= RATE_MCS_CHAN_WIDTH_160;  	} else if (rate->flags & IEEE80211_TX_RC_MCS) { -		result = RATE_MCS_HT_MSK_V1; -		result |= u32_encode_bits(rate->idx, -					  RATE_HT_MCS_RATE_CODE_MSK_V1 | -					  RATE_HT_MCS_NSS_MSK_V1); +		result = RATE_MCS_MOD_TYPE_HT; +		result |= u32_encode_bits(rate->idx & 0x7, +					  RATE_HT_MCS_CODE_MSK); +		result |= u32_encode_bits(rate->idx >> 3, +					  RATE_MCS_NSS_MSK);  		if (rate->flags & IEEE80211_TX_RC_SHORT_GI) -			result |= RATE_MCS_SGI_MSK_V1; +			result |= RATE_MCS_SGI_MSK;  		if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) -			result |= u32_encode_bits(1, RATE_MCS_CHAN_WIDTH_MSK_V1); +			result |= RATE_MCS_CHAN_WIDTH_40;  		if (info->flags & IEEE80211_TX_CTL_LDPC) -			result |= RATE_MCS_LDPC_MSK_V1; +			result |= RATE_MCS_LDPC_MSK;  		if (u32_get_bits(info->flags, IEEE80211_TX_CTL_STBC))  			result |= RATE_MCS_STBC_MSK; - -		if (iwl_fw_lookup_notif_ver(mvm->fw, LONG_GROUP, TX_CMD, 0) > 6) -			result = iwl_new_rate_from_v1(result);  	} else {  		int rate_idx = info->control.rates[0].idx; @@ -390,36 +377,41 @@ static u32 iwl_mvm_get_tx_rate(struct iwl_mvm *mvm,  	return iwl_mvm_convert_rate_idx(mvm, info, rate_idx);  } -static u32 iwl_mvm_get_tx_rate_n_flags(struct iwl_mvm *mvm, -				       struct ieee80211_tx_info *info, -				       struct ieee80211_sta *sta, __le16 fc) +static __le32 iwl_mvm_get_tx_rate_n_flags(struct iwl_mvm *mvm, +					  struct ieee80211_tx_info *info, +					  struct ieee80211_sta *sta, __le16 fc)  { +	u32 rate; +  	if (unlikely(info->control.flags & IEEE80211_TX_CTRL_RATE_INJECT)) -		return iwl_mvm_get_inject_tx_rate(mvm, info, sta, fc); +		rate = iwl_mvm_get_inject_tx_rate(mvm, info, sta, fc); +	else +		rate = iwl_mvm_get_tx_rate(mvm, info, sta, fc) | +		       iwl_mvm_get_tx_ant(mvm, info, sta, fc); -	return iwl_mvm_get_tx_rate(mvm, info, sta, fc) | -		iwl_mvm_get_tx_ant(mvm, info, sta, fc); +	return iwl_mvm_v3_rate_to_fw(rate, mvm->fw_rates_ver);  }  /*   * Sets the fields in the Tx cmd that are rate related   */ -void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm, struct iwl_tx_cmd *tx_cmd, -			    struct ieee80211_tx_info *info, -			    struct ieee80211_sta *sta, __le16 fc) +void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm, +			     struct iwl_tx_cmd_v6_params *tx_cmd_params, +			     struct ieee80211_tx_info *info, +			     struct ieee80211_sta *sta, __le16 fc)  {  	/* Set retry limit on RTS packets */ -	tx_cmd->rts_retry_limit = IWL_RTS_DFAULT_RETRY_LIMIT; +	tx_cmd_params->rts_retry_limit = IWL_RTS_DFAULT_RETRY_LIMIT;  	/* Set retry limit on DATA packets and Probe Responses*/  	if (ieee80211_is_probe_resp(fc)) { -		tx_cmd->data_retry_limit = IWL_MGMT_DFAULT_RETRY_LIMIT; -		tx_cmd->rts_retry_limit = -			min(tx_cmd->data_retry_limit, tx_cmd->rts_retry_limit); +		tx_cmd_params->data_retry_limit = IWL_MGMT_DFAULT_RETRY_LIMIT; +		tx_cmd_params->rts_retry_limit = +			min(tx_cmd_params->data_retry_limit, tx_cmd_params->rts_retry_limit);  	} else if (ieee80211_is_back_req(fc)) { -		tx_cmd->data_retry_limit = IWL_BAR_DFAULT_RETRY_LIMIT; +		tx_cmd_params->data_retry_limit = IWL_BAR_DFAULT_RETRY_LIMIT;  	} else { -		tx_cmd->data_retry_limit = IWL_DEFAULT_TX_RETRY; +		tx_cmd_params->data_retry_limit = IWL_DEFAULT_TX_RETRY;  	}  	/* @@ -432,18 +424,17 @@ void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm, struct iwl_tx_cmd *tx_cmd,  		struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);  		if (mvmsta->sta_state >= IEEE80211_STA_AUTHORIZED) { -			tx_cmd->initial_rate_index = 0; -			tx_cmd->tx_flags |= cpu_to_le32(TX_CMD_FLG_STA_RATE); +			tx_cmd_params->initial_rate_index = 0; +			tx_cmd_params->tx_flags |= cpu_to_le32(TX_CMD_FLG_STA_RATE);  			return;  		}  	} else if (ieee80211_is_back_req(fc)) { -		tx_cmd->tx_flags |= +		tx_cmd_params->tx_flags |=  			cpu_to_le32(TX_CMD_FLG_ACK | TX_CMD_FLG_BAR);  	}  	/* Set the rate in the TX cmd */ -	tx_cmd->rate_n_flags = -		cpu_to_le32(iwl_mvm_get_tx_rate_n_flags(mvm, info, sta, fc)); +	tx_cmd_params->rate_n_flags = iwl_mvm_get_tx_rate_n_flags(mvm, info, sta, fc);  }  static inline void iwl_mvm_set_tx_cmd_pn(struct ieee80211_tx_info *info, @@ -468,7 +459,7 @@ static inline void iwl_mvm_set_tx_cmd_pn(struct ieee80211_tx_info *info,   */  static void iwl_mvm_set_tx_cmd_crypto(struct iwl_mvm *mvm,  				      struct ieee80211_tx_info *info, -				      struct iwl_tx_cmd *tx_cmd, +				      struct iwl_tx_cmd_v6_params *tx_cmd_params,  				      struct sk_buff *skb_frag,  				      int hdrlen)  { @@ -479,26 +470,26 @@ static void iwl_mvm_set_tx_cmd_crypto(struct iwl_mvm *mvm,  	switch (keyconf->cipher) {  	case WLAN_CIPHER_SUITE_CCMP: -		iwl_mvm_set_tx_cmd_ccmp(info, tx_cmd); +		iwl_mvm_set_tx_cmd_ccmp(info, tx_cmd_params);  		iwl_mvm_set_tx_cmd_pn(info, crypto_hdr);  		break;  	case WLAN_CIPHER_SUITE_TKIP: -		tx_cmd->sec_ctl = TX_CMD_SEC_TKIP; +		tx_cmd_params->sec_ctl = TX_CMD_SEC_TKIP;  		pn = atomic64_inc_return(&keyconf->tx_pn);  		ieee80211_tkip_add_iv(crypto_hdr, keyconf, pn); -		ieee80211_get_tkip_p2k(keyconf, skb_frag, tx_cmd->key); +		ieee80211_get_tkip_p2k(keyconf, skb_frag, tx_cmd_params->key);  		break;  	case WLAN_CIPHER_SUITE_WEP104: -		tx_cmd->sec_ctl |= TX_CMD_SEC_KEY128; +		tx_cmd_params->sec_ctl |= TX_CMD_SEC_KEY128;  		fallthrough;  	case WLAN_CIPHER_SUITE_WEP40: -		tx_cmd->sec_ctl |= TX_CMD_SEC_WEP | +		tx_cmd_params->sec_ctl |= TX_CMD_SEC_WEP |  			((keyconf->keyidx << TX_CMD_SEC_WEP_KEY_IDX_POS) &  			  TX_CMD_SEC_WEP_KEY_IDX_MSK); -		memcpy(&tx_cmd->key[3], keyconf->key, keyconf->keylen); +		memcpy(&tx_cmd_params->key[3], keyconf->key, keyconf->keylen);  		break;  	case WLAN_CIPHER_SUITE_GCMP:  	case WLAN_CIPHER_SUITE_GCMP_256: @@ -511,12 +502,12 @@ static void iwl_mvm_set_tx_cmd_crypto(struct iwl_mvm *mvm,  		 * one.  		 * Need to handle this.  		 */ -		tx_cmd->sec_ctl |= type | TX_CMD_SEC_KEY_FROM_TABLE; -		tx_cmd->key[0] = keyconf->hw_key_idx; +		tx_cmd_params->sec_ctl |= type | TX_CMD_SEC_KEY_FROM_TABLE; +		tx_cmd_params->key[0] = keyconf->hw_key_idx;  		iwl_mvm_set_tx_cmd_pn(info, crypto_hdr);  		break;  	default: -		tx_cmd->sec_ctl |= TX_CMD_SEC_EXT; +		tx_cmd_params->sec_ctl |= TX_CMD_SEC_EXT;  	}  } @@ -542,7 +533,7 @@ static bool iwl_mvm_use_host_rate(struct iwl_mvm *mvm,  	 * (since we don't necesarily know the link), but FW rate  	 * selection was fixed.  	 */ -	return mvm->trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_BZ; +	return mvm->trans->mac_cfg->device_family < IWL_DEVICE_FAMILY_BZ;  }  static void iwl_mvm_copy_hdr(void *cmd, const void *hdr, int hdrlen, @@ -566,7 +557,7 @@ iwl_mvm_set_tx_params(struct iwl_mvm *mvm, struct sk_buff *skb,  {  	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;  	struct iwl_device_tx_cmd *dev_cmd; -	struct iwl_tx_cmd *tx_cmd; +	struct iwl_tx_cmd_v6 *tx_cmd;  	dev_cmd = iwl_trans_alloc_tx_cmd(mvm->trans); @@ -576,7 +567,7 @@ iwl_mvm_set_tx_params(struct iwl_mvm *mvm, struct sk_buff *skb,  	dev_cmd->hdr.cmd = TX_CMD;  	if (iwl_mvm_has_new_tx_api(mvm)) { -		u32 rate_n_flags = 0; +		__le32 rate_n_flags = 0;  		u16 flags = 0;  		struct iwl_mvm_sta *mvmsta = sta ?  			iwl_mvm_sta_from_mac80211(sta) : NULL; @@ -608,9 +599,9 @@ iwl_mvm_set_tx_params(struct iwl_mvm *mvm, struct sk_buff *skb,  			flags |= IWL_TX_FLAGS_HIGH_PRI;  		} -		if (mvm->trans->trans_cfg->device_family >= +		if (mvm->trans->mac_cfg->device_family >=  		    IWL_DEVICE_FAMILY_AX210) { -			struct iwl_tx_cmd_gen3 *cmd = (void *)dev_cmd->payload; +			struct iwl_tx_cmd *cmd = (void *)dev_cmd->payload;  			u32 offload_assist = iwl_mvm_tx_csum(mvm, skb,  							     info, amsdu); @@ -623,9 +614,9 @@ iwl_mvm_set_tx_params(struct iwl_mvm *mvm, struct sk_buff *skb,  			iwl_mvm_copy_hdr(cmd->hdr, hdr, hdrlen, addr3_override);  			cmd->flags = cpu_to_le16(flags); -			cmd->rate_n_flags = cpu_to_le32(rate_n_flags); +			cmd->rate_n_flags = rate_n_flags;  		} else { -			struct iwl_tx_cmd_gen2 *cmd = (void *)dev_cmd->payload; +			struct iwl_tx_cmd_v9 *cmd = (void *)dev_cmd->payload;  			u16 offload_assist = iwl_mvm_tx_csum(mvm, skb,  							     info, amsdu); @@ -638,19 +629,19 @@ iwl_mvm_set_tx_params(struct iwl_mvm *mvm, struct sk_buff *skb,  			iwl_mvm_copy_hdr(cmd->hdr, hdr, hdrlen, addr3_override);  			cmd->flags = cpu_to_le32(flags); -			cmd->rate_n_flags = cpu_to_le32(rate_n_flags); +			cmd->rate_n_flags = rate_n_flags;  		}  		goto out;  	} -	tx_cmd = (struct iwl_tx_cmd *)dev_cmd->payload; +	tx_cmd = (struct iwl_tx_cmd_v6 *)dev_cmd->payload;  	if (info->control.hw_key) -		iwl_mvm_set_tx_cmd_crypto(mvm, info, tx_cmd, skb, hdrlen); +		iwl_mvm_set_tx_cmd_crypto(mvm, info, &tx_cmd->params, skb, hdrlen); -	iwl_mvm_set_tx_cmd(mvm, skb, tx_cmd, info, sta_id); +	iwl_mvm_set_tx_cmd(mvm, skb, &tx_cmd->params, info, sta_id); -	iwl_mvm_set_tx_cmd_rate(mvm, tx_cmd, info, sta, hdr->frame_control); +	iwl_mvm_set_tx_cmd_rate(mvm, &tx_cmd->params, info, sta, hdr->frame_control);  	/* Copy MAC header from skb into command buffer */  	iwl_mvm_copy_hdr(tx_cmd->hdr, hdr, hdrlen, addr3_override); @@ -938,78 +929,6 @@ unsigned int iwl_mvm_max_amsdu_size(struct iwl_mvm *mvm,  #ifdef CONFIG_INET -static int -iwl_mvm_tx_tso_segment(struct sk_buff *skb, unsigned int num_subframes, -		       netdev_features_t netdev_flags, -		       struct sk_buff_head *mpdus_skb) -{ -	struct sk_buff *tmp, *next; -	struct ieee80211_hdr *hdr = (void *)skb->data; -	char cb[sizeof(skb->cb)]; -	u16 i = 0; -	unsigned int tcp_payload_len; -	unsigned int mss = skb_shinfo(skb)->gso_size; -	bool ipv4 = (skb->protocol == htons(ETH_P_IP)); -	bool qos = ieee80211_is_data_qos(hdr->frame_control); -	u16 ip_base_id = ipv4 ? ntohs(ip_hdr(skb)->id) : 0; - -	skb_shinfo(skb)->gso_size = num_subframes * mss; -	memcpy(cb, skb->cb, sizeof(cb)); - -	next = skb_gso_segment(skb, netdev_flags); -	skb_shinfo(skb)->gso_size = mss; -	skb_shinfo(skb)->gso_type = ipv4 ? SKB_GSO_TCPV4 : SKB_GSO_TCPV6; - -	if (IS_ERR(next) && PTR_ERR(next) == -ENOMEM) -		return -ENOMEM; - -	if (WARN_ONCE(IS_ERR(next), -		      "skb_gso_segment error: %d\n", (int)PTR_ERR(next))) -		return PTR_ERR(next); - -	if (next) -		consume_skb(skb); - -	skb_list_walk_safe(next, tmp, next) { -		memcpy(tmp->cb, cb, sizeof(tmp->cb)); -		/* -		 * Compute the length of all the data added for the A-MSDU. -		 * This will be used to compute the length to write in the TX -		 * command. We have: SNAP + IP + TCP for n -1 subframes and -		 * ETH header for n subframes. -		 */ -		tcp_payload_len = skb_tail_pointer(tmp) - -			skb_transport_header(tmp) - -			tcp_hdrlen(tmp) + tmp->data_len; - -		if (ipv4) -			ip_hdr(tmp)->id = htons(ip_base_id + i * num_subframes); - -		if (tcp_payload_len > mss) { -			skb_shinfo(tmp)->gso_size = mss; -			skb_shinfo(tmp)->gso_type = ipv4 ? SKB_GSO_TCPV4 : -							   SKB_GSO_TCPV6; -		} else { -			if (qos) { -				u8 *qc; - -				if (ipv4) -					ip_send_check(ip_hdr(tmp)); - -				qc = ieee80211_get_qos_ctl((void *)tmp->data); -				*qc &= ~IEEE80211_QOS_CTL_A_MSDU_PRESENT; -			} -			skb_shinfo(tmp)->gso_size = 0; -		} - -		skb_mark_not_on_list(tmp); -		__skb_queue_tail(mpdus_skb, tmp); -		i++; -	} - -	return 0; -} -  static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb,  			  struct ieee80211_tx_info *info,  			  struct ieee80211_sta *sta, @@ -1028,7 +947,7 @@ static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb,  	if (!mvmsta->max_amsdu_len ||  	    !ieee80211_is_data_qos(hdr->frame_control) ||  	    !mvmsta->amsdu_enabled) -		return iwl_mvm_tx_tso_segment(skb, 1, netdev_flags, mpdus_skb); +		return iwl_tx_tso_segment(skb, 1, netdev_flags, mpdus_skb);  	/*  	 * Do not build AMSDU for IPv6 with extension headers. @@ -1038,7 +957,7 @@ static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb,  	    ((struct ipv6hdr *)skb_network_header(skb))->nexthdr !=  	    IPPROTO_TCP) {  		netdev_flags &= ~NETIF_F_CSUM_MASK; -		return iwl_mvm_tx_tso_segment(skb, 1, netdev_flags, mpdus_skb); +		return iwl_tx_tso_segment(skb, 1, netdev_flags, mpdus_skb);  	}  	tid = ieee80211_get_tid(hdr); @@ -1052,7 +971,7 @@ static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb,  	if ((info->flags & IEEE80211_TX_CTL_AMPDU &&  	     !mvmsta->tid_data[tid].amsdu_in_ampdu_allowed) ||  	    !(mvmsta->amsdu_enabled & BIT(tid))) -		return iwl_mvm_tx_tso_segment(skb, 1, netdev_flags, mpdus_skb); +		return iwl_tx_tso_segment(skb, 1, netdev_flags, mpdus_skb);  	/*  	 * Take the min of ieee80211 station and mvm station @@ -1094,7 +1013,7 @@ static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb,  	 *	1 more for the potential data in the header  	 */  	if ((num_subframes * 2 + skb_shinfo(skb)->nr_frags + 1) > -	    mvm->trans->max_skb_frags) +	    mvm->trans->info.max_skb_frags)  		num_subframes = 1;  	if (num_subframes > 1) @@ -1110,8 +1029,7 @@ static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb,  	 * Trick the segmentation function to make it  	 * create SKBs that can fit into one A-MSDU.  	 */ -	return iwl_mvm_tx_tso_segment(skb, num_subframes, netdev_flags, -				      mpdus_skb); +	return iwl_tx_tso_segment(skb, num_subframes, netdev_flags, mpdus_skb);  }  #else /* CONFIG_INET */  static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb, @@ -1203,6 +1121,9 @@ static int iwl_mvm_tx_mpdu(struct iwl_mvm *mvm, struct sk_buff *skb,  	bool is_ampdu = false;  	int hdrlen; +	if (WARN_ON_ONCE(!sta)) +		return -1; +  	mvmsta = iwl_mvm_sta_from_mac80211(sta);  	fc = hdr->frame_control;  	hdrlen = ieee80211_hdrlen(fc); @@ -1210,10 +1131,7 @@ static int iwl_mvm_tx_mpdu(struct iwl_mvm *mvm, struct sk_buff *skb,  	if (IWL_MVM_NON_TRANSMITTING_AP && ieee80211_is_probe_resp(fc))  		return -1; -	if (WARN_ON_ONCE(!mvmsta)) -		return -1; - -	if (WARN_ON_ONCE(mvmsta->deflink.sta_id == IWL_MVM_INVALID_STA)) +	if (WARN_ON_ONCE(mvmsta->deflink.sta_id == IWL_INVALID_STA))  		return -1;  	if (unlikely(ieee80211_is_any_nullfunc(fc)) && sta->deflink.he_cap.has_he) @@ -1257,7 +1175,7 @@ static int iwl_mvm_tx_mpdu(struct iwl_mvm *mvm, struct sk_buff *skb,  		seq_number &= IEEE80211_SCTL_SEQ;  		if (!iwl_mvm_has_new_tx_api(mvm)) { -			struct iwl_tx_cmd *tx_cmd = (void *)dev_cmd->payload; +			struct iwl_tx_cmd_v6 *tx_cmd = (void *)dev_cmd->payload;  			hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);  			hdr->seq_ctrl |= cpu_to_le16(seq_number); @@ -1349,7 +1267,7 @@ drop:  int iwl_mvm_tx_skb_sta(struct iwl_mvm *mvm, struct sk_buff *skb,  		       struct ieee80211_sta *sta)  { -	struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); +	struct iwl_mvm_sta *mvmsta;  	struct ieee80211_tx_info info;  	struct sk_buff_head mpdus_skbs;  	struct ieee80211_vif *vif; @@ -1358,10 +1276,12 @@ int iwl_mvm_tx_skb_sta(struct iwl_mvm *mvm, struct sk_buff *skb,  	struct sk_buff *orig_skb = skb;  	const u8 *addr3; -	if (WARN_ON_ONCE(!mvmsta)) +	if (WARN_ON_ONCE(!sta))  		return -1; -	if (WARN_ON_ONCE(mvmsta->deflink.sta_id == IWL_MVM_INVALID_STA)) +	mvmsta = iwl_mvm_sta_from_mac80211(sta); + +	if (WARN_ON_ONCE(mvmsta->deflink.sta_id == IWL_INVALID_STA))  		return -1;  	memcpy(&info, skb->cb, sizeof(info)); @@ -1448,8 +1368,7 @@ static void iwl_mvm_check_ratid_empty(struct iwl_mvm *mvm,  	lockdep_assert_held(&mvmsta->lock); -	if ((tid_data->state == IWL_AGG_ON || -	     tid_data->state == IWL_EMPTYING_HW_QUEUE_DELBA) && +	if (tid_data->state == IWL_AGG_ON &&  	    iwl_mvm_tid_queued(mvm, tid_data) == 0) {  		/*  		 * Now that this aggregation or DQA queue is empty tell @@ -1464,7 +1383,7 @@ static void iwl_mvm_check_ratid_empty(struct iwl_mvm *mvm,  	 * to align the wrap around of ssn so we compare relevant values.  	 */  	normalized_ssn = tid_data->ssn; -	if (mvm->trans->trans_cfg->gen2) +	if (mvm->trans->mac_cfg->gen2)  		normalized_ssn &= 0xff;  	if (normalized_ssn != tid_data->next_reclaimed) @@ -1478,15 +1397,6 @@ static void iwl_mvm_check_ratid_empty(struct iwl_mvm *mvm,  		tid_data->state = IWL_AGG_STARTING;  		ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);  		break; - -	case IWL_EMPTYING_HW_QUEUE_DELBA: -		IWL_DEBUG_TX_QUEUES(mvm, -				    "Can continue DELBA flow ssn = next_recl = %d\n", -				    tid_data->next_reclaimed); -		tid_data->state = IWL_AGG_OFF; -		ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); -		break; -  	default:  		break;  	} @@ -1553,7 +1463,7 @@ void iwl_mvm_hwrate_to_tx_rate(u32 rate_n_flags,  			       struct ieee80211_tx_rate *r)  {  	u32 format = rate_n_flags & RATE_MCS_MOD_TYPE_MSK; -	u32 rate = format == RATE_MCS_HT_MSK ? +	u32 rate = format == RATE_MCS_MOD_TYPE_HT ?  		RATE_HT_MCS_INDEX(rate_n_flags) :  		rate_n_flags & RATE_MCS_CODE_MSK; @@ -1563,68 +1473,51 @@ void iwl_mvm_hwrate_to_tx_rate(u32 rate_n_flags,  	if (rate_n_flags & RATE_MCS_SGI_MSK)  		r->flags |= IEEE80211_TX_RC_SHORT_GI; -	if (format ==  RATE_MCS_HT_MSK) { +	switch (format) { +	case RATE_MCS_MOD_TYPE_HT:  		r->flags |= IEEE80211_TX_RC_MCS;  		r->idx = rate; -	} else if (format ==  RATE_MCS_VHT_MSK) { +		break; +	case RATE_MCS_MOD_TYPE_VHT:  		ieee80211_rate_set_vht(r, rate,  				       FIELD_GET(RATE_MCS_NSS_MSK,  						 rate_n_flags) + 1);  		r->flags |= IEEE80211_TX_RC_VHT_MCS; -	} else if (format == RATE_MCS_HE_MSK) { +		break; +	case RATE_MCS_MOD_TYPE_HE: +	case RATE_MCS_MOD_TYPE_EHT:  		/* mac80211 cannot do this without ieee80211_tx_status_ext()  		 * but it only matters for radiotap */  		r->idx = 0; -	} else { +		break; +	default:  		r->idx = iwl_mvm_legacy_hw_idx_to_mac80211_idx(rate_n_flags,  							       band);  	}  } -void iwl_mvm_hwrate_to_tx_rate_v1(u32 rate_n_flags, -				  enum nl80211_band band, -				  struct ieee80211_tx_rate *r) -{ -	if (rate_n_flags & RATE_HT_MCS_GF_MSK) -		r->flags |= IEEE80211_TX_RC_GREEN_FIELD; - -	r->flags |= -		iwl_mvm_get_hwrate_chan_width(rate_n_flags & -					      RATE_MCS_CHAN_WIDTH_MSK_V1); - -	if (rate_n_flags & RATE_MCS_SGI_MSK_V1) -		r->flags |= IEEE80211_TX_RC_SHORT_GI; -	if (rate_n_flags & RATE_MCS_HT_MSK_V1) { -		r->flags |= IEEE80211_TX_RC_MCS; -		r->idx = rate_n_flags & RATE_HT_MCS_INDEX_MSK_V1; -	} else if (rate_n_flags & RATE_MCS_VHT_MSK_V1) { -		ieee80211_rate_set_vht( -			r, rate_n_flags & RATE_VHT_MCS_RATE_CODE_MSK, -			FIELD_GET(RATE_MCS_NSS_MSK, rate_n_flags) + 1); -		r->flags |= IEEE80211_TX_RC_VHT_MCS; -	} else { -		r->idx = iwl_mvm_legacy_rate_to_mac80211_idx(rate_n_flags, -							     band); -	} -} -  /*   * translate ucode response to mac80211 tx status control values   */ -static void iwl_mvm_hwrate_to_tx_status(const struct iwl_fw *fw, -					u32 rate_n_flags, +static void iwl_mvm_hwrate_to_tx_status(struct iwl_mvm *mvm, +					__le32 rate_n_flags,  					struct ieee80211_tx_info *info)  {  	struct ieee80211_tx_rate *r = &info->status.rates[0]; +	u32 rate; -	if (iwl_fw_lookup_notif_ver(fw, LONG_GROUP, -				    TX_CMD, 0) <= 6) -		rate_n_flags = iwl_new_rate_from_v1(rate_n_flags); +	/* +	 * Technically this conversion is incorrect for BA status, however: +	 *  - we only use the BA notif data for older firmware that have +	 *    host rate scaling and don't use newer rate formats +	 *  - the firmware API changed together for BA notif and TX CMD +	 *    as well +	 */ +	rate = iwl_mvm_v3_rate_from_fw(rate_n_flags, mvm->fw_rates_ver);  	info->status.antenna = -		((rate_n_flags & RATE_MCS_ANT_AB_MSK) >> RATE_MCS_ANT_POS); -	iwl_mvm_hwrate_to_tx_rate(rate_n_flags, -				  info->band, r); +		((rate & RATE_MCS_ANT_AB_MSK) >> RATE_MCS_ANT_POS); +	iwl_mvm_hwrate_to_tx_rate(rate, info->band, r);  }  static void iwl_mvm_tx_status_check_trigger(struct iwl_mvm *mvm, @@ -1684,12 +1577,12 @@ static void iwl_mvm_tx_status_check_trigger(struct iwl_mvm *mvm,   * For 22000-series and lower, this is just 12 bits. For later, 16 bits.   */  static inline u32 iwl_mvm_get_scd_ssn(struct iwl_mvm *mvm, -				      struct iwl_mvm_tx_resp *tx_resp) +				      struct iwl_tx_resp *tx_resp)  {  	u32 val = le32_to_cpup((__le32 *)iwl_mvm_get_agg_status(mvm, tx_resp) +  			       tx_resp->frame_count); -	if (mvm->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) +	if (mvm->trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_AX210)  		return val & 0xFFFF;  	return val & 0xFFF;  } @@ -1700,10 +1593,10 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,  	struct ieee80211_sta *sta;  	u16 sequence = le16_to_cpu(pkt->hdr.sequence);  	int txq_id = SEQ_TO_QUEUE(sequence); -	/* struct iwl_mvm_tx_resp_v3 is almost the same */ -	struct iwl_mvm_tx_resp *tx_resp = (void *)pkt->data; -	int sta_id = IWL_MVM_TX_RES_GET_RA(tx_resp->ra_tid); -	int tid = IWL_MVM_TX_RES_GET_TID(tx_resp->ra_tid); +	/* struct iwl_tx_resp_v3 is almost the same */ +	struct iwl_tx_resp *tx_resp = (void *)pkt->data; +	int sta_id = IWL_TX_RES_GET_RA(tx_resp->ra_tid); +	int tid = IWL_TX_RES_GET_TID(tx_resp->ra_tid);  	struct agg_tx_status *agg_status =  		iwl_mvm_get_agg_status(mvm, tx_resp);  	u32 status = le16_to_cpu(agg_status->status); @@ -1776,9 +1669,7 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,  		info->status.rates[0].count = tx_resp->failure_frame + 1; -		iwl_mvm_hwrate_to_tx_status(mvm->fw, -					    le32_to_cpu(tx_resp->initial_rate), -					    info); +		iwl_mvm_hwrate_to_tx_status(mvm, tx_resp->initial_rate, info);  		/* Don't assign the converted initial_rate, because driver  		 * TLC uses this and doesn't support the new FW rate @@ -1884,7 +1775,9 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,  				IWL_DEBUG_TX_REPLY(mvm,  						   "Next reclaimed packet:%d\n",  						   next_reclaimed); -				iwl_mvm_count_mpdu(mvmsta, sta_id, 1, true, 0); +				if (tid < IWL_MAX_TID_COUNT) +					iwl_mvm_count_mpdu(mvmsta, sta_id, 1, +							   true, 0);  			} else {  				IWL_DEBUG_TX_REPLY(mvm,  						   "NDP - don't update next_reclaimed\n"); @@ -1958,7 +1851,7 @@ static const char *iwl_get_agg_tx_status(u16 status)  static void iwl_mvm_rx_tx_cmd_agg_dbg(struct iwl_mvm *mvm,  				      struct iwl_rx_packet *pkt)  { -	struct iwl_mvm_tx_resp *tx_resp = (void *)pkt->data; +	struct iwl_tx_resp *tx_resp = (void *)pkt->data;  	struct agg_tx_status *frame_status =  		iwl_mvm_get_agg_status(mvm, tx_resp);  	int i; @@ -1992,9 +1885,9 @@ static void iwl_mvm_rx_tx_cmd_agg_dbg(struct iwl_mvm *mvm,  static void iwl_mvm_rx_tx_cmd_agg(struct iwl_mvm *mvm,  				  struct iwl_rx_packet *pkt)  { -	struct iwl_mvm_tx_resp *tx_resp = (void *)pkt->data; -	int sta_id = IWL_MVM_TX_RES_GET_RA(tx_resp->ra_tid); -	int tid = IWL_MVM_TX_RES_GET_TID(tx_resp->ra_tid); +	struct iwl_tx_resp *tx_resp = (void *)pkt->data; +	int sta_id = IWL_TX_RES_GET_RA(tx_resp->ra_tid); +	int tid = IWL_TX_RES_GET_TID(tx_resp->ra_tid);  	u16 sequence = le16_to_cpu(pkt->hdr.sequence);  	struct iwl_mvm_sta *mvmsta;  	int queue = SEQ_TO_QUEUE(sequence); @@ -2018,7 +1911,7 @@ static void iwl_mvm_rx_tx_cmd_agg(struct iwl_mvm *mvm,  	if (!WARN_ON_ONCE(!mvmsta)) {  		mvmsta->tid_data[tid].rate_n_flags = -			le32_to_cpu(tx_resp->initial_rate); +			tx_resp->initial_rate;  		mvmsta->tid_data[tid].tx_time =  			le16_to_cpu(tx_resp->wireless_media_time);  		mvmsta->tid_data[tid].lq_color = @@ -2033,7 +1926,7 @@ static void iwl_mvm_rx_tx_cmd_agg(struct iwl_mvm *mvm,  void iwl_mvm_rx_tx_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb)  {  	struct iwl_rx_packet *pkt = rxb_addr(rxb); -	struct iwl_mvm_tx_resp *tx_resp = (void *)pkt->data; +	struct iwl_tx_resp *tx_resp = (void *)pkt->data;  	if (tx_resp->frame_count == 1)  		iwl_mvm_rx_tx_cmd_single(mvm, pkt); @@ -2043,7 +1936,7 @@ void iwl_mvm_rx_tx_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb)  static void iwl_mvm_tx_reclaim(struct iwl_mvm *mvm, int sta_id, int tid,  			       int txq, int index, -			       struct ieee80211_tx_info *tx_info, u32 rate, +			       struct ieee80211_tx_info *tx_info, __le32 rate,  			       bool is_flush)  {  	struct sk_buff_head reclaimed_skbs; @@ -2127,7 +2020,9 @@ static void iwl_mvm_tx_reclaim(struct iwl_mvm *mvm, int sta_id, int tid,  	tx_info->status.status_driver_data[0] =  		RS_DRV_DATA_PACK(tid_data->lq_color,  				 tx_info->status.status_driver_data[0]); -	tx_info->status.status_driver_data[1] = (void *)(uintptr_t)rate; +	/* the value is only consumed for old FW that has v1 rates anyway */ +	tx_info->status.status_driver_data[1] = +		(void *)(uintptr_t)le32_to_cpu(rate);  	skb_queue_walk(&reclaimed_skbs, skb) {  		struct ieee80211_hdr *hdr = (void *)skb->data; @@ -2146,7 +2041,7 @@ static void iwl_mvm_tx_reclaim(struct iwl_mvm *mvm, int sta_id, int tid,  			info->flags |= IEEE80211_TX_STAT_AMPDU;  			memcpy(&info->status, &tx_info->status,  			       sizeof(tx_info->status)); -			iwl_mvm_hwrate_to_tx_status(mvm->fw, rate, info); +			iwl_mvm_hwrate_to_tx_status(mvm, rate, info);  		}  	} @@ -2169,7 +2064,7 @@ static void iwl_mvm_tx_reclaim(struct iwl_mvm *mvm, int sta_id, int tid,  			goto out;  		tx_info->band = chanctx_conf->def.chan->band; -		iwl_mvm_hwrate_to_tx_status(mvm->fw, rate, tx_info); +		iwl_mvm_hwrate_to_tx_status(mvm, rate, tx_info);  		IWL_DEBUG_TX_REPLY(mvm, "No reclaim. Update rs directly\n");  		iwl_mvm_rs_tx_status(mvm, sta, tid, tx_info, false); @@ -2197,7 +2092,7 @@ void iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb)  	ba_info.flags = IEEE80211_TX_STAT_AMPDU;  	if (iwl_mvm_has_new_tx_api(mvm)) { -		struct iwl_mvm_compressed_ba_notif *ba_res = +		struct iwl_compressed_ba_notif *ba_res =  			(void *)pkt->data;  		u8 lq_color = TX_RES_RATE_TABLE_COL_GET(ba_res->tlc_rate_info);  		u16 tfd_cnt; @@ -2245,8 +2140,7 @@ void iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb)  		/* Free per TID */  		for (i = 0; i < tfd_cnt; i++) { -			struct iwl_mvm_compressed_ba_tfd *ba_tfd = -				&ba_res->tfd[i]; +			struct iwl_compressed_ba_tfd *ba_tfd = &ba_res->tfd[i];  			tid = ba_tfd->tid;  			if (tid == IWL_MGMT_TID) @@ -2259,7 +2153,7 @@ void iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb)  					   (int)(le16_to_cpu(ba_tfd->q_num)),  					   le16_to_cpu(ba_tfd->tfd_index),  					   &ba_info, -					   le32_to_cpu(ba_res->tx_rate), false); +					   ba_res->tx_rate, false);  		}  		if (mvmsta) { diff --git a/sys/contrib/dev/iwlwifi/mvm/utils.c b/sys/contrib/dev/iwlwifi/mvm/utils.c index 6c507882b08c..e7e24941db15 100644 --- a/sys/contrib/dev/iwlwifi/mvm/utils.c +++ b/sys/contrib/dev/iwlwifi/mvm/utils.c @@ -1,6 +1,6 @@  // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause  /* - * Copyright (C) 2012-2014, 2018-2024 Intel Corporation + * Copyright (C) 2012-2014, 2018-2025 Intel Corporation   * Copyright (C) 2013-2014 Intel Mobile Communications GmbH   * Copyright (C) 2015-2017 Intel Deutschland GmbH   */ @@ -145,7 +145,7 @@ int iwl_mvm_legacy_hw_idx_to_mac80211_idx(u32 rate_n_flags,  	int rate = rate_n_flags & RATE_LEGACY_RATE_MSK;  	bool is_LB = band == NL80211_BAND_2GHZ; -	if (format == RATE_MCS_LEGACY_OFDM_MSK) +	if (format == RATE_MCS_MOD_TYPE_LEGACY_OFDM)  		return is_LB ? rate + IWL_FIRST_OFDM_RATE :  			rate; @@ -172,15 +172,9 @@ int iwl_mvm_legacy_rate_to_mac80211_idx(u32 rate_n_flags,  u8 iwl_mvm_mac80211_idx_to_hwrate(const struct iwl_fw *fw, int rate_idx)  { -	if (iwl_fw_lookup_cmd_ver(fw, TX_CMD, 0) > 8) -		/* In the new rate legacy rates are indexed: -		 * 0 - 3 for CCK and 0 - 7 for OFDM. -		 */ -		return (rate_idx >= IWL_FIRST_OFDM_RATE ? -			rate_idx - IWL_FIRST_OFDM_RATE : -			rate_idx); - -	return iwl_fw_rate_idx_to_plcp(rate_idx); +	return (rate_idx >= IWL_FIRST_OFDM_RATE ? +		rate_idx - IWL_FIRST_OFDM_RATE : +		rate_idx);  }  u8 iwl_mvm_mac80211_ac_to_ucode_ac(enum ieee80211_ac_numbers ac) @@ -264,7 +258,7 @@ int iwl_mvm_send_lq_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq)  		.data = { lq, },  	}; -	if (WARN_ON(lq->sta_id == IWL_MVM_INVALID_STA || +	if (WARN_ON(lq->sta_id == IWL_INVALID_STA ||  		    iwl_mvm_has_tlc_offload(mvm)))  		return -EINVAL; @@ -300,6 +294,10 @@ void iwl_mvm_update_smps(struct iwl_mvm *mvm, struct ieee80211_vif *vif,  	if (vif->type != NL80211_IFTYPE_STATION)  		return; +	/* SMPS is handled by firmware */ +	if (iwl_mvm_has_rlc_offload(mvm)) +		return; +  	mvmvif = iwl_mvm_vif_from_mac80211(vif);  	if (WARN_ON_ONCE(!mvmvif->link[link_id])) @@ -678,10 +676,8 @@ struct ieee80211_vif *iwl_mvm_get_bss_vif(struct iwl_mvm *mvm)  		mvm->hw, IEEE80211_IFACE_ITER_NORMAL,  		iwl_mvm_bss_iface_iterator, &bss_iter_data); -	if (bss_iter_data.error) { -		IWL_ERR(mvm, "More than one managed interface active!\n"); +	if (bss_iter_data.error)  		return ERR_PTR(-EINVAL); -	}  	return bss_iter_data.vif;  } @@ -746,58 +742,20 @@ bool iwl_mvm_is_vif_assoc(struct iwl_mvm *mvm)  }  unsigned int iwl_mvm_get_wd_timeout(struct iwl_mvm *mvm, -				    struct ieee80211_vif *vif, -				    bool tdls, bool cmd_q) +				    struct ieee80211_vif *vif)  { -	struct iwl_fw_dbg_trigger_tlv *trigger; -	struct iwl_fw_dbg_trigger_txq_timer *txq_timer; -	unsigned int default_timeout = cmd_q ? -		IWL_DEF_WD_TIMEOUT : -		mvm->trans->trans_cfg->base_params->wd_timeout; +	unsigned int default_timeout = +		mvm->trans->mac_cfg->base->wd_timeout; -	if (!iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_TXQ_TIMERS)) { -		/* -		 * We can't know when the station is asleep or awake, so we -		 * must disable the queue hang detection. -		 */ -		if (fw_has_capa(&mvm->fw->ucode_capa, -				IWL_UCODE_TLV_CAPA_STA_PM_NOTIF) && -		    vif && vif->type == NL80211_IFTYPE_AP) -			return IWL_WATCHDOG_DISABLED; -		return default_timeout; -	} - -	trigger = iwl_fw_dbg_get_trigger(mvm->fw, FW_DBG_TRIGGER_TXQ_TIMERS); -	txq_timer = (void *)trigger->data; - -	if (tdls) -		return le32_to_cpu(txq_timer->tdls); - -	if (cmd_q) -		return le32_to_cpu(txq_timer->command_queue); - -	if (WARN_ON(!vif)) -		return default_timeout; - -	switch (ieee80211_vif_type_p2p(vif)) { -	case NL80211_IFTYPE_ADHOC: -		return le32_to_cpu(txq_timer->ibss); -	case NL80211_IFTYPE_STATION: -		return le32_to_cpu(txq_timer->bss); -	case NL80211_IFTYPE_AP: -		return le32_to_cpu(txq_timer->softap); -	case NL80211_IFTYPE_P2P_CLIENT: -		return le32_to_cpu(txq_timer->p2p_client); -	case NL80211_IFTYPE_P2P_GO: -		return le32_to_cpu(txq_timer->p2p_go); -	case NL80211_IFTYPE_P2P_DEVICE: -		return le32_to_cpu(txq_timer->p2p_device); -	case NL80211_IFTYPE_MONITOR: -		return default_timeout; -	default: -		WARN_ON(1); -		return mvm->trans->trans_cfg->base_params->wd_timeout; -	} +	/* +	 * We can't know when the station is asleep or awake, so we +	 * must disable the queue hang detection. +	 */ +	if (fw_has_capa(&mvm->fw->ucode_capa, +			IWL_UCODE_TLV_CAPA_STA_PM_NOTIF) && +	    vif->type == NL80211_IFTYPE_AP) +		return IWL_WATCHDOG_DISABLED; +	return default_timeout;  }  void iwl_mvm_connection_loss(struct iwl_mvm *mvm, struct ieee80211_vif *vif, @@ -1226,9 +1184,9 @@ u32 iwl_mvm_get_systime(struct iwl_mvm *mvm)  {  	u32 reg_addr = DEVICE_SYSTEM_TIME_REG; -	if (mvm->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_22000 && -	    mvm->trans->cfg->gp2_reg_addr) -		reg_addr = mvm->trans->cfg->gp2_reg_addr; +	if (mvm->trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_22000 && +	    mvm->trans->mac_cfg->base->gp2_reg_addr) +		reg_addr = mvm->trans->mac_cfg->base->gp2_reg_addr;  	return iwl_read_prph(mvm->trans, reg_addr);  } @@ -1279,6 +1237,170 @@ bool iwl_mvm_have_links_same_channel(struct iwl_mvm_vif *vif1,  	return false;  } +static u32 iwl_legacy_rate_to_fw_idx(u32 rate_n_flags) +{ +	int rate = rate_n_flags & RATE_LEGACY_RATE_MSK_V1; +	int idx; +	bool ofdm = !(rate_n_flags & RATE_MCS_CCK_MSK_V1); +	int offset = ofdm ? IWL_FIRST_OFDM_RATE : 0; +	int last = ofdm ? IWL_RATE_COUNT_LEGACY : IWL_FIRST_OFDM_RATE; + +	for (idx = offset; idx < last; idx++) +		if (iwl_fw_rate_idx_to_plcp(idx) == rate) +			return idx - offset; +	return IWL_RATE_INVALID; +} + +u32 iwl_mvm_v3_rate_from_fw(__le32 rate, u8 rate_ver) +{ +	u32 rate_v3 = 0, rate_v1; +	u32 dup = 0; + +	if (rate_ver > 1) +		return iwl_v3_rate_from_v2_v3(rate, rate_ver >= 3); + +	rate_v1 = le32_to_cpu(rate); +	if (rate_v1 == 0) +		return rate_v1; +	/* convert rate */ +	if (rate_v1 & RATE_MCS_HT_MSK_V1) { +		u32 nss; + +		rate_v3 |= RATE_MCS_MOD_TYPE_HT; +		rate_v3 |= +			rate_v1 & RATE_HT_MCS_RATE_CODE_MSK_V1; +		nss = u32_get_bits(rate_v1, RATE_HT_MCS_MIMO2_MSK); +		rate_v3 |= u32_encode_bits(nss, RATE_MCS_NSS_MSK); +	} else if (rate_v1 & RATE_MCS_VHT_MSK_V1 || +		   rate_v1 & RATE_MCS_HE_MSK_V1) { +		u32 nss = u32_get_bits(rate_v1, RATE_VHT_MCS_NSS_MSK); + +		rate_v3 |= rate_v1 & RATE_VHT_MCS_RATE_CODE_MSK; + +		rate_v3 |= u32_encode_bits(nss, RATE_MCS_NSS_MSK); + +		if (rate_v1 & RATE_MCS_HE_MSK_V1) { +			u32 he_type_bits = rate_v1 & RATE_MCS_HE_TYPE_MSK_V1; +			u32 he_type = he_type_bits >> RATE_MCS_HE_TYPE_POS_V1; +			u32 he_106t = (rate_v1 & RATE_MCS_HE_106T_MSK_V1) >> +				RATE_MCS_HE_106T_POS_V1; +			u32 he_gi_ltf = (rate_v1 & RATE_MCS_HE_GI_LTF_MSK_V1) >> +				RATE_MCS_HE_GI_LTF_POS; + +			if ((he_type_bits == RATE_MCS_HE_TYPE_SU || +			     he_type_bits == RATE_MCS_HE_TYPE_EXT_SU) && +			    he_gi_ltf == RATE_MCS_HE_SU_4_LTF) +				/* the new rate have an additional bit to +				 * represent the value 4 rather then using SGI +				 * bit for this purpose - as it was done in the +				 * old rate +				 */ +				he_gi_ltf += (rate_v1 & RATE_MCS_SGI_MSK_V1) >> +					RATE_MCS_SGI_POS_V1; + +			rate_v3 |= he_gi_ltf << RATE_MCS_HE_GI_LTF_POS; +			rate_v3 |= he_type << RATE_MCS_HE_TYPE_POS; +			rate_v3 |= he_106t << RATE_MCS_HE_106T_POS; +			rate_v3 |= rate_v1 & RATE_HE_DUAL_CARRIER_MODE_MSK; +			rate_v3 |= RATE_MCS_MOD_TYPE_HE; +		} else { +			rate_v3 |= RATE_MCS_MOD_TYPE_VHT; +		} +	/* if legacy format */ +	} else { +		u32 legacy_rate = iwl_legacy_rate_to_fw_idx(rate_v1); + +		if (WARN_ON_ONCE(legacy_rate == IWL_RATE_INVALID)) +			legacy_rate = (rate_v1 & RATE_MCS_CCK_MSK_V1) ? +				IWL_FIRST_CCK_RATE : IWL_FIRST_OFDM_RATE; + +		rate_v3 |= legacy_rate; +		if (!(rate_v1 & RATE_MCS_CCK_MSK_V1)) +			rate_v3 |= RATE_MCS_MOD_TYPE_LEGACY_OFDM; +	} + +	/* convert flags */ +	if (rate_v1 & RATE_MCS_LDPC_MSK_V1) +		rate_v3 |= RATE_MCS_LDPC_MSK; +	rate_v3 |= (rate_v1 & RATE_MCS_CHAN_WIDTH_MSK_V1) | +		(rate_v1 & RATE_MCS_ANT_AB_MSK) | +		(rate_v1 & RATE_MCS_STBC_MSK) | +		(rate_v1 & RATE_MCS_BF_MSK); + +	dup = (rate_v1 & RATE_MCS_DUP_MSK_V1) >> RATE_MCS_DUP_POS_V1; +	if (dup) { +		rate_v3 |= RATE_MCS_DUP_MSK; +		rate_v3 |= dup << RATE_MCS_CHAN_WIDTH_POS; +	} + +	if ((!(rate_v1 & RATE_MCS_HE_MSK_V1)) && +	    (rate_v1 & RATE_MCS_SGI_MSK_V1)) +		rate_v3 |= RATE_MCS_SGI_MSK; + +	return rate_v3; +} + +__le32 iwl_mvm_v3_rate_to_fw(u32 rate, u8 rate_ver) +{ +	u32 result = 0; +	int rate_idx; + +	if (rate_ver > 1) +		return iwl_v3_rate_to_v2_v3(rate, rate_ver > 2); + +	switch (rate & RATE_MCS_MOD_TYPE_MSK) { +	case RATE_MCS_MOD_TYPE_CCK: +		result = RATE_MCS_CCK_MSK_V1; +		fallthrough; +	case RATE_MCS_MOD_TYPE_LEGACY_OFDM: +		rate_idx = u32_get_bits(rate, RATE_LEGACY_RATE_MSK); +		if (!(result & RATE_MCS_CCK_MSK_V1)) +			rate_idx += IWL_FIRST_OFDM_RATE; +		result |= u32_encode_bits(iwl_fw_rate_idx_to_plcp(rate_idx), +					  RATE_LEGACY_RATE_MSK_V1); +		break; +	case RATE_MCS_MOD_TYPE_HT: +		result = RATE_MCS_HT_MSK_V1; +		result |= u32_encode_bits(u32_get_bits(rate, +						       RATE_HT_MCS_CODE_MSK), +					  RATE_HT_MCS_RATE_CODE_MSK_V1); +		result |= u32_encode_bits(u32_get_bits(rate, +						       RATE_MCS_NSS_MSK), +					  RATE_HT_MCS_MIMO2_MSK); +		break; +	case RATE_MCS_MOD_TYPE_VHT: +		result = RATE_MCS_VHT_MSK_V1; +		result |= u32_encode_bits(u32_get_bits(rate, +						       RATE_VHT_MCS_NSS_MSK), +					  RATE_MCS_CODE_MSK); +		result |= u32_encode_bits(u32_get_bits(rate, RATE_MCS_NSS_MSK), +					  RATE_VHT_MCS_NSS_MSK); +		break; +	case RATE_MCS_MOD_TYPE_HE: /* not generated */ +	default: +		WARN_ONCE(1, "bad modulation type %d\n", +			  u32_get_bits(rate, RATE_MCS_MOD_TYPE_MSK)); +		return 0; +	} + +	if (rate & RATE_MCS_LDPC_MSK) +		result |= RATE_MCS_LDPC_MSK_V1; +	WARN_ON_ONCE(u32_get_bits(rate, RATE_MCS_CHAN_WIDTH_MSK) > +			RATE_MCS_CHAN_WIDTH_160_VAL); +	result |= (rate & RATE_MCS_CHAN_WIDTH_MSK_V1) | +		  (rate & RATE_MCS_ANT_AB_MSK) | +		  (rate & RATE_MCS_STBC_MSK) | +		  (rate & RATE_MCS_BF_MSK); + +	/* not handling DUP since we don't use it */ +	WARN_ON_ONCE(rate & RATE_MCS_DUP_MSK); + +	if (rate & RATE_MCS_SGI_MSK) +		result |= RATE_MCS_SGI_MSK_V1; + +	return cpu_to_le32(result); +} +  bool iwl_mvm_vif_is_active(struct iwl_mvm_vif *mvmvif)  {  	unsigned int i; | 
