diff options
Diffstat (limited to 'drivers/net/wireless/intel')
26 files changed, 217 insertions, 112 deletions
| diff --git a/drivers/net/wireless/intel/ipw2x00/Makefile b/drivers/net/wireless/intel/ipw2x00/Makefile index aecd2cff462b..e1ec50359dff 100644 --- a/drivers/net/wireless/intel/ipw2x00/Makefile +++ b/drivers/net/wireless/intel/ipw2x00/Makefile @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0  #  # Makefile for the Intel Centrino wireless drivers  # diff --git a/drivers/net/wireless/intel/iwlegacy/Makefile b/drivers/net/wireless/intel/iwlegacy/Makefile index c826a6b985bb..c5ad0453b334 100644 --- a/drivers/net/wireless/intel/iwlegacy/Makefile +++ b/drivers/net/wireless/intel/iwlegacy/Makefile @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0  obj-$(CONFIG_IWLEGACY)	+= iwlegacy.o  iwlegacy-objs 		:= common.o  iwlegacy-$(CONFIG_IWLEGACY_DEBUGFS) += debug.o diff --git a/drivers/net/wireless/intel/iwlwifi/Makefile b/drivers/net/wireless/intel/iwlwifi/Makefile index 35a32a3ec882..595b26b66bfc 100644 --- a/drivers/net/wireless/intel/iwlwifi/Makefile +++ b/drivers/net/wireless/intel/iwlwifi/Makefile @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0  # common  obj-$(CONFIG_IWLWIFI)	+= iwlwifi.o  iwlwifi-objs		+= iwl-io.o diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/7000.c b/drivers/net/wireless/intel/iwlwifi/cfg/7000.c index 45e2efc70d19..ce741beec1fc 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/7000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/7000.c @@ -309,6 +309,7 @@ const struct iwl_cfg iwl3168_2ac_cfg = {  	.nvm_calib_ver = IWL3168_TX_POWER_VERSION,  	.pwr_tx_backoffs = iwl7265_pwr_tx_backoffs,  	.dccm_len = IWL7265_DCCM_LEN, +	.nvm_type = IWL_NVM_SDP,  };  const struct iwl_cfg iwl7265_2ac_cfg = { diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/8000.c b/drivers/net/wireless/intel/iwlwifi/cfg/8000.c index 2e6c52664cee..c2a5936ccede 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/8000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/8000.c @@ -164,7 +164,7 @@ static const struct iwl_tt_params iwl8000_tt_params = {  	.default_nvm_file_C_step = DEFAULT_NVM_FILE_FAMILY_8000C,	\  	.thermal_params = &iwl8000_tt_params,				\  	.apmg_not_supported = true,					\ -	.ext_nvm = true,						\ +	.nvm_type = IWL_NVM_EXT,					\  	.dbgc_supported = true  #define IWL_DEVICE_8000							\ diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/9000.c b/drivers/net/wireless/intel/iwlwifi/cfg/9000.c index 2babe0a1f18b..e8b5ff42f5a8 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/9000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/9000.c @@ -148,7 +148,7 @@ static const struct iwl_tt_params iwl9000_tt_params = {  	.vht_mu_mimo_supported = true,					\  	.mac_addr_from_csr = true,					\  	.rf_id = true,							\ -	.ext_nvm = true,						\ +	.nvm_type = IWL_NVM_EXT,					\  	.dbgc_supported = true  const struct iwl_cfg iwl9160_2ac_cfg = { diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/a000.c b/drivers/net/wireless/intel/iwlwifi/cfg/a000.c index 76ba1f8bc72f..a440140ed8dd 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/a000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/a000.c @@ -133,7 +133,7 @@ static const struct iwl_ht_params iwl_a000_ht_params = {  	.use_tfh = true,						\  	.rf_id = true,							\  	.gen2 = true,							\ -	.ext_nvm = true,						\ +	.nvm_type = IWL_NVM_EXT,					\  	.dbgc_supported = true  const struct iwl_cfg iwla000_2ac_cfg_hr = { diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/Makefile b/drivers/net/wireless/intel/iwlwifi/dvm/Makefile index b256a354953a..702d42b2d452 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/Makefile +++ b/drivers/net/wireless/intel/iwlwifi/dvm/Makefile @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0  # DVM  obj-$(CONFIG_IWLDVM)	+= iwldvm.o  iwldvm-objs		+= main.o rs.o mac80211.o ucode.o tx.o diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h b/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h index 00bc7a25dece..3fd07bc80f54 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h @@ -108,6 +108,7 @@ enum iwl_nvm_access_target {   * @NVM_SECTION_TYPE_REGULATORY: regulatory section   * @NVM_SECTION_TYPE_CALIBRATION: calibration section   * @NVM_SECTION_TYPE_PRODUCTION: production section + * @NVM_SECTION_TYPE_REGULATORY_SDP: regulatory section used by 3168 series   * @NVM_SECTION_TYPE_MAC_OVERRIDE: MAC override section   * @NVM_SECTION_TYPE_PHY_SKU: PHY SKU section   * @NVM_MAX_NUM_SECTIONS: number of sections @@ -117,6 +118,7 @@ enum iwl_nvm_section_type {  	NVM_SECTION_TYPE_REGULATORY = 3,  	NVM_SECTION_TYPE_CALIBRATION = 4,  	NVM_SECTION_TYPE_PRODUCTION = 5, +	NVM_SECTION_TYPE_REGULATORY_SDP = 8,  	NVM_SECTION_TYPE_MAC_OVERRIDE = 11,  	NVM_SECTION_TYPE_PHY_SKU = 12,  	NVM_MAX_NUM_SECTIONS = 13, diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c index 6afc7a799892..f5dd7d83cd0a 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c @@ -1086,7 +1086,7 @@ void iwl_fw_error_dump_wk(struct work_struct *work)  	if (fwrt->trans->cfg->device_family == IWL_DEVICE_FAMILY_7000) {  		/* stop recording */ -		iwl_set_bits_prph(fwrt->trans, MON_BUFF_SAMPLE_CTL, 0x100); +		iwl_fw_dbg_stop_recording(fwrt);  		iwl_fw_error_dump(fwrt); @@ -1104,10 +1104,7 @@ void iwl_fw_error_dump_wk(struct work_struct *work)  		u32 in_sample = iwl_read_prph(fwrt->trans, DBGC_IN_SAMPLE);  		u32 out_ctrl = iwl_read_prph(fwrt->trans, DBGC_OUT_CTRL); -		/* stop recording */ -		iwl_write_prph(fwrt->trans, DBGC_IN_SAMPLE, 0); -		udelay(100); -		iwl_write_prph(fwrt->trans, DBGC_OUT_CTRL, 0); +		iwl_fw_dbg_stop_recording(fwrt);  		/* wait before we collect the data till the DBGC stop */  		udelay(500); diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.h b/drivers/net/wireless/intel/iwlwifi/fw/dbg.h index 0f810ea89d31..9c889a32fe24 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.h @@ -68,6 +68,8 @@  #include <linux/workqueue.h>  #include <net/cfg80211.h>  #include "runtime.h" +#include "iwl-prph.h" +#include "iwl-io.h"  #include "file.h"  #include "error-dump.h" @@ -194,8 +196,21 @@ _iwl_fw_dbg_trigger_simple_stop(struct iwl_fw_runtime *fwrt,  					iwl_fw_dbg_get_trigger((fwrt)->fw,\  							       (trig))) +static inline void iwl_fw_dbg_stop_recording(struct iwl_fw_runtime *fwrt) +{ +	if (fwrt->trans->cfg->device_family == IWL_DEVICE_FAMILY_7000) { +		iwl_set_bits_prph(fwrt->trans, MON_BUFF_SAMPLE_CTL, 0x100); +	} else { +		iwl_write_prph(fwrt->trans, DBGC_IN_SAMPLE, 0); +		udelay(100); +		iwl_write_prph(fwrt->trans, DBGC_OUT_CTRL, 0); +	} +} +  static inline void iwl_fw_dump_conf_clear(struct iwl_fw_runtime *fwrt)  { +	iwl_fw_dbg_stop_recording(fwrt); +  	fwrt->dump.conf = FW_DBG_INVALID;  } diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h index 3e057b539d5b..71cb1ecde0f7 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h @@ -108,6 +108,18 @@ enum iwl_led_mode {  	IWL_LED_DISABLE,  }; +/** + * enum iwl_nvm_type - nvm formats + * @IWL_NVM: the regular format + * @IWL_NVM_EXT: extended NVM format + * @IWL_NVM_SDP: NVM format used by 3168 series + */ +enum iwl_nvm_type { +	IWL_NVM, +	IWL_NVM_EXT, +	IWL_NVM_SDP, +}; +  /*   * This is the threshold value of plcp error rate per 100mSecs.  It is   * used to set and check for the validity of plcp_delta. @@ -320,7 +332,7 @@ struct iwl_pwr_tx_backoff {   * @integrated: discrete or integrated   * @gen2: a000 and on transport operation   * @cdb: CDB support - * @ext_nvm: extended NVM format + * @nvm_type: see &enum iwl_nvm_type   *   * We enable the driver to be backward compatible wrt. hardware features.   * API differences in uCode shouldn't be handled here but through TLVs @@ -342,6 +354,7 @@ struct iwl_cfg {  	const struct iwl_tt_params *thermal_params;  	enum iwl_device_family device_family;  	enum iwl_led_mode led_mode; +	enum iwl_nvm_type nvm_type;  	u32 max_data_size;  	u32 max_inst_size;  	netdev_features_t features; @@ -369,7 +382,6 @@ struct iwl_cfg {  	    use_tfh:1,  	    gen2:1,  	    cdb:1, -	    ext_nvm:1,  	    dbgc_supported:1;  	u8 valid_tx_ant;  	u8 valid_rx_ant; diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c index 3014beef4873..c3a5d8ccc95e 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c @@ -77,7 +77,7 @@  #include "iwl-csr.h"  /* NVM offsets (in words) definitions */ -enum wkp_nvm_offsets { +enum nvm_offsets {  	/* NVM HW-Section offset (in words) definitions */  	SUBSYSTEM_ID = 0x0A,  	HW_ADDR = 0x15, @@ -92,7 +92,10 @@ enum wkp_nvm_offsets {  	/* NVM calibration section offset (in words) definitions */  	NVM_CALIB_SECTION = 0x2B8, -	XTAL_CALIB = 0x316 - NVM_CALIB_SECTION +	XTAL_CALIB = 0x316 - NVM_CALIB_SECTION, + +	/* NVM REGULATORY -Section offset (in words) definitions */ +	NVM_CHANNELS_SDP = 0,  };  enum ext_nvm_offsets { @@ -206,8 +209,36 @@ enum iwl_nvm_channel_flags {  	NVM_CHANNEL_DC_HIGH		= BIT(12),  }; +static inline void iwl_nvm_print_channel_flags(struct device *dev, u32 level, +					       int chan, u16 flags) +{  #define CHECK_AND_PRINT_I(x)	\ -	((ch_flags & NVM_CHANNEL_##x) ? # x " " : "") +	((flags & NVM_CHANNEL_##x) ? " " #x : "") + +	if (!(flags & NVM_CHANNEL_VALID)) { +		IWL_DEBUG_DEV(dev, level, "Ch. %d: 0x%x: No traffic\n", +			      chan, flags); +		return; +	} + +	/* Note: already can print up to 101 characters, 110 is the limit! */ +	IWL_DEBUG_DEV(dev, level, +		      "Ch. %d: 0x%x:%s%s%s%s%s%s%s%s%s%s%s%s\n", +		      chan, flags, +		      CHECK_AND_PRINT_I(VALID), +		      CHECK_AND_PRINT_I(IBSS), +		      CHECK_AND_PRINT_I(ACTIVE), +		      CHECK_AND_PRINT_I(RADAR), +		      CHECK_AND_PRINT_I(INDOOR_ONLY), +		      CHECK_AND_PRINT_I(GO_CONCURRENT), +		      CHECK_AND_PRINT_I(UNIFORM), +		      CHECK_AND_PRINT_I(20MHZ), +		      CHECK_AND_PRINT_I(40MHZ), +		      CHECK_AND_PRINT_I(80MHZ), +		      CHECK_AND_PRINT_I(160MHZ), +		      CHECK_AND_PRINT_I(DC_HIGH)); +#undef CHECK_AND_PRINT_I +}  static u32 iwl_get_channel_flags(u8 ch_num, int ch_idx, bool is_5ghz,  				 u16 nvm_flags, const struct iwl_cfg *cfg) @@ -215,7 +246,7 @@ static u32 iwl_get_channel_flags(u8 ch_num, int ch_idx, bool is_5ghz,  	u32 flags = IEEE80211_CHAN_NO_HT40;  	u32 last_5ghz_ht = LAST_5GHZ_HT; -	if (cfg->ext_nvm) +	if (cfg->nvm_type == IWL_NVM_EXT)  		last_5ghz_ht = LAST_5GHZ_HT_FAMILY_8000;  	if (!is_5ghz && (nvm_flags & NVM_CHANNEL_40MHZ)) { @@ -268,7 +299,7 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,  	int num_of_ch, num_2ghz_channels;  	const u8 *nvm_chan; -	if (!cfg->ext_nvm) { +	if (cfg->nvm_type != IWL_NVM_EXT) {  		num_of_ch = IWL_NUM_CHANNELS;  		nvm_chan = &iwl_nvm_channels[0];  		num_2ghz_channels = NUM_2GHZ_CHANNELS; @@ -302,12 +333,8 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,  			 * supported, hence we still want to add them to  			 * the list of supported channels to cfg80211.  			 */ -			IWL_DEBUG_EEPROM(dev, -					 "Ch. %d Flags %x [%sGHz] - No traffic\n", -					 nvm_chan[ch_idx], -					 ch_flags, -					 (ch_idx >= num_2ghz_channels) ? -					 "5.2" : "2.4"); +			iwl_nvm_print_channel_flags(dev, IWL_DL_EEPROM, +						    nvm_chan[ch_idx], ch_flags);  			continue;  		} @@ -337,27 +364,10 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,  		else  			channel->flags = 0; -		IWL_DEBUG_EEPROM(dev, -				 "Ch. %d [%sGHz] flags 0x%x %s%s%s%s%s%s%s%s%s%s%s%s(%ddBm): Ad-Hoc %ssupported\n", -				 channel->hw_value, -				 is_5ghz ? "5.2" : "2.4", -				 ch_flags, -				 CHECK_AND_PRINT_I(VALID), -				 CHECK_AND_PRINT_I(IBSS), -				 CHECK_AND_PRINT_I(ACTIVE), -				 CHECK_AND_PRINT_I(RADAR), -				 CHECK_AND_PRINT_I(INDOOR_ONLY), -				 CHECK_AND_PRINT_I(GO_CONCURRENT), -				 CHECK_AND_PRINT_I(UNIFORM), -				 CHECK_AND_PRINT_I(20MHZ), -				 CHECK_AND_PRINT_I(40MHZ), -				 CHECK_AND_PRINT_I(80MHZ), -				 CHECK_AND_PRINT_I(160MHZ), -				 CHECK_AND_PRINT_I(DC_HIGH), -				 channel->max_power, -				 ((ch_flags & NVM_CHANNEL_IBSS) && -				  !(ch_flags & NVM_CHANNEL_RADAR)) -					? "" : "not "); +		iwl_nvm_print_channel_flags(dev, IWL_DL_EEPROM, +					    channel->hw_value, ch_flags); +		IWL_DEBUG_EEPROM(dev, "Ch. %d: %ddBm\n", +				 channel->hw_value, channel->max_power);  	}  	return n_channels; @@ -484,7 +494,7 @@ IWL_EXPORT_SYMBOL(iwl_init_sbands);  static int iwl_get_sku(const struct iwl_cfg *cfg, const __le16 *nvm_sw,  		       const __le16 *phy_sku)  { -	if (!cfg->ext_nvm) +	if (cfg->nvm_type != IWL_NVM_EXT)  		return le16_to_cpup(nvm_sw + SKU);  	return le32_to_cpup((__le32 *)(phy_sku + SKU_FAMILY_8000)); @@ -492,7 +502,7 @@ static int iwl_get_sku(const struct iwl_cfg *cfg, const __le16 *nvm_sw,  static int iwl_get_nvm_version(const struct iwl_cfg *cfg, const __le16 *nvm_sw)  { -	if (!cfg->ext_nvm) +	if (cfg->nvm_type != IWL_NVM_EXT)  		return le16_to_cpup(nvm_sw + NVM_VERSION);  	else  		return le32_to_cpup((__le32 *)(nvm_sw + @@ -502,7 +512,7 @@ static int iwl_get_nvm_version(const struct iwl_cfg *cfg, const __le16 *nvm_sw)  static int iwl_get_radio_cfg(const struct iwl_cfg *cfg, const __le16 *nvm_sw,  			     const __le16 *phy_sku)  { -	if (!cfg->ext_nvm) +	if (cfg->nvm_type != IWL_NVM_EXT)  		return le16_to_cpup(nvm_sw + RADIO_CFG);  	return le32_to_cpup((__le32 *)(phy_sku + RADIO_CFG_FAMILY_EXT_NVM)); @@ -513,7 +523,7 @@ static int iwl_get_n_hw_addrs(const struct iwl_cfg *cfg, const __le16 *nvm_sw)  {  	int n_hw_addr; -	if (!cfg->ext_nvm) +	if (cfg->nvm_type != IWL_NVM_EXT)  		return le16_to_cpup(nvm_sw + N_HW_ADDRS);  	n_hw_addr = le32_to_cpup((__le32 *)(nvm_sw + N_HW_ADDRS_FAMILY_8000)); @@ -525,7 +535,7 @@ static void iwl_set_radio_cfg(const struct iwl_cfg *cfg,  			      struct iwl_nvm_data *data,  			      u32 radio_cfg)  { -	if (!cfg->ext_nvm) { +	if (cfg->nvm_type != IWL_NVM_EXT) {  		data->radio_cfg_type = NVM_RF_CFG_TYPE_MSK(radio_cfg);  		data->radio_cfg_step = NVM_RF_CFG_STEP_MSK(radio_cfg);  		data->radio_cfg_dash = NVM_RF_CFG_DASH_MSK(radio_cfg); @@ -634,7 +644,7 @@ static int iwl_set_hw_address(struct iwl_trans *trans,  {  	if (cfg->mac_addr_from_csr) {  		iwl_set_hw_address_from_csr(trans, data); -	} else if (!cfg->ext_nvm) { +	} else if (cfg->nvm_type != IWL_NVM_EXT) {  		const u8 *hw_addr = (const u8 *)(nvm_hw + HW_ADDR);  		/* The byte order is little endian 16 bit, meaning 214365 */ @@ -706,7 +716,7 @@ iwl_parse_nvm_data(struct iwl_trans *trans, const struct iwl_cfg *cfg,  	u16 lar_config;  	const __le16 *ch_section; -	if (!cfg->ext_nvm) +	if (cfg->nvm_type != IWL_NVM_EXT)  		data = kzalloc(sizeof(*data) +  			       sizeof(struct ieee80211_channel) *  			       IWL_NUM_CHANNELS, @@ -740,7 +750,7 @@ iwl_parse_nvm_data(struct iwl_trans *trans, const struct iwl_cfg *cfg,  	data->n_hw_addrs = iwl_get_n_hw_addrs(cfg, nvm_sw); -	if (!cfg->ext_nvm) { +	if (cfg->nvm_type != IWL_NVM_EXT) {  		/* Checking for required sections */  		if (!nvm_calib) {  			IWL_ERR(trans, @@ -748,11 +758,15 @@ iwl_parse_nvm_data(struct iwl_trans *trans, const struct iwl_cfg *cfg,  			kfree(data);  			return NULL;  		} + +		ch_section = cfg->nvm_type == IWL_NVM_SDP ? +			     ®ulatory[NVM_CHANNELS_SDP] : +			     &nvm_sw[NVM_CHANNELS]; +  		/* in family 8000 Xtal calibration values moved to OTP */  		data->xtal_calib[0] = *(nvm_calib + XTAL_CALIB);  		data->xtal_calib[1] = *(nvm_calib + XTAL_CALIB + 1);  		lar_enabled = true; -		ch_section = &nvm_sw[NVM_CHANNELS];  	} else {  		u16 lar_offset = data->nvm_version < 0xE39 ?  				 NVM_LAR_OFFSET_OLD : @@ -786,7 +800,7 @@ static u32 iwl_nvm_get_regdom_bw_flags(const u8 *nvm_chan,  	u32 flags = NL80211_RRF_NO_HT40;  	u32 last_5ghz_ht = LAST_5GHZ_HT; -	if (cfg->ext_nvm) +	if (cfg->nvm_type == IWL_NVM_EXT)  		last_5ghz_ht = LAST_5GHZ_HT_FAMILY_8000;  	if (ch_idx < NUM_2GHZ_CHANNELS && @@ -834,7 +848,7 @@ iwl_parse_nvm_mcc_info(struct device *dev, const struct iwl_cfg *cfg,  	int ch_idx;  	u16 ch_flags;  	u32 reg_rule_flags, prev_reg_rule_flags = 0; -	const u8 *nvm_chan = cfg->ext_nvm ? +	const u8 *nvm_chan = cfg->nvm_type == IWL_NVM_EXT ?  			     iwl_ext_nvm_channels : iwl_nvm_channels;  	struct ieee80211_regdomain *regd;  	int size_of_regd; @@ -843,7 +857,7 @@ iwl_parse_nvm_mcc_info(struct device *dev, const struct iwl_cfg *cfg,  	int center_freq, prev_center_freq = 0;  	int valid_rules = 0;  	bool new_rule; -	int max_num_ch = cfg->ext_nvm ? +	int max_num_ch = cfg->nvm_type == IWL_NVM_EXT ?  			 IWL_NUM_CHANNELS_EXT : IWL_NUM_CHANNELS;  	if (WARN_ON_ONCE(num_of_ch > NL80211_MAX_SUPP_REG_RULES)) @@ -873,12 +887,8 @@ iwl_parse_nvm_mcc_info(struct device *dev, const struct iwl_cfg *cfg,  		new_rule = false;  		if (!(ch_flags & NVM_CHANNEL_VALID)) { -			IWL_DEBUG_DEV(dev, IWL_DL_LAR, -				      "Ch. %d Flags %x [%sGHz] - No traffic\n", -				      nvm_chan[ch_idx], -				      ch_flags, -				      (ch_idx >= NUM_2GHZ_CHANNELS) ? -				      "5.2" : "2.4"); +			iwl_nvm_print_channel_flags(dev, IWL_DL_LAR, +						    nvm_chan[ch_idx], ch_flags);  			continue;  		} @@ -914,31 +924,8 @@ iwl_parse_nvm_mcc_info(struct device *dev, const struct iwl_cfg *cfg,  		prev_center_freq = center_freq;  		prev_reg_rule_flags = reg_rule_flags; -		IWL_DEBUG_DEV(dev, IWL_DL_LAR, -			      "Ch. %d [%sGHz] %s%s%s%s%s%s%s%s%s%s%s%s(0x%02x)\n", -			      center_freq, -			      band == NL80211_BAND_5GHZ ? "5.2" : "2.4", -			      CHECK_AND_PRINT_I(VALID), -			      CHECK_AND_PRINT_I(IBSS), -			      CHECK_AND_PRINT_I(ACTIVE), -			      CHECK_AND_PRINT_I(RADAR), -			      CHECK_AND_PRINT_I(INDOOR_ONLY), -			      CHECK_AND_PRINT_I(GO_CONCURRENT), -			      CHECK_AND_PRINT_I(UNIFORM), -			      CHECK_AND_PRINT_I(20MHZ), -			      CHECK_AND_PRINT_I(40MHZ), -			      CHECK_AND_PRINT_I(80MHZ), -			      CHECK_AND_PRINT_I(160MHZ), -			      CHECK_AND_PRINT_I(DC_HIGH), -			      ch_flags); -		IWL_DEBUG_DEV(dev, IWL_DL_LAR, -			      "Ch. %d [%sGHz] reg_flags 0x%x: %s\n", -			      center_freq, -			      band == NL80211_BAND_5GHZ ? "5.2" : "2.4", -			      reg_rule_flags, -			      ((ch_flags & NVM_CHANNEL_ACTIVE) && -			       !(ch_flags & NVM_CHANNEL_RADAR)) -					 ? "Ad-Hoc" : ""); +		iwl_nvm_print_channel_flags(dev, IWL_DL_LAR, +					    nvm_chan[ch_idx], ch_flags);  	}  	regd->n_reg_rules = valid_rules; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/Makefile b/drivers/net/wireless/intel/iwlwifi/mvm/Makefile index 00e6737dda72..a47635c32c11 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/Makefile +++ b/drivers/net/wireless/intel/iwlwifi/mvm/Makefile @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0  obj-$(CONFIG_IWLMVM)   += iwlmvm.o  iwlmvm-y += fw.o mac80211.o nvm.o ops.o phy-ctxt.o mac-ctxt.o  iwlmvm-y += utils.o rx.o rxmq.o tx.o binding.o quota.o sta.o sf.o diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index 5de19ea10575..b205a7bfb828 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -2167,7 +2167,7 @@ out:  	 * 1. We are not using a unified image  	 * 2. We are using a unified image but had an error while exiting D3  	 */ -	set_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status); +	set_bit(IWL_MVM_STATUS_HW_RESTART_REQUESTED, &mvm->status);  	set_bit(IWL_MVM_STATUS_D3_RECONFIG, &mvm->status);  	/*  	 * When switching images we return 1, which causes mac80211 diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 15f2d826bb4b..a9ac872226fd 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -1077,6 +1077,7 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm)  	mvm->vif_count = 0;  	mvm->rx_ba_sessions = 0;  	mvm->fwrt.dump.conf = FW_DBG_INVALID; +	mvm->monitor_on = false;  	/* keep statistics ticking */  	iwl_mvm_accu_radio_stats(mvm); @@ -1437,6 +1438,9 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,  		mvm->p2p_device_vif = vif;  	} +	if (vif->type == NL80211_IFTYPE_MONITOR) +		mvm->monitor_on = true; +  	iwl_mvm_vif_dbgfs_register(mvm, vif);  	goto out_unlock; @@ -1526,6 +1530,9 @@ static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw,  	iwl_mvm_power_update_mac(mvm);  	iwl_mvm_mac_ctxt_remove(mvm, vif); +	if (vif->type == NL80211_IFTYPE_MONITOR) +		mvm->monitor_on = false; +  out_release:  	mutex_unlock(&mvm->mutex);  } @@ -1546,6 +1553,11 @@ static void iwl_mvm_mc_iface_iterator(void *_data, u8 *mac,  	struct iwl_mvm_mc_iter_data *data = _data;  	struct iwl_mvm *mvm = data->mvm;  	struct iwl_mcast_filter_cmd *cmd = mvm->mcast_filter_cmd; +	struct iwl_host_cmd hcmd = { +		.id = MCAST_FILTER_CMD, +		.flags = CMD_ASYNC, +		.dataflags[0] = IWL_HCMD_DFL_NOCOPY, +	};  	int ret, len;  	/* if we don't have free ports, mcast frames will be dropped */ @@ -1560,7 +1572,10 @@ static void iwl_mvm_mc_iface_iterator(void *_data, u8 *mac,  	memcpy(cmd->bssid, vif->bss_conf.bssid, ETH_ALEN);  	len = roundup(sizeof(*cmd) + cmd->count * ETH_ALEN, 4); -	ret = iwl_mvm_send_cmd_pdu(mvm, MCAST_FILTER_CMD, CMD_ASYNC, len, cmd); +	hcmd.len[0] = len; +	hcmd.data[0] = cmd; + +	ret = iwl_mvm_send_cmd(mvm, &hcmd);  	if (ret)  		IWL_ERR(mvm, "mcast filter cmd error. ret=%d\n", ret);  } @@ -1635,6 +1650,12 @@ static void iwl_mvm_configure_filter(struct ieee80211_hw *hw,  	if (!cmd)  		goto out; +	if (changed_flags & FIF_ALLMULTI) +		cmd->pass_all = !!(*total_flags & FIF_ALLMULTI); + +	if (cmd->pass_all) +		cmd->count = 0; +  	iwl_mvm_recalc_multicast(mvm);  out:  	mutex_unlock(&mvm->mutex); @@ -2563,7 +2584,7 @@ static void iwl_mvm_purge_deferred_tx_frames(struct iwl_mvm *mvm,  			 * queues, so we should never get a second deferred  			 * frame for the RA/TID.  			 */ -			iwl_mvm_start_mac_queues(mvm, info->hw_queue); +			iwl_mvm_start_mac_queues(mvm, BIT(info->hw_queue));  			ieee80211_free_txskb(mvm->hw, skb);  		}  	} @@ -3975,6 +3996,43 @@ out_unlock:  	return ret;  } +static void iwl_mvm_flush_no_vif(struct iwl_mvm *mvm, u32 queues, bool drop) +{ +	if (drop) { +		if (iwl_mvm_has_new_tx_api(mvm)) +			/* TODO new tx api */ +			WARN_ONCE(1, +				  "Need to implement flush TX queue\n"); +		else +			iwl_mvm_flush_tx_path(mvm, +				iwl_mvm_flushable_queues(mvm) & queues, +				0); +	} else { +		if (iwl_mvm_has_new_tx_api(mvm)) { +			struct ieee80211_sta *sta; +			int i; + +			mutex_lock(&mvm->mutex); + +			for (i = 0; i < ARRAY_SIZE(mvm->fw_id_to_mac_id); i++) { +				sta = rcu_dereference_protected( +						mvm->fw_id_to_mac_id[i], +						lockdep_is_held(&mvm->mutex)); +				if (IS_ERR_OR_NULL(sta)) +					continue; + +				iwl_mvm_wait_sta_queues_empty(mvm, +						iwl_mvm_sta_from_mac80211(sta)); +			} + +			mutex_unlock(&mvm->mutex); +		} else { +			iwl_trans_wait_tx_queues_empty(mvm->trans, +						       queues); +		} +	} +} +  static void iwl_mvm_mac_flush(struct ieee80211_hw *hw,  			      struct ieee80211_vif *vif, u32 queues, bool drop)  { @@ -3985,7 +4043,12 @@ static void iwl_mvm_mac_flush(struct ieee80211_hw *hw,  	int i;  	u32 msk = 0; -	if (!vif || vif->type != NL80211_IFTYPE_STATION) +	if (!vif) { +		iwl_mvm_flush_no_vif(mvm, queues, drop); +		return; +	} + +	if (vif->type != NL80211_IFTYPE_STATION)  		return;  	/* Make sure we're done with the deferred traffic before flushing */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 83303bac0e4b..949e63418299 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -1015,6 +1015,9 @@ struct iwl_mvm {  	bool drop_bcn_ap_mode;  	struct delayed_work cs_tx_unblock_dwork; + +	/* does a monitor vif exist (only one can exist hence bool) */ +	bool monitor_on;  #ifdef CONFIG_ACPI  	struct iwl_mvm_sar_profile sar_profiles[IWL_MVM_SAR_PROFILE_NUM];  	struct iwl_mvm_geo_profile geo_profiles[IWL_NUM_GEO_PROFILES]; @@ -1159,7 +1162,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->ext_nvm) +	if (mvm->cfg->nvm_type == IWL_NVM_EXT)  		return nvm_lar && tlv_lar;  	else  		return tlv_lar; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c index 422aa6be9932..fb25b6f29323 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c @@ -295,18 +295,24 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm)  	const __be16 *hw;  	const __le16 *sw, *calib, *regulatory, *mac_override, *phy_sku;  	bool lar_enabled; +	int regulatory_type;  	/* Checking for required sections */ -	if (!mvm->trans->cfg->ext_nvm) { +	if (mvm->trans->cfg->nvm_type != IWL_NVM_EXT) {  		if (!mvm->nvm_sections[NVM_SECTION_TYPE_SW].data ||  		    !mvm->nvm_sections[mvm->cfg->nvm_hw_section_num].data) {  			IWL_ERR(mvm, "Can't parse empty OTP/NVM sections\n");  			return NULL;  		}  	} else { +		if (mvm->trans->cfg->nvm_type == IWL_NVM_SDP) +			regulatory_type = NVM_SECTION_TYPE_REGULATORY_SDP; +		else +			regulatory_type = NVM_SECTION_TYPE_REGULATORY; +  		/* SW and REGULATORY sections are mandatory */  		if (!mvm->nvm_sections[NVM_SECTION_TYPE_SW].data || -		    !mvm->nvm_sections[NVM_SECTION_TYPE_REGULATORY].data) { +		    !mvm->nvm_sections[regulatory_type].data) {  			IWL_ERR(mvm,  				"Can't parse empty family 8000 OTP/NVM sections\n");  			return NULL; @@ -330,11 +336,14 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm)  	hw = (const __be16 *)sections[mvm->cfg->nvm_hw_section_num].data;  	sw = (const __le16 *)sections[NVM_SECTION_TYPE_SW].data;  	calib = (const __le16 *)sections[NVM_SECTION_TYPE_CALIBRATION].data; -	regulatory = (const __le16 *)sections[NVM_SECTION_TYPE_REGULATORY].data;  	mac_override =  		(const __le16 *)sections[NVM_SECTION_TYPE_MAC_OVERRIDE].data;  	phy_sku = (const __le16 *)sections[NVM_SECTION_TYPE_PHY_SKU].data; +	regulatory = mvm->trans->cfg->nvm_type == IWL_NVM_SDP ? +		(const __le16 *)sections[NVM_SECTION_TYPE_REGULATORY_SDP].data : +		(const __le16 *)sections[NVM_SECTION_TYPE_REGULATORY].data; +  	lar_enabled = !iwlwifi_mod_params.lar_disable &&  		      fw_has_capa(&mvm->fw->ucode_capa,  				  IWL_UCODE_TLV_CAPA_LAR_SUPPORT); @@ -394,7 +403,7 @@ int iwl_mvm_read_external_nvm(struct iwl_mvm *mvm)  	IWL_DEBUG_EEPROM(mvm->trans->dev, "Read from external NVM\n");  	/* Maximal size depends on NVM version */ -	if (!mvm->trans->cfg->ext_nvm) +	if (mvm->trans->cfg->nvm_type != IWL_NVM_EXT)  		max_section_size = IWL_MAX_NVM_SECTION_SIZE;  	else  		max_section_size = IWL_MAX_EXT_NVM_SECTION_SIZE; @@ -465,7 +474,7 @@ int iwl_mvm_read_external_nvm(struct iwl_mvm *mvm)  			break;  		} -		if (!mvm->trans->cfg->ext_nvm) { +		if (mvm->trans->cfg->nvm_type != IWL_NVM_EXT) {  			section_size =  				2 * NVM_WORD1_LEN(le16_to_cpu(file_sec->word1));  			section_id = NVM_WORD2_ID(le16_to_cpu(file_sec->word2)); @@ -740,7 +749,7 @@ int iwl_mvm_init_mcc(struct iwl_mvm *mvm)  	struct ieee80211_regdomain *regd;  	char mcc[3]; -	if (mvm->cfg->ext_nvm) { +	if (mvm->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; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c index ba7bd049d3d4..0fe723ca844e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c @@ -661,7 +661,8 @@ static void rs_tl_turn_on_agg(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta,  	    (lq_sta->tx_agg_tid_en & BIT(tid)) &&  	    (tid_data->tx_count_last >= IWL_MVM_RS_AGG_START_THRESHOLD)) {  		IWL_DEBUG_RATE(mvm, "try to aggregate tid %d\n", tid); -		rs_tl_turn_on_agg_for_tid(mvm, lq_sta, tid, sta); +		if (rs_tl_turn_on_agg_for_tid(mvm, lq_sta, tid, sta) == 0) +			tid_data->state = IWL_AGG_QUEUED;  	}  } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c index 184c749766f2..2d14a58cbdd7 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c @@ -244,7 +244,9 @@ static u32 iwl_mvm_set_mac80211_rx_flag(struct iwl_mvm *mvm,  		return 0;  	default: -		IWL_ERR(mvm, "Unhandled alg: 0x%x\n", rx_pkt_status); +		/* Expected in monitor (not having the keys) */ +		if (!mvm->monitor_on) +			IWL_ERR(mvm, "Unhandled alg: 0x%x\n", rx_pkt_status);  	}  	return 0; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index 67ffd9774712..248699c2c4bf 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -277,7 +277,9 @@ static int iwl_mvm_rx_crypto(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr,  		stats->flag |= RX_FLAG_DECRYPTED;  		return 0;  	default: -		IWL_ERR(mvm, "Unhandled alg: 0x%x\n", status); +		/* Expected in monitor (not having the keys) */ +		if (!mvm->monitor_on) +			IWL_ERR(mvm, "Unhandled alg: 0x%x\n", status);  	}  	return 0; @@ -672,11 +674,12 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm,  	 * If there was a significant jump in the nssn - adjust.  	 * If the SN is smaller than the NSSN it might need to first go into  	 * the reorder buffer, in which case we just release up to it and the -	 * rest of the function will take of storing it and releasing up to the -	 * nssn +	 * rest of the function will take care of storing it and releasing up to +	 * the nssn  	 */  	if (!iwl_mvm_is_sn_less(nssn, buffer->head_sn + buffer->buf_size, -				buffer->buf_size)) { +				buffer->buf_size) || +	    !ieee80211_sn_less(sn, buffer->head_sn + buffer->buf_size)) {  		u16 min_sn = ieee80211_sn_less(sn, nssn) ? sn : nssn;  		iwl_mvm_release_frames(mvm, sta, napi, buffer, min_sn); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c index 50983615dce6..774122fed454 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c @@ -555,7 +555,7 @@ static int iwl_mvm_lmac_scan_abort(struct iwl_mvm *mvm)  	struct iwl_host_cmd cmd = {  		.id = SCAN_OFFLOAD_ABORT_CMD,  	}; -	u32 status; +	u32 status = CAN_ABORT_STATUS;  	ret = iwl_mvm_send_cmd_status(mvm, &cmd, &status);  	if (ret) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index 411a2055dc45..c4a343534c5e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -1285,7 +1285,7 @@ static int iwl_mvm_add_int_sta_common(struct iwl_mvm *mvm,  {  	struct iwl_mvm_add_sta_cmd cmd;  	int ret; -	u32 status; +	u32 status = ADD_STA_SUCCESS;  	lockdep_assert_held(&mvm->mutex); @@ -2385,8 +2385,10 @@ int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif,  	if (WARN_ON_ONCE(tid >= IWL_MAX_TID_COUNT))  		return -EINVAL; -	if (mvmsta->tid_data[tid].state != IWL_AGG_OFF) { -		IWL_ERR(mvm, "Start AGG when state is not IWL_AGG_OFF %d!\n", +	if (mvmsta->tid_data[tid].state != IWL_AGG_QUEUED && +	    mvmsta->tid_data[tid].state != IWL_AGG_OFF) { +		IWL_ERR(mvm, +			"Start AGG when state is not IWL_AGG_QUEUED or IWL_AGG_OFF %d!\n",  			mvmsta->tid_data[tid].state);  		return -ENXIO;  	} diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h index d13893806513..aedabe101cf0 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h @@ -281,6 +281,7 @@ struct iwl_mvm_vif;   * These states relate to a specific RA / TID.   *   * @IWL_AGG_OFF: aggregation is not used + * @IWL_AGG_QUEUED: aggregation start work has been queued   * @IWL_AGG_STARTING: aggregation are starting (between start and oper)   * @IWL_AGG_ON: aggregation session is up   * @IWL_EMPTYING_HW_QUEUE_ADDBA: establishing a BA session - waiting for the @@ -290,6 +291,7 @@ struct iwl_mvm_vif;   */  enum iwl_mvm_agg_state {  	IWL_AGG_OFF = 0, +	IWL_AGG_QUEUED,  	IWL_AGG_STARTING,  	IWL_AGG_ON,  	IWL_EMPTYING_HW_QUEUE_ADDBA, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tt.c b/drivers/net/wireless/intel/iwlwifi/mvm/tt.c index 8876c2abc440..1232f63278eb 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tt.c @@ -529,6 +529,7 @@ int iwl_mvm_ctdp_command(struct iwl_mvm *mvm, u32 op, u32 state)  	lockdep_assert_held(&mvm->mutex); +	status = 0;  	ret = iwl_mvm_send_cmd_pdu_status(mvm, WIDE_ID(PHY_OPS_GROUP,  						       CTDP_CONFIG_CMD),  					  sizeof(cmd), &cmd, &status); @@ -630,7 +631,7 @@ static int iwl_mvm_tzone_get_temp(struct thermal_zone_device *device,  	if (!iwl_mvm_firmware_running(mvm) ||  	    mvm->fwrt.cur_fw_img != IWL_UCODE_REGULAR) { -		ret = -EIO; +		ret = -ENODATA;  		goto out;  	} diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index 172b5e63d3fb..6f2e2af23219 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -564,8 +564,8 @@ static int iwl_mvm_get_ctrl_vif_queue(struct iwl_mvm *mvm,  	case NL80211_IFTYPE_AP:  	case NL80211_IFTYPE_ADHOC:  		/* -		 * Handle legacy hostapd as well, where station will be added -		 * only just before sending the association response. +		 * Non-bufferable frames use the broadcast station, thus they +		 * use the probe queue.  		 * Also take care of the case where we send a deauth to a  		 * station that we don't have, or similarly an association  		 * response (with non-success status) for a station we can't @@ -573,9 +573,9 @@ static int iwl_mvm_get_ctrl_vif_queue(struct iwl_mvm *mvm,  		 * Also, disassociate frames might happen, particular with  		 * reason 7 ("Class 3 frame received from nonassociated STA").  		 */ -		if (ieee80211_is_probe_resp(fc) || ieee80211_is_auth(fc) || -		    ieee80211_is_deauth(fc) || ieee80211_is_assoc_resp(fc) || -		    ieee80211_is_disassoc(fc)) +		if (ieee80211_is_mgmt(fc) && +		    (!ieee80211_is_bufferable_mmpdu(fc) || +		     ieee80211_is_deauth(fc) || ieee80211_is_disassoc(fc)))  			return mvm->probe_queue;  		if (info->hw_queue == info->control.vif->cab_queue)  			return mvmvif->cab_queue; |