Skip to content

Commit fc29713

Browse files
lucacoelhogregkh
authored andcommitted
iwlwifi: add workaround to disable wide channels in 5GHz
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>
1 parent 146a9dc commit fc29713

1 file changed

Lines changed: 58 additions & 12 deletions

File tree

drivers/net/wireless/iwlwifi/iwl-nvm-parse.c

Lines changed: 58 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@
7373
/* NVM offsets (in words) definitions */
7474
enum wkp_nvm_offsets {
7575
/* NVM HW-Section offset (in words) definitions */
76+
SUBSYSTEM_ID = 0x0A,
7677
HW_ADDR = 0x15,
7778

7879
/* 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,
257258
static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
258259
struct iwl_nvm_data *data,
259260
const __le16 * const nvm_ch_flags,
260-
bool lar_supported)
261+
bool lar_supported, bool no_wide_in_5ghz)
261262
{
262263
int ch_idx;
263264
int n_channels = 0;
264265
struct ieee80211_channel *channel;
265266
u16 ch_flags;
266-
bool is_5ghz;
267267
int num_of_ch, num_2ghz_channels;
268268
const u8 *nvm_chan;
269269

@@ -278,12 +278,20 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
278278
}
279279

280280
for (ch_idx = 0; ch_idx < num_of_ch; ch_idx++) {
281+
bool is_5ghz = (ch_idx >= num_2ghz_channels);
282+
281283
ch_flags = __le16_to_cpup(nvm_ch_flags + ch_idx);
282284

283-
if (ch_idx >= num_2ghz_channels &&
284-
!data->sku_cap_band_52GHz_enable)
285+
if (is_5ghz && !data->sku_cap_band_52GHz_enable)
285286
continue;
286287

288+
/* workaround to disable wide channels in 5GHz */
289+
if (no_wide_in_5ghz && is_5ghz) {
290+
ch_flags &= ~(NVM_CHANNEL_40MHZ |
291+
NVM_CHANNEL_80MHZ |
292+
NVM_CHANNEL_160MHZ);
293+
}
294+
287295
if (!lar_supported && !(ch_flags & NVM_CHANNEL_VALID)) {
288296
/*
289297
* 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,
303311
n_channels++;
304312

305313
channel->hw_value = nvm_chan[ch_idx];
306-
channel->band = (ch_idx < num_2ghz_channels) ?
307-
IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
314+
channel->band = is_5ghz ?
315+
IEEE80211_BAND_5GHZ : IEEE80211_BAND_2GHZ;
308316
channel->center_freq =
309317
ieee80211_channel_to_frequency(
310318
channel->hw_value, channel->band);
@@ -316,7 +324,6 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
316324
* is not used in mvm, and is used for backwards compatibility
317325
*/
318326
channel->max_power = IWL_DEFAULT_MAX_TX_POWER;
319-
is_5ghz = channel->band == IEEE80211_BAND_5GHZ;
320327

321328
/* don't put limitations in case we're using LAR */
322329
if (!lar_supported)
@@ -405,7 +412,8 @@ static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg,
405412
static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg,
406413
struct iwl_nvm_data *data,
407414
const __le16 *ch_section,
408-
u8 tx_chains, u8 rx_chains, bool lar_supported)
415+
u8 tx_chains, u8 rx_chains, bool lar_supported,
416+
bool no_wide_in_5ghz)
409417
{
410418
int n_channels;
411419
int n_used = 0;
@@ -414,12 +422,14 @@ static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg,
414422
if (cfg->device_family != IWL_DEVICE_FAMILY_8000)
415423
n_channels = iwl_init_channel_map(
416424
dev, cfg, data,
417-
&ch_section[NVM_CHANNELS], lar_supported);
425+
&ch_section[NVM_CHANNELS], lar_supported,
426+
no_wide_in_5ghz);
418427
else
419428
n_channels = iwl_init_channel_map(
420429
dev, cfg, data,
421430
&ch_section[NVM_CHANNELS_FAMILY_8000],
422-
lar_supported);
431+
lar_supported,
432+
no_wide_in_5ghz);
423433

424434
sband = &data->bands[IEEE80211_BAND_2GHZ];
425435
sband->band = IEEE80211_BAND_2GHZ;
@@ -582,6 +592,39 @@ static void iwl_set_hw_address_family_8000(struct device *dev,
582592

583593
#define IWL_4165_DEVICE_ID 0x5501
584594

595+
static bool
596+
iwl_nvm_no_wide_in_5ghz(struct device *dev, const struct iwl_cfg *cfg,
597+
const __le16 *nvm_hw)
598+
{
599+
/*
600+
* Workaround a bug in Indonesia SKUs where the regulatory in
601+
* some 7000-family OTPs erroneously allow wide channels in
602+
* 5GHz. To check for Indonesia, we take the SKU value from
603+
* bits 1-4 in the subsystem ID and check if it is either 5 or
604+
* 9. In those cases, we need to force-disable wide channels
605+
* in 5GHz otherwise the FW will throw a sysassert when we try
606+
* to use them.
607+
*/
608+
if (cfg->device_family == IWL_DEVICE_FAMILY_7000) {
609+
/*
610+
* Unlike the other sections in the NVM, the hw
611+
* section uses big-endian.
612+
*/
613+
u16 subsystem_id = be16_to_cpup((const __be16 *)nvm_hw
614+
+ SUBSYSTEM_ID);
615+
u8 sku = (subsystem_id & 0x1e) >> 1;
616+
617+
if (sku == 5 || sku == 9) {
618+
IWL_DEBUG_EEPROM(dev,
619+
"disabling wide channels in 5GHz (0x%0x %d)\n",
620+
subsystem_id, sku);
621+
return true;
622+
}
623+
}
624+
625+
return false;
626+
}
627+
585628
struct iwl_nvm_data *
586629
iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg,
587630
const __le16 *nvm_hw, const __le16 *nvm_sw,
@@ -591,6 +634,7 @@ iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg,
591634
u32 mac_addr0, u32 mac_addr1, u32 hw_id)
592635
{
593636
struct iwl_nvm_data *data;
637+
bool no_wide_in_5ghz = iwl_nvm_no_wide_in_5ghz(dev, cfg, nvm_hw);
594638
u32 sku;
595639
u32 radio_cfg;
596640
u16 lar_config;
@@ -657,7 +701,8 @@ iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg,
657701
iwl_set_hw_address(cfg, data, nvm_hw);
658702

659703
iwl_init_sbands(dev, cfg, data, nvm_sw,
660-
tx_chains, rx_chains, lar_fw_supported);
704+
tx_chains, rx_chains, lar_fw_supported,
705+
no_wide_in_5ghz);
661706
} else {
662707
u16 lar_offset = data->nvm_version < 0xE39 ?
663708
NVM_LAR_OFFSET_FAMILY_8000_OLD :
@@ -673,7 +718,8 @@ iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg,
673718

674719
iwl_init_sbands(dev, cfg, data, regulatory,
675720
tx_chains, rx_chains,
676-
lar_fw_supported && data->lar_enabled);
721+
lar_fw_supported && data->lar_enabled,
722+
no_wide_in_5ghz);
677723
}
678724

679725
data->calib_version = 255;

0 commit comments

Comments
 (0)