diff options
Diffstat (limited to 'sys/contrib/dev/iwlwifi/mvm/mac-ctxt.c')
| -rw-r--r-- | sys/contrib/dev/iwlwifi/mvm/mac-ctxt.c | 259 | 
1 files changed, 137 insertions, 122 deletions
| 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(); -} | 
