All of lore.kernel.org
 help / color / mirror / Atom feed
* Patch "iwlwifi: add workaround to disable wide channels in 5GHz" has been added to the 4.13-stable tree
@ 2017-09-22  9:36 gregkh
  2017-09-22  9:50 ` Greg KH
  0 siblings, 1 reply; 10+ messages in thread
From: gregkh @ 2017-09-22  9:36 UTC (permalink / raw)
  To: luciano.coelho, gregkh; +Cc: stable, stable-commits


This is a note to let you know that I've just added the patch titled

    iwlwifi: add workaround to disable wide channels in 5GHz

to the 4.13-stable tree which can be found at:
    http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
     iwlwifi-add-workaround-to-disable-wide-channels-in-5ghz.patch
and it can be found in the queue-4.13 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <stable@vger.kernel.org> know about it.


>From 01a9c948a09348950515bf2abb6113ed83e696d8 Mon Sep 17 00:00:00 2001
From: Luca Coelho <luciano.coelho@intel.com>
Date: Tue, 15 Aug 2017 20:48:41 +0300
Subject: iwlwifi: add workaround to disable wide channels in 5GHz

From: Luca Coelho <luciano.coelho@intel.com>

commit 01a9c948a09348950515bf2abb6113ed83e696d8 upstream.

The OTP in some SKUs have erroneously allowed 40MHz and 80MHz channels
in the 5.2GHz band.  The firmware has been modified to not allow this
in those SKUs, so the driver needs to do the same otherwise the
firmware will assert when we try to use it.

Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

diff --git a/drivers/net/wireless/intel/iwlwifi/fw/nvm.c b/drivers/net/wireless/intel/iwlwifi/fw/nvm.c
index ae03d0f5564f..e81f6dd3744e 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/nvm.c
+++ b/drivers/net/wireless/intel/iwlwifi/fw/nvm.c
@@ -148,7 +148,8 @@ struct iwl_nvm_data *iwl_fw_get_nvm(struct iwl_fw_runtime *fwrt)
 			rsp->regulatory.channel_profile,
 			nvm->valid_tx_ant & fwrt->fw->valid_tx_ant,
 			nvm->valid_rx_ant & fwrt->fw->valid_rx_ant,
-			rsp->regulatory.lar_enabled && lar_fw_supported);
+			rsp->regulatory.lar_enabled && lar_fw_supported,
+			false);
 
 	iwl_free_resp(&hcmd);
 	return nvm;
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
index 1172e4572a82..ea165b3e6dd3 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
@@ -79,6 +79,7 @@
 /* NVM offsets (in words) definitions */
 enum wkp_nvm_offsets {
 	/* NVM HW-Section offset (in words) definitions */
+	SUBSYSTEM_ID = 0x0A,
 	HW_ADDR = 0x15,
 
 	/* NVM SW-Section offset (in words) definitions */
@@ -258,13 +259,12 @@ static u32 iwl_get_channel_flags(u8 ch_num, int ch_idx, bool is_5ghz,
 static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
 				struct iwl_nvm_data *data,
 				const __le16 * const nvm_ch_flags,
-				bool lar_supported)
+				bool lar_supported, bool no_wide_in_5ghz)
 {
 	int ch_idx;
 	int n_channels = 0;
 	struct ieee80211_channel *channel;
 	u16 ch_flags;
-	bool is_5ghz;
 	int num_of_ch, num_2ghz_channels;
 	const u8 *nvm_chan;
 
@@ -279,12 +279,20 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
 	}
 
 	for (ch_idx = 0; ch_idx < num_of_ch; ch_idx++) {
+		bool is_5ghz = (ch_idx >= num_2ghz_channels);
+
 		ch_flags = __le16_to_cpup(nvm_ch_flags + ch_idx);
 
-		if (ch_idx >= num_2ghz_channels &&
-		    !data->sku_cap_band_52GHz_enable)
+		if (is_5ghz && !data->sku_cap_band_52GHz_enable)
 			continue;
 
+		/* workaround to disable wide channels in 5GHz */
+		if (no_wide_in_5ghz && is_5ghz) {
+			ch_flags &= ~(NVM_CHANNEL_40MHZ |
+				     NVM_CHANNEL_80MHZ |
+				     NVM_CHANNEL_160MHZ);
+		}
+
 		if (ch_flags & NVM_CHANNEL_160MHZ)
 			data->vht160_supported = true;
 
@@ -307,8 +315,8 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
 		n_channels++;
 
 		channel->hw_value = nvm_chan[ch_idx];
-		channel->band = (ch_idx < num_2ghz_channels) ?
-				NL80211_BAND_2GHZ : NL80211_BAND_5GHZ;
+		channel->band = is_5ghz ?
+				NL80211_BAND_5GHZ : NL80211_BAND_2GHZ;
 		channel->center_freq =
 			ieee80211_channel_to_frequency(
 				channel->hw_value, channel->band);
@@ -320,7 +328,6 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
 		 * is not used in mvm, and is used for backwards compatibility
 		 */
 		channel->max_power = IWL_DEFAULT_MAX_TX_POWER;
-		is_5ghz = channel->band == NL80211_BAND_5GHZ;
 
 		/* don't put limitations in case we're using LAR */
 		if (!lar_supported)
@@ -438,14 +445,15 @@ static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg,
 
 void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg,
 		     struct iwl_nvm_data *data, const __le16 *nvm_ch_flags,
-		     u8 tx_chains, u8 rx_chains, bool lar_supported)
+		     u8 tx_chains, u8 rx_chains, bool lar_supported,
+		     bool no_wide_in_5ghz)
 {
 	int n_channels;
 	int n_used = 0;
 	struct ieee80211_supported_band *sband;
 
 	n_channels = iwl_init_channel_map(dev, cfg, data, nvm_ch_flags,
-					  lar_supported);
+					  lar_supported, no_wide_in_5ghz);
 	sband = &data->bands[NL80211_BAND_2GHZ];
 	sband->band = NL80211_BAND_2GHZ;
 	sband->bitrates = &iwl_cfg80211_rates[RATES_24_OFFS];
@@ -651,6 +659,39 @@ static int iwl_set_hw_address(struct iwl_trans *trans,
 	return 0;
 }
 
+static bool
+iwl_nvm_no_wide_in_5ghz(struct device *dev, const struct iwl_cfg *cfg,
+			const __le16 *nvm_hw)
+{
+	/*
+	 * Workaround a bug in Indonesia SKUs where the regulatory in
+	 * some 7000-family OTPs erroneously allow wide channels in
+	 * 5GHz.  To check for Indonesia, we take the SKU value from
+	 * bits 1-4 in the subsystem ID and check if it is either 5 or
+	 * 9.  In those cases, we need to force-disable wide channels
+	 * in 5GHz otherwise the FW will throw a sysassert when we try
+	 * to use them.
+	 */
+	if (cfg->device_family == IWL_DEVICE_FAMILY_7000) {
+		/*
+		 * Unlike the other sections in the NVM, the hw
+		 * section uses big-endian.
+		 */
+		u16 subsystem_id = be16_to_cpup((const __be16 *)nvm_hw
+						+ SUBSYSTEM_ID);
+		u8 sku = (subsystem_id & 0x1e) >> 1;
+
+		if (sku == 5 || sku == 9) {
+			IWL_DEBUG_EEPROM(dev,
+					 "disabling wide channels in 5GHz (0x%0x %d)\n",
+					 subsystem_id, sku);
+			return true;
+		}
+	}
+
+	return false;
+}
+
 struct iwl_nvm_data *
 iwl_parse_nvm_data(struct iwl_trans *trans, const struct iwl_cfg *cfg,
 		   const __le16 *nvm_hw, const __le16 *nvm_sw,
@@ -661,6 +702,7 @@ iwl_parse_nvm_data(struct iwl_trans *trans, const struct iwl_cfg *cfg,
 	struct device *dev = trans->dev;
 	struct iwl_nvm_data *data;
 	bool lar_enabled;
+	bool no_wide_in_5ghz = iwl_nvm_no_wide_in_5ghz(dev, cfg, nvm_hw);
 	u32 sku, radio_cfg;
 	u16 lar_config;
 	const __le16 *ch_section;
@@ -731,7 +773,7 @@ iwl_parse_nvm_data(struct iwl_trans *trans, const struct iwl_cfg *cfg,
 	}
 
 	iwl_init_sbands(dev, cfg, data, ch_section, tx_chains, rx_chains,
-			lar_fw_supported && lar_enabled);
+			lar_fw_supported && lar_enabled, no_wide_in_5ghz);
 	data->calib_version = 255;
 
 	return data;
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h
index 3fd6506a02ab..50d9b3eaa4f8 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h
@@ -93,7 +93,8 @@ void iwl_set_hw_address_from_csr(struct iwl_trans *trans,
  */
 void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg,
 		     struct iwl_nvm_data *data, const __le16 *nvm_ch_flags,
-		     u8 tx_chains, u8 rx_chains, bool lar_supported);
+		     u8 tx_chains, u8 rx_chains, bool lar_supported,
+		     bool no_wide_in_5ghz);
 
 /**
  * iwl_parse_mcc_info - parse MCC (mobile country code) info coming from FW


Patches currently in stable-queue which might be from luciano.coelho@intel.com are

queue-4.13/iwlwifi-add-workaround-to-disable-wide-channels-in-5ghz.patch

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: Patch "iwlwifi: add workaround to disable wide channels in 5GHz" has been added to the 4.13-stable tree
  2017-09-22  9:36 Patch "iwlwifi: add workaround to disable wide channels in 5GHz" has been added to the 4.13-stable tree gregkh
@ 2017-09-22  9:50 ` Greg KH
  2017-09-22 12:17   ` [PATCH] iwlwifi: add workaround to disable wide channels in 5GHz Luca Coelho
  0 siblings, 1 reply; 10+ messages in thread
From: Greg KH @ 2017-09-22  9:50 UTC (permalink / raw)
  To: luciano.coelho; +Cc: stable, stable-commits

On Fri, Sep 22, 2017 at 11:36:59AM +0200, gregkh@linuxfoundation.org wrote:
> 
> This is a note to let you know that I've just added the patch titled
> 
>     iwlwifi: add workaround to disable wide channels in 5GHz
> 
> to the 4.13-stable tree which can be found at:
>     http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary
> 
> The filename of the patch is:
>      iwlwifi-add-workaround-to-disable-wide-channels-in-5ghz.patch
> and it can be found in the queue-4.13 subdirectory.

Oops, no, it didn't apply, if someone wants it applied, please provide a
working backport.

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH] iwlwifi: add workaround to disable wide channels in 5GHz
  2017-09-22  9:50 ` Greg KH
@ 2017-09-22 12:17   ` Luca Coelho
  2017-09-22 16:20     ` Greg KH
  0 siblings, 1 reply; 10+ messages in thread
From: Luca Coelho @ 2017-09-22 12:17 UTC (permalink / raw)
  To: gregkh; +Cc: stable, stable-commits, luciano.coelho

From: Luca Coelho <luciano.coelho@intel.com>

commit 01a9c948a09348950515bf2abb6113ed83e696d8 upstream.

The OTP in some SKUs have erroneously allowed 40MHz and 80MHz channels
in the 5.2GHz band.  The firmware has been modified to not allow this
in those SKUs, so the driver needs to do the same otherwise the
firmware will assert when we try to use it.

Cc: stable@vger.kernel.org
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
---
 drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c | 62 ++++++++++++++++++----
 drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h |  3 +-
 drivers/net/wireless/intel/iwlwifi/mvm/nvm.c       |  3 +-
 3 files changed, 56 insertions(+), 12 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
index 3ee6767392b6..d25bad052d78 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
@@ -79,6 +79,7 @@
 /* NVM offsets (in words) definitions */
 enum wkp_nvm_offsets {
 	/* NVM HW-Section offset (in words) definitions */
+	SUBSYSTEM_ID = 0x0A,
 	HW_ADDR = 0x15,
 
 	/* NVM SW-Section offset (in words) definitions */
@@ -254,13 +255,12 @@ static u32 iwl_get_channel_flags(u8 ch_num, int ch_idx, bool is_5ghz,
 static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
 				struct iwl_nvm_data *data,
 				const __le16 * const nvm_ch_flags,
-				bool lar_supported)
+				bool lar_supported, bool no_wide_in_5ghz)
 {
 	int ch_idx;
 	int n_channels = 0;
 	struct ieee80211_channel *channel;
 	u16 ch_flags;
-	bool is_5ghz;
 	int num_of_ch, num_2ghz_channels;
 	const u8 *nvm_chan;
 
@@ -275,12 +275,20 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
 	}
 
 	for (ch_idx = 0; ch_idx < num_of_ch; ch_idx++) {
+		bool is_5ghz = (ch_idx >= num_2ghz_channels);
+
 		ch_flags = __le16_to_cpup(nvm_ch_flags + ch_idx);
 
-		if (ch_idx >= num_2ghz_channels &&
-		    !data->sku_cap_band_52GHz_enable)
+		if (is_5ghz && !data->sku_cap_band_52GHz_enable)
 			continue;
 
+		/* workaround to disable wide channels in 5GHz */
+		if (no_wide_in_5ghz && is_5ghz) {
+			ch_flags &= ~(NVM_CHANNEL_40MHZ |
+				     NVM_CHANNEL_80MHZ |
+				     NVM_CHANNEL_160MHZ);
+		}
+
 		if (ch_flags & NVM_CHANNEL_160MHZ)
 			data->vht160_supported = true;
 
@@ -303,8 +311,8 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
 		n_channels++;
 
 		channel->hw_value = nvm_chan[ch_idx];
-		channel->band = (ch_idx < num_2ghz_channels) ?
-				NL80211_BAND_2GHZ : NL80211_BAND_5GHZ;
+		channel->band = is_5ghz ?
+				NL80211_BAND_5GHZ : NL80211_BAND_2GHZ;
 		channel->center_freq =
 			ieee80211_channel_to_frequency(
 				channel->hw_value, channel->band);
@@ -316,7 +324,6 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
 		 * is not used in mvm, and is used for backwards compatibility
 		 */
 		channel->max_power = IWL_DEFAULT_MAX_TX_POWER;
-		is_5ghz = channel->band == NL80211_BAND_5GHZ;
 
 		/* don't put limitations in case we're using LAR */
 		if (!lar_supported)
@@ -432,14 +439,15 @@ static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg,
 
 void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg,
 		     struct iwl_nvm_data *data, const __le16 *nvm_ch_flags,
-		     u8 tx_chains, u8 rx_chains, bool lar_supported)
+		     u8 tx_chains, u8 rx_chains, bool lar_supported,
+		     bool no_wide_in_5ghz)
 {
 	int n_channels;
 	int n_used = 0;
 	struct ieee80211_supported_band *sband;
 
 	n_channels = iwl_init_channel_map(dev, cfg, data, nvm_ch_flags,
-					  lar_supported);
+					  lar_supported, no_wide_in_5ghz);
 	sband = &data->bands[NL80211_BAND_2GHZ];
 	sband->band = NL80211_BAND_2GHZ;
 	sband->bitrates = &iwl_cfg80211_rates[RATES_24_OFFS];
@@ -645,6 +653,39 @@ static int iwl_set_hw_address(struct iwl_trans *trans,
 	return 0;
 }
 
+static bool
+iwl_nvm_no_wide_in_5ghz(struct device *dev, const struct iwl_cfg *cfg,
+			const __le16 *nvm_hw)
+{
+	/*
+	 * Workaround a bug in Indonesia SKUs where the regulatory in
+	 * some 7000-family OTPs erroneously allow wide channels in
+	 * 5GHz.  To check for Indonesia, we take the SKU value from
+	 * bits 1-4 in the subsystem ID and check if it is either 5 or
+	 * 9.  In those cases, we need to force-disable wide channels
+	 * in 5GHz otherwise the FW will throw a sysassert when we try
+	 * to use them.
+	 */
+	if (cfg->device_family == IWL_DEVICE_FAMILY_7000) {
+		/*
+		 * Unlike the other sections in the NVM, the hw
+		 * section uses big-endian.
+		 */
+		u16 subsystem_id = be16_to_cpup((const __be16 *)nvm_hw
+						+ SUBSYSTEM_ID);
+		u8 sku = (subsystem_id & 0x1e) >> 1;
+
+		if (sku == 5 || sku == 9) {
+			IWL_DEBUG_EEPROM(dev,
+					 "disabling wide channels in 5GHz (0x%0x %d)\n",
+					 subsystem_id, sku);
+			return true;
+		}
+	}
+
+	return false;
+}
+
 struct iwl_nvm_data *
 iwl_parse_nvm_data(struct iwl_trans *trans, const struct iwl_cfg *cfg,
 		   const __le16 *nvm_hw, const __le16 *nvm_sw,
@@ -655,6 +696,7 @@ iwl_parse_nvm_data(struct iwl_trans *trans, const struct iwl_cfg *cfg,
 	struct device *dev = trans->dev;
 	struct iwl_nvm_data *data;
 	bool lar_enabled;
+	bool no_wide_in_5ghz = iwl_nvm_no_wide_in_5ghz(dev, cfg, nvm_hw);
 	u32 sku, radio_cfg;
 	u16 lar_config;
 	const __le16 *ch_section;
@@ -725,7 +767,7 @@ iwl_parse_nvm_data(struct iwl_trans *trans, const struct iwl_cfg *cfg,
 	}
 
 	iwl_init_sbands(dev, cfg, data, ch_section, tx_chains, rx_chains,
-			lar_fw_supported && lar_enabled);
+			lar_fw_supported && lar_enabled, no_wide_in_5ghz);
 	data->calib_version = 255;
 
 	return data;
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h
index 3fd6506a02ab..50d9b3eaa4f8 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h
@@ -93,7 +93,8 @@ void iwl_set_hw_address_from_csr(struct iwl_trans *trans,
  */
 void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg,
 		     struct iwl_nvm_data *data, const __le16 *nvm_ch_flags,
-		     u8 tx_chains, u8 rx_chains, bool lar_supported);
+		     u8 tx_chains, u8 rx_chains, bool lar_supported,
+		     bool no_wide_in_5ghz);
 
 /**
  * iwl_parse_mcc_info - parse MCC (mobile country code) info coming from FW
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c
index dac7e542a190..4de565cec747 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c
@@ -628,7 +628,8 @@ int iwl_mvm_nvm_get_from_fw(struct iwl_mvm *mvm)
 			rsp->regulatory.channel_profile,
 			mvm->nvm_data->valid_tx_ant & mvm->fw->valid_tx_ant,
 			mvm->nvm_data->valid_rx_ant & mvm->fw->valid_rx_ant,
-			rsp->regulatory.lar_enabled && lar_fw_supported);
+			rsp->regulatory.lar_enabled && lar_fw_supported,
+			false);
 
 	iwl_free_resp(&hcmd);
 	return 0;
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH] iwlwifi: add workaround to disable wide channels in 5GHz
  2017-09-22 12:17   ` [PATCH] iwlwifi: add workaround to disable wide channels in 5GHz Luca Coelho
@ 2017-09-22 16:20     ` Greg KH
  2017-09-22 16:36       ` Coelho, Luciano
                         ` (3 more replies)
  0 siblings, 4 replies; 10+ messages in thread
From: Greg KH @ 2017-09-22 16:20 UTC (permalink / raw)
  To: Luca Coelho; +Cc: stable, stable-commits, luciano.coelho

On Fri, Sep 22, 2017 at 03:17:26PM +0300, Luca Coelho wrote:
> From: Luca Coelho <luciano.coelho@intel.com>
> 
> commit 01a9c948a09348950515bf2abb6113ed83e696d8 upstream.
> 
> The OTP in some SKUs have erroneously allowed 40MHz and 80MHz channels
> in the 5.2GHz band.  The firmware has been modified to not allow this
> in those SKUs, so the driver needs to do the same otherwise the
> firmware will assert when we try to use it.
> 
> Cc: stable@vger.kernel.org
> Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
> ---
>  drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c | 62 ++++++++++++++++++----
>  drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h |  3 +-
>  drivers/net/wireless/intel/iwlwifi/mvm/nvm.c       |  3 +-
>  3 files changed, 56 insertions(+), 12 deletions(-)

Thanks, that worked for 4.13-stable, if you want it in 4.9 or anything
else, I need a backport for that, as this patch didn't apply there.

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] iwlwifi: add workaround to disable wide channels in 5GHz
  2017-09-22 16:20     ` Greg KH
@ 2017-09-22 16:36       ` Coelho, Luciano
  2017-10-10  7:57       ` [PATCH for v4.9] " Luca Coelho
                         ` (2 subsequent siblings)
  3 siblings, 0 replies; 10+ messages in thread
From: Coelho, Luciano @ 2017-09-22 16:36 UTC (permalink / raw)
  To: gregkh; +Cc: stable, stable-commits

Thanks, Greg.

I'll backport to the other kernel versions too and send you the patch.

--
Cheers,
Luca.

On Fri, 2017-09-22 at 18:20 +0200, Greg KH wrote:
> On Fri, Sep 22, 2017 at 03:17:26PM +0300, Luca Coelho wrote:
> > From: Luca Coelho <luciano.coelho@intel.com>
> > 
> > commit 01a9c948a09348950515bf2abb6113ed83e696d8 upstream.
> > 
> > The OTP in some SKUs have erroneously allowed 40MHz and 80MHz channels
> > in the 5.2GHz band.  The firmware has been modified to not allow this
> > in those SKUs, so the driver needs to do the same otherwise the
> > firmware will assert when we try to use it.
> > 
> > Cc: stable@vger.kernel.org
> > Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
> > ---
> >  drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c | 62 ++++++++++++++++++----
> >  drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h |  3 +-
> >  drivers/net/wireless/intel/iwlwifi/mvm/nvm.c       |  3 +-
> >  3 files changed, 56 insertions(+), 12 deletions(-)
> 
> Thanks, that worked for 4.13-stable, if you want it in 4.9 or anything
> else, I need a backport for that, as this patch didn't apply there.
> 
> thanks,
> 
> greg k-h

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH for v4.9] iwlwifi: add workaround to disable wide channels in 5GHz
  2017-09-22 16:20     ` Greg KH
  2017-09-22 16:36       ` Coelho, Luciano
@ 2017-10-10  7:57       ` Luca Coelho
  2017-10-10 15:27         ` Greg KH
  2017-10-10  8:12       ` [PATCH for v4.4] " Luca Coelho
  2017-10-10  8:20       ` [PATCH v2 " Luca Coelho
  3 siblings, 1 reply; 10+ messages in thread
From: Luca Coelho @ 2017-10-10  7:57 UTC (permalink / raw)
  To: gregkh; +Cc: stable, stable-commits, luciano.coelho

From: Luca Coelho <luciano.coelho@intel.com>

commit 01a9c948a09348950515bf2abb6113ed83e696d8 upstream.

The OTP in some SKUs have erroneously allowed 40MHz and 80MHz channels
in the 5.2GHz band.  The firmware has been modified to not allow this
in those SKUs, so the driver needs to do the same otherwise the
firmware will assert when we try to use it.

Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
---
 drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c | 66 ++++++++++++++++++----
 1 file changed, 55 insertions(+), 11 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
index 3bd6fc1b76d4..33f4d7c7b53a 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
@@ -78,6 +78,7 @@
 /* NVM offsets (in words) definitions */
 enum wkp_nvm_offsets {
 	/* NVM HW-Section offset (in words) definitions */
+	SUBSYSTEM_ID = 0x0A,
 	HW_ADDR = 0x15,
 
 	/* NVM SW-Section offset (in words) definitions */
@@ -262,13 +263,12 @@ static u32 iwl_get_channel_flags(u8 ch_num, int ch_idx, bool is_5ghz,
 static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
 				struct iwl_nvm_data *data,
 				const __le16 * const nvm_ch_flags,
-				bool lar_supported)
+				bool lar_supported, bool no_wide_in_5ghz)
 {
 	int ch_idx;
 	int n_channels = 0;
 	struct ieee80211_channel *channel;
 	u16 ch_flags;
-	bool is_5ghz;
 	int num_of_ch, num_2ghz_channels;
 	const u8 *nvm_chan;
 
@@ -283,12 +283,20 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
 	}
 
 	for (ch_idx = 0; ch_idx < num_of_ch; ch_idx++) {
+		bool is_5ghz = (ch_idx >= num_2ghz_channels);
+
 		ch_flags = __le16_to_cpup(nvm_ch_flags + ch_idx);
 
-		if (ch_idx >= num_2ghz_channels &&
-		    !data->sku_cap_band_52GHz_enable)
+		if (is_5ghz && !data->sku_cap_band_52GHz_enable)
 			continue;
 
+		/* workaround to disable wide channels in 5GHz */
+		if (no_wide_in_5ghz && is_5ghz) {
+			ch_flags &= ~(NVM_CHANNEL_40MHZ |
+				     NVM_CHANNEL_80MHZ |
+				     NVM_CHANNEL_160MHZ);
+		}
+
 		if (ch_flags & NVM_CHANNEL_160MHZ)
 			data->vht160_supported = true;
 
@@ -311,8 +319,8 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
 		n_channels++;
 
 		channel->hw_value = nvm_chan[ch_idx];
-		channel->band = (ch_idx < num_2ghz_channels) ?
-				NL80211_BAND_2GHZ : NL80211_BAND_5GHZ;
+		channel->band = is_5ghz ?
+				NL80211_BAND_5GHZ : NL80211_BAND_2GHZ;
 		channel->center_freq =
 			ieee80211_channel_to_frequency(
 				channel->hw_value, channel->band);
@@ -324,7 +332,6 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
 		 * is not used in mvm, and is used for backwards compatibility
 		 */
 		channel->max_power = IWL_DEFAULT_MAX_TX_POWER;
-		is_5ghz = channel->band == NL80211_BAND_5GHZ;
 
 		/* don't put limitations in case we're using LAR */
 		if (!lar_supported)
@@ -441,7 +448,8 @@ static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg,
 static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg,
 			    struct iwl_nvm_data *data,
 			    const __le16 *ch_section,
-			    u8 tx_chains, u8 rx_chains, bool lar_supported)
+			    u8 tx_chains, u8 rx_chains, bool lar_supported,
+			    bool no_wide_in_5ghz)
 {
 	int n_channels;
 	int n_used = 0;
@@ -450,12 +458,14 @@ static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg,
 	if (cfg->device_family != IWL_DEVICE_FAMILY_8000)
 		n_channels = iwl_init_channel_map(
 				dev, cfg, data,
-				&ch_section[NVM_CHANNELS], lar_supported);
+				&ch_section[NVM_CHANNELS], lar_supported,
+				no_wide_in_5ghz);
 	else
 		n_channels = iwl_init_channel_map(
 				dev, cfg, data,
 				&ch_section[NVM_CHANNELS_FAMILY_8000],
-				lar_supported);
+				lar_supported,
+				no_wide_in_5ghz);
 
 	sband = &data->bands[NL80211_BAND_2GHZ];
 	sband->band = NL80211_BAND_2GHZ;
@@ -658,6 +668,39 @@ static int iwl_set_hw_address(struct iwl_trans *trans,
 	return 0;
 }
 
+static bool
+iwl_nvm_no_wide_in_5ghz(struct device *dev, const struct iwl_cfg *cfg,
+			const __le16 *nvm_hw)
+{
+	/*
+	 * Workaround a bug in Indonesia SKUs where the regulatory in
+	 * some 7000-family OTPs erroneously allow wide channels in
+	 * 5GHz.  To check for Indonesia, we take the SKU value from
+	 * bits 1-4 in the subsystem ID and check if it is either 5 or
+	 * 9.  In those cases, we need to force-disable wide channels
+	 * in 5GHz otherwise the FW will throw a sysassert when we try
+	 * to use them.
+	 */
+	if (cfg->device_family == IWL_DEVICE_FAMILY_7000) {
+		/*
+		 * Unlike the other sections in the NVM, the hw
+		 * section uses big-endian.
+		 */
+		u16 subsystem_id = be16_to_cpup((const __be16 *)nvm_hw
+						+ SUBSYSTEM_ID);
+		u8 sku = (subsystem_id & 0x1e) >> 1;
+
+		if (sku == 5 || sku == 9) {
+			IWL_DEBUG_EEPROM(dev,
+					 "disabling wide channels in 5GHz (0x%0x %d)\n",
+					 subsystem_id, sku);
+			return true;
+		}
+	}
+
+	return false;
+}
+
 struct iwl_nvm_data *
 iwl_parse_nvm_data(struct iwl_trans *trans, const struct iwl_cfg *cfg,
 		   const __le16 *nvm_hw, const __le16 *nvm_sw,
@@ -668,6 +711,7 @@ iwl_parse_nvm_data(struct iwl_trans *trans, const struct iwl_cfg *cfg,
 	struct device *dev = trans->dev;
 	struct iwl_nvm_data *data;
 	bool lar_enabled;
+	bool no_wide_in_5ghz = iwl_nvm_no_wide_in_5ghz(dev, cfg, nvm_hw);
 	u32 sku, radio_cfg;
 	u16 lar_config;
 	const __le16 *ch_section;
@@ -738,7 +782,7 @@ iwl_parse_nvm_data(struct iwl_trans *trans, const struct iwl_cfg *cfg,
 	}
 
 	iwl_init_sbands(dev, cfg, data, ch_section, tx_chains, rx_chains,
-			lar_fw_supported && lar_enabled);
+			lar_fw_supported && lar_enabled, no_wide_in_5ghz);
 	data->calib_version = 255;
 
 	return data;
-- 
2.14.2

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH for v4.4] iwlwifi: add workaround to disable wide channels in 5GHz
  2017-09-22 16:20     ` Greg KH
  2017-09-22 16:36       ` Coelho, Luciano
  2017-10-10  7:57       ` [PATCH for v4.9] " Luca Coelho
@ 2017-10-10  8:12       ` Luca Coelho
  2017-10-10  8:16         ` Luciano Coelho
  2017-10-10  8:20       ` [PATCH v2 " Luca Coelho
  3 siblings, 1 reply; 10+ messages in thread
From: Luca Coelho @ 2017-10-10  8:12 UTC (permalink / raw)
  To: gregkh; +Cc: stable, stable-commits, luciano.coelho

From: Luca Coelho <luciano.coelho@intel.com>

commit 01a9c948a09348950515bf2abb6113ed83e696d8 upstream.

The OTP in some SKUs have erroneously allowed 40MHz and 80MHz channels
in the 5.2GHz band.  The firmware has been modified to not allow this
in those SKUs, so the driver needs to do the same otherwise the
firmware will assert when we try to use it.

Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
---
 drivers/net/wireless/iwlwifi/iwl-nvm-parse.c | 65 +++++++++++++++++++++++-----
 1 file changed, 55 insertions(+), 10 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c
index d82984912e04..e7f58e00b5fb 100644
--- a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c
+++ b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c
@@ -73,6 +73,7 @@
 /* NVM offsets (in words) definitions */
 enum wkp_nvm_offsets {
 	/* NVM HW-Section offset (in words) definitions */
+	SUBSYSTEM_ID = 0x0A,
 	HW_ADDR = 0x15,
 
 	/* NVM SW-Section offset (in words) definitions */
@@ -257,13 +258,12 @@ static u32 iwl_get_channel_flags(u8 ch_num, int ch_idx, bool is_5ghz,
 static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
 				struct iwl_nvm_data *data,
 				const __le16 * const nvm_ch_flags,
-				bool lar_supported)
+				bool lar_supported, bool no_wide_in_5ghz)
 {
 	int ch_idx;
 	int n_channels = 0;
 	struct ieee80211_channel *channel;
 	u16 ch_flags;
-	bool is_5ghz;
 	int num_of_ch, num_2ghz_channels;
 	const u8 *nvm_chan;
 
@@ -278,12 +278,20 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
 	}
 
 	for (ch_idx = 0; ch_idx < num_of_ch; ch_idx++) {
+		bool is_5ghz = (ch_idx >= num_2ghz_channels);
+
 		ch_flags = __le16_to_cpup(nvm_ch_flags + ch_idx);
 
-		if (ch_idx >= num_2ghz_channels &&
-		    !data->sku_cap_band_52GHz_enable)
+		if (is_5ghz && !data->sku_cap_band_52GHz_enable)
 			continue;
 
+		/* workaround to disable wide channels in 5GHz */
+		if (no_wide_in_5ghz && is_5ghz) {
+			ch_flags &= ~(NVM_CHANNEL_40MHZ |
+				     NVM_CHANNEL_80MHZ |
+				     NVM_CHANNEL_160MHZ);
+		}
+
 		if (!lar_supported && !(ch_flags & NVM_CHANNEL_VALID)) {
 			/*
 			 * Channels might become valid later if lar is
@@ -303,7 +311,7 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
 		n_channels++;
 
 		channel->hw_value = nvm_chan[ch_idx];
-		channel->band = (ch_idx < num_2ghz_channels) ?
+		channel->band = is_5ghz ?
 				IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
 		channel->center_freq =
 			ieee80211_channel_to_frequency(
@@ -316,7 +324,6 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
 		 * is not used in mvm, and is used for backwards compatibility
 		 */
 		channel->max_power = IWL_DEFAULT_MAX_TX_POWER;
-		is_5ghz = channel->band == IEEE80211_BAND_5GHZ;
 
 		/* don't put limitations in case we're using LAR */
 		if (!lar_supported)
@@ -405,7 +412,8 @@ static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg,
 static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg,
 			    struct iwl_nvm_data *data,
 			    const __le16 *ch_section,
-			    u8 tx_chains, u8 rx_chains, bool lar_supported)
+			    u8 tx_chains, u8 rx_chains, bool lar_supported,
+			    bool no_wide_in_5ghz)
 {
 	int n_channels;
 	int n_used = 0;
@@ -414,12 +422,14 @@ static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg,
 	if (cfg->device_family != IWL_DEVICE_FAMILY_8000)
 		n_channels = iwl_init_channel_map(
 				dev, cfg, data,
-				&ch_section[NVM_CHANNELS], lar_supported);
+				&ch_section[NVM_CHANNELS], lar_supported,
+				no_wide_in_5ghz);
 	else
 		n_channels = iwl_init_channel_map(
 				dev, cfg, data,
 				&ch_section[NVM_CHANNELS_FAMILY_8000],
-				lar_supported);
+				lar_supported,
+				no_wide_in_5ghz);
 
 	sband = &data->bands[IEEE80211_BAND_2GHZ];
 	sband->band = IEEE80211_BAND_2GHZ;
@@ -582,6 +592,39 @@ static void iwl_set_hw_address_family_8000(struct device *dev,
 
 #define IWL_4165_DEVICE_ID 0x5501
 
+static bool
+iwl_nvm_no_wide_in_5ghz(struct device *dev, const struct iwl_cfg *cfg,
+			const __le16 *nvm_hw)
+{
+	/*
+	 * Workaround a bug in Indonesia SKUs where the regulatory in
+	 * some 7000-family OTPs erroneously allow wide channels in
+	 * 5GHz.  To check for Indonesia, we take the SKU value from
+	 * bits 1-4 in the subsystem ID and check if it is either 5 or
+	 * 9.  In those cases, we need to force-disable wide channels
+	 * in 5GHz otherwise the FW will throw a sysassert when we try
+	 * to use them.
+	 */
+	if (cfg->device_family == IWL_DEVICE_FAMILY_7000) {
+		/*
+		 * Unlike the other sections in the NVM, the hw
+		 * section uses big-endian.
+		 */
+		u16 subsystem_id = be16_to_cpup((const __be16 *)nvm_hw
+						+ SUBSYSTEM_ID);
+		u8 sku = (subsystem_id & 0x1e) >> 1;
+
+		if (sku == 5 || sku == 9) {
+			IWL_DEBUG_EEPROM(dev,
+					 "disabling wide channels in 5GHz (0x%0x %d)\n",
+					 subsystem_id, sku);
+			return true;
+		}
+	}
+
+	return false;
+}
+
 struct iwl_nvm_data *
 iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg,
 		   const __le16 *nvm_hw, const __le16 *nvm_sw,
@@ -591,6 +634,7 @@ iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg,
 		   u32 mac_addr0, u32 mac_addr1, u32 hw_id)
 {
 	struct iwl_nvm_data *data;
+	bool no_wide_in_5ghz = iwl_nvm_no_wide_in_5ghz(dev, cfg, nvm_hw);
 	u32 sku;
 	u32 radio_cfg;
 	u16 lar_config;
@@ -673,7 +717,8 @@ iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg,
 
 		iwl_init_sbands(dev, cfg, data, regulatory,
 				tx_chains, rx_chains,
-				lar_fw_supported && data->lar_enabled);
+				lar_fw_supported && data->lar_enabled,
+				no_wide_in_5ghz);
 	}
 
 	data->calib_version = 255;
-- 
2.14.2

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH for v4.4] iwlwifi: add workaround to disable wide channels in 5GHz
  2017-10-10  8:12       ` [PATCH for v4.4] " Luca Coelho
@ 2017-10-10  8:16         ` Luciano Coelho
  0 siblings, 0 replies; 10+ messages in thread
From: Luciano Coelho @ 2017-10-10  8:16 UTC (permalink / raw)
  To: gregkh; +Cc: stable, stable-commits

On Tue, 2017-10-10 at 11:12 +0300, Luca Coelho wrote:
> From: Luca Coelho <luciano.coelho@intel.com>
> 
> commit 01a9c948a09348950515bf2abb6113ed83e696d8 upstream.
> 
> The OTP in some SKUs have erroneously allowed 40MHz and 80MHz channels
> in the 5.2GHz band.  The firmware has been modified to not allow this
> in those SKUs, so the driver needs to do the same otherwise the
> firmware will assert when we try to use it.
> 
> Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
> ---
>  drivers/net/wireless/iwlwifi/iwl-nvm-parse.c | 65 +++++++++++++++++++++++-----
>  1 file changed, 55 insertions(+), 10 deletions(-)
> 
> diff --git a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c
> index d82984912e04..e7f58e00b5fb 100644
> --- a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c
> +++ b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c
> @@ -73,6 +73,7 @@
>  /* NVM offsets (in words) definitions */
>  enum wkp_nvm_offsets {
>  	/* NVM HW-Section offset (in words) definitions */
> +	SUBSYSTEM_ID = 0x0A,
>  	HW_ADDR = 0x15,
>  
>  	/* NVM SW-Section offset (in words) definitions */
> @@ -257,13 +258,12 @@ static u32 iwl_get_channel_flags(u8 ch_num, int ch_idx, bool is_5ghz,
>  static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
>  				struct iwl_nvm_data *data,
>  				const __le16 * const nvm_ch_flags,
> -				bool lar_supported)
> +				bool lar_supported, bool no_wide_in_5ghz)
>  {
>  	int ch_idx;
>  	int n_channels = 0;
>  	struct ieee80211_channel *channel;
>  	u16 ch_flags;
> -	bool is_5ghz;
>  	int num_of_ch, num_2ghz_channels;
>  	const u8 *nvm_chan;
>  
> @@ -278,12 +278,20 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
>  	}
>  
>  	for (ch_idx = 0; ch_idx < num_of_ch; ch_idx++) {
> +		bool is_5ghz = (ch_idx >= num_2ghz_channels);
> +
>  		ch_flags = __le16_to_cpup(nvm_ch_flags + ch_idx);
>  
> -		if (ch_idx >= num_2ghz_channels &&
> -		    !data->sku_cap_band_52GHz_enable)
> +		if (is_5ghz && !data->sku_cap_band_52GHz_enable)
>  			continue;
>  
> +		/* workaround to disable wide channels in 5GHz */
> +		if (no_wide_in_5ghz && is_5ghz) {
> +			ch_flags &= ~(NVM_CHANNEL_40MHZ |
> +				     NVM_CHANNEL_80MHZ |
> +				     NVM_CHANNEL_160MHZ);
> +		}
> +
>  		if (!lar_supported && !(ch_flags & NVM_CHANNEL_VALID)) {
>  			/*
>  			 * Channels might become valid later if lar is
> @@ -303,7 +311,7 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
>  		n_channels++;
>  
>  		channel->hw_value = nvm_chan[ch_idx];
> -		channel->band = (ch_idx < num_2ghz_channels) ?
> +		channel->band = is_5ghz ?
>  				IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;

Ooops, sorry, I made a mistake here.  I'll send v2.

--
Luca.

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH v2 for v4.4] iwlwifi: add workaround to disable wide channels in 5GHz
  2017-09-22 16:20     ` Greg KH
                         ` (2 preceding siblings ...)
  2017-10-10  8:12       ` [PATCH for v4.4] " Luca Coelho
@ 2017-10-10  8:20       ` Luca Coelho
  3 siblings, 0 replies; 10+ messages in thread
From: Luca Coelho @ 2017-10-10  8:20 UTC (permalink / raw)
  To: gregkh; +Cc: stable, stable-commits, luciano.coelho

From: Luca Coelho <luciano.coelho@intel.com>

commit 01a9c948a09348950515bf2abb6113ed83e696d8 upstream.

The OTP in some SKUs have erroneously allowed 40MHz and 80MHz channels
in the 5.2GHz band.  The firmware has been modified to not allow this
in those SKUs, so the driver needs to do the same otherwise the
firmware will assert when we try to use it.

Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
---
 drivers/net/wireless/iwlwifi/iwl-nvm-parse.c | 70 +++++++++++++++++++++++-----
 1 file changed, 58 insertions(+), 12 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c
index d82984912e04..95b82cc132e6 100644
--- a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c
+++ b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c
@@ -73,6 +73,7 @@
 /* NVM offsets (in words) definitions */
 enum wkp_nvm_offsets {
 	/* NVM HW-Section offset (in words) definitions */
+	SUBSYSTEM_ID = 0x0A,
 	HW_ADDR = 0x15,
 
 	/* NVM SW-Section offset (in words) definitions */
@@ -257,13 +258,12 @@ static u32 iwl_get_channel_flags(u8 ch_num, int ch_idx, bool is_5ghz,
 static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
 				struct iwl_nvm_data *data,
 				const __le16 * const nvm_ch_flags,
-				bool lar_supported)
+				bool lar_supported, bool no_wide_in_5ghz)
 {
 	int ch_idx;
 	int n_channels = 0;
 	struct ieee80211_channel *channel;
 	u16 ch_flags;
-	bool is_5ghz;
 	int num_of_ch, num_2ghz_channels;
 	const u8 *nvm_chan;
 
@@ -278,12 +278,20 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
 	}
 
 	for (ch_idx = 0; ch_idx < num_of_ch; ch_idx++) {
+		bool is_5ghz = (ch_idx >= num_2ghz_channels);
+
 		ch_flags = __le16_to_cpup(nvm_ch_flags + ch_idx);
 
-		if (ch_idx >= num_2ghz_channels &&
-		    !data->sku_cap_band_52GHz_enable)
+		if (is_5ghz && !data->sku_cap_band_52GHz_enable)
 			continue;
 
+		/* workaround to disable wide channels in 5GHz */
+		if (no_wide_in_5ghz && is_5ghz) {
+			ch_flags &= ~(NVM_CHANNEL_40MHZ |
+				     NVM_CHANNEL_80MHZ |
+				     NVM_CHANNEL_160MHZ);
+		}
+
 		if (!lar_supported && !(ch_flags & NVM_CHANNEL_VALID)) {
 			/*
 			 * Channels might become valid later if lar is
@@ -303,8 +311,8 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
 		n_channels++;
 
 		channel->hw_value = nvm_chan[ch_idx];
-		channel->band = (ch_idx < num_2ghz_channels) ?
-				IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
+		channel->band = is_5ghz ?
+				IEEE80211_BAND_5GHZ : IEEE80211_BAND_2GHZ;
 		channel->center_freq =
 			ieee80211_channel_to_frequency(
 				channel->hw_value, channel->band);
@@ -316,7 +324,6 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
 		 * is not used in mvm, and is used for backwards compatibility
 		 */
 		channel->max_power = IWL_DEFAULT_MAX_TX_POWER;
-		is_5ghz = channel->band == IEEE80211_BAND_5GHZ;
 
 		/* don't put limitations in case we're using LAR */
 		if (!lar_supported)
@@ -405,7 +412,8 @@ static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg,
 static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg,
 			    struct iwl_nvm_data *data,
 			    const __le16 *ch_section,
-			    u8 tx_chains, u8 rx_chains, bool lar_supported)
+			    u8 tx_chains, u8 rx_chains, bool lar_supported,
+			    bool no_wide_in_5ghz)
 {
 	int n_channels;
 	int n_used = 0;
@@ -414,12 +422,14 @@ static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg,
 	if (cfg->device_family != IWL_DEVICE_FAMILY_8000)
 		n_channels = iwl_init_channel_map(
 				dev, cfg, data,
-				&ch_section[NVM_CHANNELS], lar_supported);
+				&ch_section[NVM_CHANNELS], lar_supported,
+				no_wide_in_5ghz);
 	else
 		n_channels = iwl_init_channel_map(
 				dev, cfg, data,
 				&ch_section[NVM_CHANNELS_FAMILY_8000],
-				lar_supported);
+				lar_supported,
+				no_wide_in_5ghz);
 
 	sband = &data->bands[IEEE80211_BAND_2GHZ];
 	sband->band = IEEE80211_BAND_2GHZ;
@@ -582,6 +592,39 @@ static void iwl_set_hw_address_family_8000(struct device *dev,
 
 #define IWL_4165_DEVICE_ID 0x5501
 
+static bool
+iwl_nvm_no_wide_in_5ghz(struct device *dev, const struct iwl_cfg *cfg,
+			const __le16 *nvm_hw)
+{
+	/*
+	 * Workaround a bug in Indonesia SKUs where the regulatory in
+	 * some 7000-family OTPs erroneously allow wide channels in
+	 * 5GHz.  To check for Indonesia, we take the SKU value from
+	 * bits 1-4 in the subsystem ID and check if it is either 5 or
+	 * 9.  In those cases, we need to force-disable wide channels
+	 * in 5GHz otherwise the FW will throw a sysassert when we try
+	 * to use them.
+	 */
+	if (cfg->device_family == IWL_DEVICE_FAMILY_7000) {
+		/*
+		 * Unlike the other sections in the NVM, the hw
+		 * section uses big-endian.
+		 */
+		u16 subsystem_id = be16_to_cpup((const __be16 *)nvm_hw
+						+ SUBSYSTEM_ID);
+		u8 sku = (subsystem_id & 0x1e) >> 1;
+
+		if (sku == 5 || sku == 9) {
+			IWL_DEBUG_EEPROM(dev,
+					 "disabling wide channels in 5GHz (0x%0x %d)\n",
+					 subsystem_id, sku);
+			return true;
+		}
+	}
+
+	return false;
+}
+
 struct iwl_nvm_data *
 iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg,
 		   const __le16 *nvm_hw, const __le16 *nvm_sw,
@@ -591,6 +634,7 @@ iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg,
 		   u32 mac_addr0, u32 mac_addr1, u32 hw_id)
 {
 	struct iwl_nvm_data *data;
+	bool no_wide_in_5ghz = iwl_nvm_no_wide_in_5ghz(dev, cfg, nvm_hw);
 	u32 sku;
 	u32 radio_cfg;
 	u16 lar_config;
@@ -657,7 +701,8 @@ iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg,
 		iwl_set_hw_address(cfg, data, nvm_hw);
 
 		iwl_init_sbands(dev, cfg, data, nvm_sw,
-				tx_chains, rx_chains, lar_fw_supported);
+				tx_chains, rx_chains, lar_fw_supported,
+				no_wide_in_5ghz);
 	} else {
 		u16 lar_offset = data->nvm_version < 0xE39 ?
 				 NVM_LAR_OFFSET_FAMILY_8000_OLD :
@@ -673,7 +718,8 @@ iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg,
 
 		iwl_init_sbands(dev, cfg, data, regulatory,
 				tx_chains, rx_chains,
-				lar_fw_supported && data->lar_enabled);
+				lar_fw_supported && data->lar_enabled,
+				no_wide_in_5ghz);
 	}
 
 	data->calib_version = 255;
-- 
2.14.2

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH for v4.9] iwlwifi: add workaround to disable wide channels in 5GHz
  2017-10-10  7:57       ` [PATCH for v4.9] " Luca Coelho
@ 2017-10-10 15:27         ` Greg KH
  0 siblings, 0 replies; 10+ messages in thread
From: Greg KH @ 2017-10-10 15:27 UTC (permalink / raw)
  To: Luca Coelho; +Cc: stable, stable-commits, luciano.coelho

On Tue, Oct 10, 2017 at 10:57:41AM +0300, Luca Coelho wrote:
> From: Luca Coelho <luciano.coelho@intel.com>
> 
> commit 01a9c948a09348950515bf2abb6113ed83e696d8 upstream.
> 
> The OTP in some SKUs have erroneously allowed 40MHz and 80MHz channels
> in the 5.2GHz band.  The firmware has been modified to not allow this
> in those SKUs, so the driver needs to do the same otherwise the
> firmware will assert when we try to use it.
> 
> Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
> ---
>  drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c | 66 ++++++++++++++++++----
>  1 file changed, 55 insertions(+), 11 deletions(-)

Thanks for this, and the 4.4 patch, now queued up.

greg k-h

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2017-10-10 15:27 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-09-22  9:36 Patch "iwlwifi: add workaround to disable wide channels in 5GHz" has been added to the 4.13-stable tree gregkh
2017-09-22  9:50 ` Greg KH
2017-09-22 12:17   ` [PATCH] iwlwifi: add workaround to disable wide channels in 5GHz Luca Coelho
2017-09-22 16:20     ` Greg KH
2017-09-22 16:36       ` Coelho, Luciano
2017-10-10  7:57       ` [PATCH for v4.9] " Luca Coelho
2017-10-10 15:27         ` Greg KH
2017-10-10  8:12       ` [PATCH for v4.4] " Luca Coelho
2017-10-10  8:16         ` Luciano Coelho
2017-10-10  8:20       ` [PATCH v2 " Luca Coelho

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.