struct ieee80211_regdomain * iwl_parse_nvm_mcc_info(struct device *dev, const struct iwl_cfg *cfg, int num_of_ch, __le32 *channels, u16 fw_mcc) { int ch_idx; u16 ch_flags, prev_ch_flags = 0; const u8 *nvm_chan = cfg->device_family == IWL_DEVICE_FAMILY_8000 ? iwl_nvm_channels_family_8000 : iwl_nvm_channels; struct ieee80211_regdomain *regd; int size_of_regd; struct ieee80211_reg_rule *rule; enum nl80211_band band; int center_freq, prev_center_freq = 0; int valid_rules = 0; bool new_rule; int max_num_ch = cfg->device_family == IWL_DEVICE_FAMILY_8000 ? IWL_NUM_CHANNELS_FAMILY_8000 : IWL_NUM_CHANNELS; if (WARN_ON_ONCE(num_of_ch > NL80211_MAX_SUPP_REG_RULES)) return ERR_PTR(-EINVAL); if (WARN_ON(num_of_ch > max_num_ch)) num_of_ch = max_num_ch; IWL_DEBUG_DEV(dev, IWL_DL_LAR, "building regdom for %d channels\n", num_of_ch); /* build a regdomain rule for every valid channel */ size_of_regd = sizeof(struct ieee80211_regdomain) + num_of_ch * sizeof(struct ieee80211_reg_rule); regd = kzalloc(size_of_regd, GFP_KERNEL); if (!regd) return ERR_PTR(-ENOMEM); for (ch_idx = 0; ch_idx < num_of_ch; ch_idx++) { ch_flags = (u16)__le32_to_cpup(channels + ch_idx); band = (ch_idx < NUM_2GHZ_CHANNELS) ? NL80211_BAND_2GHZ : NL80211_BAND_5GHZ; center_freq = ieee80211_channel_to_frequency(nvm_chan[ch_idx], band); 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"); continue; } /* we can't continue the same rule */ if (ch_idx == 0 || prev_ch_flags != ch_flags || center_freq - prev_center_freq > 20) { valid_rules++; new_rule = true; } rule = ®d->reg_rules[valid_rules - 1]; if (new_rule) rule->freq_range.start_freq_khz = MHZ_TO_KHZ(center_freq - 10); rule->freq_range.end_freq_khz = MHZ_TO_KHZ(center_freq + 10); /* this doesn't matter - not used by FW */ rule->power_rule.max_antenna_gain = DBI_TO_MBI(6); rule->power_rule.max_eirp = DBM_TO_MBM(IWL_DEFAULT_MAX_TX_POWER); rule->flags = iwl_nvm_get_regdom_bw_flags(nvm_chan, ch_idx, ch_flags, cfg); /* rely on auto-calculation to merge BW of contiguous chans */ rule->flags |= NL80211_RRF_AUTO_BW; rule->freq_range.max_bandwidth_khz = 0; prev_ch_flags = ch_flags; prev_center_freq = center_freq; IWL_DEBUG_DEV(dev, IWL_DL_LAR, "Ch. %d [%sGHz] %s%s%s%s%s%s%s%s%s(0x%02x): Ad-Hoc %ssupported\n", center_freq, band == NL80211_BAND_5GHZ ? "5.2" : "2.4", CHECK_AND_PRINT_I(VALID), CHECK_AND_PRINT_I(ACTIVE), CHECK_AND_PRINT_I(RADAR), CHECK_AND_PRINT_I(WIDE), CHECK_AND_PRINT_I(40MHZ), CHECK_AND_PRINT_I(80MHZ), CHECK_AND_PRINT_I(160MHZ), CHECK_AND_PRINT_I(INDOOR_ONLY), CHECK_AND_PRINT_I(GO_CONCURRENT), ch_flags, ((ch_flags & NVM_CHANNEL_ACTIVE) && !(ch_flags & NVM_CHANNEL_RADAR)) ? "" : "not "); } regd->n_reg_rules = valid_rules; /* set alpha2 from FW. */ regd->alpha2[0] = fw_mcc >> 8; regd->alpha2[1] = fw_mcc & 0xff; return regd; }
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) { 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; if (cfg->device_family != IWL_DEVICE_FAMILY_8000) { num_of_ch = IWL_NUM_CHANNELS; nvm_chan = &iwl_nvm_channels[0]; num_2ghz_channels = NUM_2GHZ_CHANNELS; } else { num_of_ch = IWL_NUM_CHANNELS_FAMILY_8000; nvm_chan = &iwl_nvm_channels_family_8000[0]; num_2ghz_channels = NUM_2GHZ_CHANNELS_FAMILY_8000; } for (ch_idx = 0; ch_idx < num_of_ch; ch_idx++) { ch_flags = __le16_to_cpup(nvm_ch_flags + ch_idx); if (ch_idx >= num_2ghz_channels && !data->sku_cap_band_52GHz_enable) continue; if (ch_flags & NVM_CHANNEL_160MHZ) data->vht160_supported = true; if (!lar_supported && !(ch_flags & NVM_CHANNEL_VALID)) { /* * Channels might become valid later if lar is * 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"); continue; } channel = &data->channels[n_channels]; n_channels++; channel->hw_value = nvm_chan[ch_idx]; channel->band = (ch_idx < num_2ghz_channels) ? NL80211_BAND_2GHZ : NL80211_BAND_5GHZ; channel->center_freq = ieee80211_channel_to_frequency( channel->hw_value, channel->band); /* Initialize regulatory-based run-time data */ /* * Default value - highest tx power value. max_power * 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) channel->flags = iwl_get_channel_flags(nvm_chan[ch_idx], ch_idx, is_5ghz, ch_flags, 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(%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(WIDE), CHECK_AND_PRINT_I(40MHZ), CHECK_AND_PRINT_I(80MHZ), CHECK_AND_PRINT_I(160MHZ), channel->max_power, ((ch_flags & NVM_CHANNEL_IBSS) && !(ch_flags & NVM_CHANNEL_RADAR)) ? "" : "not "); } return n_channels; }
/** * iwl_init_channel_map - Set up driver's info for all possible channels */ int iwl_init_channel_map(struct iwl_priv *priv) { int eeprom_ch_count = 0; const u8 *eeprom_ch_index = NULL; const struct iwl_eeprom_channel *eeprom_ch_info = NULL; int band, ch; struct iwl_channel_info *ch_info; if (priv->channel_count) { IWL_DEBUG_INFO(priv, "Channel map already initialized.\n"); return 0; } IWL_DEBUG_INFO(priv, "Initializing regulatory info from EEPROM\n"); priv->channel_count = ARRAY_SIZE(iwl_eeprom_band_1) + ARRAY_SIZE(iwl_eeprom_band_2) + ARRAY_SIZE(iwl_eeprom_band_3) + ARRAY_SIZE(iwl_eeprom_band_4) + ARRAY_SIZE(iwl_eeprom_band_5); IWL_DEBUG_INFO(priv, "Parsing data for %d channels.\n", priv->channel_count); priv->channel_info = kzalloc(sizeof(struct iwl_channel_info) * priv->channel_count, GFP_KERNEL); if (!priv->channel_info) { IWL_ERR(priv, "Could not allocate channel_info\n"); priv->channel_count = 0; return -ENOMEM; } ch_info = priv->channel_info; /* Loop through the 5 EEPROM bands adding them in order to the * channel map we maintain (that contains additional information than * what just in the EEPROM) */ for (band = 1; band <= 5; band++) { iwl_init_band_reference(priv, band, &eeprom_ch_count, &eeprom_ch_info, &eeprom_ch_index); /* Loop through each band adding each of the channels */ for (ch = 0; ch < eeprom_ch_count; ch++) { ch_info->channel = eeprom_ch_index[ch]; ch_info->band = (band == 1) ? IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ; /* permanently store EEPROM's channel regulatory flags * and max power in channel info database. */ ch_info->eeprom = eeprom_ch_info[ch]; /* Copy the run-time flags so they are there even on * invalid channels */ ch_info->flags = eeprom_ch_info[ch].flags; /* First write that fat is not enabled, and then enable * one by one */ ch_info->fat_extension_channel = (IEEE80211_CHAN_NO_HT40PLUS | IEEE80211_CHAN_NO_HT40MINUS); if (!(is_channel_valid(ch_info))) { IWL_DEBUG_INFO(priv, "Ch. %d Flags %x [%sGHz] - " "No traffic\n", ch_info->channel, ch_info->flags, is_channel_a_band(ch_info) ? "5.2" : "2.4"); ch_info++; continue; } /* Initialize regulatory-based run-time data */ ch_info->max_power_avg = ch_info->curr_txpow = eeprom_ch_info[ch].max_power_avg; ch_info->scan_power = eeprom_ch_info[ch].max_power_avg; ch_info->min_power = 0; IWL_DEBUG_INFO(priv, "Ch. %d [%sGHz] %s%s%s%s%s%s(0x%02x %ddBm):" " Ad-Hoc %ssupported\n", ch_info->channel, is_channel_a_band(ch_info) ? "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(WIDE), CHECK_AND_PRINT_I(DFS), eeprom_ch_info[ch].flags, eeprom_ch_info[ch].max_power_avg, ((eeprom_ch_info[ch]. flags & EEPROM_CHANNEL_IBSS) && !(eeprom_ch_info[ch]. flags & EEPROM_CHANNEL_RADAR)) ? "" : "not "); /* Set the tx_power_user_lmt to the highest power * supported by any channel */ if (eeprom_ch_info[ch].max_power_avg > priv->tx_power_user_lmt) priv->tx_power_user_lmt = eeprom_ch_info[ch].max_power_avg; ch_info++; } } /* Check if we do have FAT channels */ if (priv->cfg->ops->lib->eeprom_ops.regulatory_bands[5] == EEPROM_REGULATORY_BAND_NO_FAT && priv->cfg->ops->lib->eeprom_ops.regulatory_bands[6] == EEPROM_REGULATORY_BAND_NO_FAT) return 0; /* Two additional EEPROM bands for 2.4 and 5 GHz FAT channels */ for (band = 6; band <= 7; band++) { enum ieee80211_band ieeeband; u8 fat_extension_chan; iwl_init_band_reference(priv, band, &eeprom_ch_count, &eeprom_ch_info, &eeprom_ch_index); /* EEPROM band 6 is 2.4, band 7 is 5 GHz */ ieeeband = (band == 6) ? IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ; /* Loop through each band adding each of the channels */ for (ch = 0; ch < eeprom_ch_count; ch++) { if ((band == 6) && ((eeprom_ch_index[ch] == 5) || (eeprom_ch_index[ch] == 6) || (eeprom_ch_index[ch] == 7))) /* both are allowed: above and below */ fat_extension_chan = 0; else fat_extension_chan = IEEE80211_CHAN_NO_HT40MINUS; /* Set up driver's info for lower half */ iwl_set_fat_chan_info(priv, ieeeband, eeprom_ch_index[ch], &(eeprom_ch_info[ch]), fat_extension_chan); /* Set up driver's info for upper half */ iwl_set_fat_chan_info(priv, ieeeband, (eeprom_ch_index[ch] + 4), &(eeprom_ch_info[ch]), IEEE80211_CHAN_NO_HT40PLUS); } } return 0; }
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) { 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; if (cfg->device_family != IWL_DEVICE_FAMILY_8000) { num_of_ch = IWL_NUM_CHANNELS; nvm_chan = &iwl_nvm_channels[0]; num_2ghz_channels = NUM_2GHZ_CHANNELS; } else { num_of_ch = IWL_NUM_CHANNELS_FAMILY_8000; nvm_chan = &iwl_nvm_channels_family_8000[0]; num_2ghz_channels = NUM_2GHZ_CHANNELS_FAMILY_8000; } for (ch_idx = 0; ch_idx < num_of_ch; ch_idx++) { ch_flags = __le16_to_cpup(nvm_ch_flags + ch_idx); if (ch_idx >= num_2ghz_channels && !data->sku_cap_band_52GHz_enable) ch_flags &= ~NVM_CHANNEL_VALID; if (!(ch_flags & NVM_CHANNEL_VALID)) { 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"); continue; } channel = &data->channels[n_channels]; n_channels++; channel->hw_value = nvm_chan[ch_idx]; channel->band = (ch_idx < num_2ghz_channels) ? IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ; channel->center_freq = ieee80211_channel_to_frequency( channel->hw_value, channel->band); /* TODO: Need to be dependent to the NVM */ channel->flags = IEEE80211_CHAN_NO_HT40; if (ch_idx < num_2ghz_channels && (ch_flags & NVM_CHANNEL_40MHZ)) { if (nvm_chan[ch_idx] <= LAST_2GHZ_HT_PLUS) channel->flags &= ~IEEE80211_CHAN_NO_HT40PLUS; if (nvm_chan[ch_idx] >= FIRST_2GHZ_HT_MINUS) channel->flags &= ~IEEE80211_CHAN_NO_HT40MINUS; } else if (nvm_chan[ch_idx] <= LAST_5GHZ_HT && (ch_flags & NVM_CHANNEL_40MHZ)) { if ((ch_idx - num_2ghz_channels) % 2 == 0) channel->flags &= ~IEEE80211_CHAN_NO_HT40PLUS; else channel->flags &= ~IEEE80211_CHAN_NO_HT40MINUS; } if (!(ch_flags & NVM_CHANNEL_80MHZ)) channel->flags |= IEEE80211_CHAN_NO_80MHZ; if (!(ch_flags & NVM_CHANNEL_160MHZ)) channel->flags |= IEEE80211_CHAN_NO_160MHZ; if (!(ch_flags & NVM_CHANNEL_IBSS)) channel->flags |= IEEE80211_CHAN_NO_IR; if (!(ch_flags & NVM_CHANNEL_ACTIVE)) channel->flags |= IEEE80211_CHAN_NO_IR; if (ch_flags & NVM_CHANNEL_RADAR) channel->flags |= IEEE80211_CHAN_RADAR; /* Initialize regulatory-based run-time data */ /* * Default value - highest tx power value. max_power * is not used in mvm, and is used for backwards compatibility */ channel->max_power = DEFAULT_MAX_TX_POWER; is_5ghz = channel->band == IEEE80211_BAND_5GHZ; IWL_DEBUG_EEPROM(dev, "Ch. %d [%sGHz] %s%s%s%s%s%s(0x%02x %ddBm): Ad-Hoc %ssupported\n", channel->hw_value, is_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(WIDE), CHECK_AND_PRINT_I(DFS), ch_flags, channel->max_power, ((ch_flags & NVM_CHANNEL_IBSS) && !(ch_flags & NVM_CHANNEL_RADAR)) ? "" : "not "); } return n_channels; }
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) { int ch_idx; int n_channels = 0; struct ieee80211_channel *channel; u16 ch_flags; bool is_5ghz; for (ch_idx = 0; ch_idx < IWL_NUM_CHANNELS; ch_idx++) { ch_flags = __le16_to_cpup(nvm_ch_flags + ch_idx); if (!(ch_flags & NVM_CHANNEL_VALID)) { IWL_DEBUG_EEPROM(dev, "Ch. %d Flags %x [%sGHz] - No traffic\n", iwl_nvm_channels[ch_idx], ch_flags, (ch_idx >= NUM_2GHZ_CHANNELS) ? "5.2" : "2.4"); continue; } channel = &data->channels[n_channels]; n_channels++; channel->hw_value = iwl_nvm_channels[ch_idx]; channel->band = (ch_idx < NUM_2GHZ_CHANNELS) ? IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ; channel->center_freq = ieee80211_channel_to_frequency( channel->hw_value, channel->band); /* TODO: Need to be dependent to the NVM */ channel->flags = IEEE80211_CHAN_NO_HT40; if (ch_idx < NUM_2GHZ_CHANNELS && (ch_flags & NVM_CHANNEL_40MHZ)) { if (iwl_nvm_channels[ch_idx] <= LAST_2GHZ_HT_PLUS) channel->flags &= ~IEEE80211_CHAN_NO_HT40PLUS; if (iwl_nvm_channels[ch_idx] >= FIRST_2GHZ_HT_MINUS) channel->flags &= ~IEEE80211_CHAN_NO_HT40MINUS; } else if (iwl_nvm_channels[ch_idx] <= LAST_5GHZ_HT && (ch_flags & NVM_CHANNEL_40MHZ)) { if ((ch_idx - NUM_2GHZ_CHANNELS) % 2 == 0) channel->flags &= ~IEEE80211_CHAN_NO_HT40PLUS; else channel->flags &= ~IEEE80211_CHAN_NO_HT40MINUS; } if (!(ch_flags & NVM_CHANNEL_80MHZ)) channel->flags |= IEEE80211_CHAN_NO_80MHZ; if (!(ch_flags & NVM_CHANNEL_160MHZ)) channel->flags |= IEEE80211_CHAN_NO_160MHZ; if (!(ch_flags & NVM_CHANNEL_IBSS)) channel->flags |= IEEE80211_CHAN_NO_IBSS; if (!(ch_flags & NVM_CHANNEL_ACTIVE)) channel->flags |= IEEE80211_CHAN_PASSIVE_SCAN; if (ch_flags & NVM_CHANNEL_RADAR) channel->flags |= IEEE80211_CHAN_RADAR; /* Initialize regulatory-based run-time data */ /* TODO: read the real value from the NVM */ channel->max_power = 0; is_5ghz = channel->band == IEEE80211_BAND_5GHZ; IWL_DEBUG_EEPROM(dev, "Ch. %d [%sGHz] %s%s%s%s%s%s(0x%02x %ddBm): Ad-Hoc %ssupported\n", channel->hw_value, is_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(WIDE), CHECK_AND_PRINT_I(DFS), ch_flags, channel->max_power, ((ch_flags & NVM_CHANNEL_IBSS) && !(ch_flags & NVM_CHANNEL_RADAR)) ? "" : "not "); } return n_channels; }
static inline void iwl_nvm_print_channel_flags(struct device *dev, u32 level, int chan, u32 flags) { #define CHECK_AND_PRINT_I(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 }