--- /dev/null
+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>
+
+---
+ 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(-)
+
+--- 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_n
+ 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 d
+ }
+
+ 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 d
+ 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 d
+ * 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
+
+ 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
+ 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 *tra
+ 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 *tra
+ }
+
+ 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;
+--- 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
+ */
+ 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
+--- 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_m
+ 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;