aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c
diff options
context:
space:
mode:
authorArik Nemtsov <arik@wizery.com>2014-03-05 05:19:10 -0500
committerEmmanuel Grumbach <emmanuel.grumbach@intel.com>2015-03-12 03:57:22 -0400
commitaf45a9003f1f14af24804f7747f14238e8d51163 (patch)
tree8fe4b038d577987ec80ec9579264debad450a11f /drivers/net/wireless/iwlwifi/iwl-nvm-parse.c
parent90d4f7db6c5d8af1f4eab7bc714ec0ee130f9f00 (diff)
iwlwifi: create regdomain from mcc_update_cmd response
Parse the NVM channel data and create a regulatory domain with a rule for every 20Mhz channel. Use the AUTO_BW flag so the regulatory core can unify single-channel rules into ranges. Signed-off-by: Arik Nemtsov <arikx.nemtsov@intel.com> Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-nvm-parse.c')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-nvm-parse.c153
1 files changed, 153 insertions, 0 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c
index c74f1a4edf23..d8d9a97ff14c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c
+++ b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c
@@ -643,3 +643,156 @@ iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg,
643 return data; 643 return data;
644} 644}
645IWL_EXPORT_SYMBOL(iwl_parse_nvm_data); 645IWL_EXPORT_SYMBOL(iwl_parse_nvm_data);
646
647static u32 iwl_nvm_get_regdom_bw_flags(const u8 *nvm_chan,
648 int ch_idx, u16 nvm_flags)
649{
650 u32 flags = NL80211_RRF_NO_HT40;
651
652 if (ch_idx < NUM_2GHZ_CHANNELS &&
653 (nvm_flags & NVM_CHANNEL_40MHZ)) {
654 if (nvm_chan[ch_idx] <= LAST_2GHZ_HT_PLUS)
655 flags &= ~NL80211_RRF_NO_HT40PLUS;
656 if (nvm_chan[ch_idx] >= FIRST_2GHZ_HT_MINUS)
657 flags &= ~NL80211_RRF_NO_HT40MINUS;
658 } else if (nvm_chan[ch_idx] <= LAST_5GHZ_HT &&
659 (nvm_flags & NVM_CHANNEL_40MHZ)) {
660 if ((ch_idx - NUM_2GHZ_CHANNELS) % 2 == 0)
661 flags &= ~NL80211_RRF_NO_HT40PLUS;
662 else
663 flags &= ~NL80211_RRF_NO_HT40MINUS;
664 }
665
666 if (!(nvm_flags & NVM_CHANNEL_80MHZ))
667 flags |= NL80211_RRF_NO_80MHZ;
668 if (!(nvm_flags & NVM_CHANNEL_160MHZ))
669 flags |= NL80211_RRF_NO_160MHZ;
670
671 if (!(nvm_flags & NVM_CHANNEL_IBSS))
672 flags |= NL80211_RRF_NO_IR;
673
674 if (!(nvm_flags & NVM_CHANNEL_ACTIVE))
675 flags |= NL80211_RRF_NO_IR;
676
677 if (nvm_flags & NVM_CHANNEL_RADAR)
678 flags |= NL80211_RRF_DFS;
679
680 if (nvm_flags & NVM_CHANNEL_INDOOR_ONLY)
681 flags |= NL80211_RRF_NO_OUTDOOR;
682
683 /* Set the GO concurrent flag only in case that NO_IR is set.
684 * Otherwise it is meaningless
685 */
686 if ((nvm_flags & NVM_CHANNEL_GO_CONCURRENT) &&
687 (flags & NL80211_RRF_NO_IR))
688 flags |= NL80211_RRF_GO_CONCURRENT;
689
690 return flags;
691}
692
693struct ieee80211_regdomain *
694iwl_parse_nvm_mcc_info(struct device *dev, int num_of_ch, __le32 *channels,
695 u16 fw_mcc)
696{
697 int ch_idx;
698 u16 ch_flags, prev_ch_flags = 0;
699 const u8 *nvm_chan = iwl_nvm_channels; /* TODO: 8000 series differs */
700 struct ieee80211_regdomain *regd;
701 int size_of_regd;
702 struct ieee80211_reg_rule *rule;
703 enum ieee80211_band band;
704 int center_freq, prev_center_freq = 0;
705 int valid_rules = 0;
706 bool new_rule;
707
708 if (WARN_ON_ONCE(num_of_ch > NL80211_MAX_SUPP_REG_RULES))
709 return ERR_PTR(-EINVAL);
710
711 IWL_DEBUG_DEV(dev, IWL_DL_LAR, "building regdom for %d channels\n",
712 num_of_ch);
713
714 /* build a regdomain rule for every valid channel */
715 size_of_regd =
716 sizeof(struct ieee80211_regdomain) +
717 num_of_ch * sizeof(struct ieee80211_reg_rule);
718
719 regd = kzalloc(size_of_regd, GFP_KERNEL);
720 if (!regd)
721 return ERR_PTR(-ENOMEM);
722
723 for (ch_idx = 0; ch_idx < num_of_ch; ch_idx++) {
724 ch_flags = (u16)__le32_to_cpup(channels + ch_idx);
725 band = (ch_idx < NUM_2GHZ_CHANNELS) ?
726 IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
727 center_freq = ieee80211_channel_to_frequency(nvm_chan[ch_idx],
728 band);
729 new_rule = false;
730
731 if (!(ch_flags & NVM_CHANNEL_VALID)) {
732 IWL_DEBUG_DEV(dev, IWL_DL_LAR,
733 "Ch. %d Flags %x [%sGHz] - No traffic\n",
734 nvm_chan[ch_idx],
735 ch_flags,
736 (ch_idx >= NUM_2GHZ_CHANNELS) ?
737 "5.2" : "2.4");
738 continue;
739 }
740
741 /* we can't continue the same rule */
742 if (ch_idx == 0 || prev_ch_flags != ch_flags ||
743 center_freq - prev_center_freq > 20) {
744 valid_rules++;
745 new_rule = true;
746 }
747
748 rule = &regd->reg_rules[valid_rules - 1];
749
750 if (new_rule)
751 rule->freq_range.start_freq_khz =
752 MHZ_TO_KHZ(center_freq - 10);
753
754 rule->freq_range.end_freq_khz = MHZ_TO_KHZ(center_freq + 10);
755
756 /* this doesn't matter - not used by FW */
757 rule->power_rule.max_antenna_gain = DBI_TO_MBI(6);
758 rule->power_rule.max_eirp = DBM_TO_MBM(20);
759
760 rule->flags = iwl_nvm_get_regdom_bw_flags(nvm_chan, ch_idx,
761 ch_flags);
762
763 /* rely on auto-calculation to merge BW of contiguous chans */
764 rule->flags |= NL80211_RRF_AUTO_BW;
765 rule->freq_range.max_bandwidth_khz = 0;
766
767 prev_ch_flags = ch_flags;
768 prev_center_freq = center_freq;
769
770 IWL_DEBUG_DEV(dev, IWL_DL_LAR,
771 "Ch. %d [%sGHz] %s%s%s%s%s%s%s%s%s%s(0x%02x): Ad-Hoc %ssupported\n",
772 center_freq,
773 band == IEEE80211_BAND_5GHZ ? "5.2" : "2.4",
774 CHECK_AND_PRINT_I(VALID),
775 CHECK_AND_PRINT_I(IBSS),
776 CHECK_AND_PRINT_I(ACTIVE),
777 CHECK_AND_PRINT_I(RADAR),
778 CHECK_AND_PRINT_I(WIDE),
779 CHECK_AND_PRINT_I(40MHZ),
780 CHECK_AND_PRINT_I(80MHZ),
781 CHECK_AND_PRINT_I(160MHZ),
782 CHECK_AND_PRINT_I(INDOOR_ONLY),
783 CHECK_AND_PRINT_I(GO_CONCURRENT),
784 ch_flags,
785 ((ch_flags & NVM_CHANNEL_IBSS) &&
786 !(ch_flags & NVM_CHANNEL_RADAR))
787 ? "" : "not ");
788 }
789
790 regd->n_reg_rules = valid_rules;
791
792 /* set alpha2 from FW. */
793 regd->alpha2[0] = fw_mcc >> 8;
794 regd->alpha2[1] = fw_mcc & 0xff;
795
796 return regd;
797}
798IWL_EXPORT_SYMBOL(iwl_parse_nvm_mcc_info);