diff options
Diffstat (limited to 'sys/contrib/dev/iwlwifi/mvm/utils.c')
| -rw-r--r-- | sys/contrib/dev/iwlwifi/mvm/utils.c | 258 | 
1 files changed, 190 insertions, 68 deletions
| 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; | 
