aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/iwl-eeprom.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-eeprom.c')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-eeprom.c252
1 files changed, 252 insertions, 0 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c
index 01b95e89009a..3d2b93a61e62 100644
--- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c
+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c
@@ -135,6 +135,78 @@ static const u8 iwl_eeprom_band_7[] = { /* 5.2 ht40 channel */
135 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157 135 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157
136}; 136};
137 137
138/**
139 * struct iwl_txpwr_section: eeprom section information
140 * @offset: indirect address into eeprom image
141 * @count: number of "struct iwl_eeprom_enhanced_txpwr" in this section
142 * @band: band type for the section
143 * @is_common - true: common section, false: channel section
144 * @is_cck - true: cck section, false: not cck section
145 * @is_ht_40 - true: all channel in the section are HT40 channel,
146 * false: legacy or HT 20 MHz
147 * ignore if it is common section
148 * @iwl_eeprom_section_channel: channel array in the section,
149 * ignore if common section
150 */
151struct iwl_txpwr_section {
152 u32 offset;
153 u8 count;
154 enum ieee80211_band band;
155 bool is_common;
156 bool is_cck;
157 bool is_ht40;
158 u8 iwl_eeprom_section_channel[EEPROM_MAX_TXPOWER_SECTION_ELEMENTS];
159};
160
161/**
162 * section 1 - 3 are regulatory tx power apply to all channels based on
163 * modulation: CCK, OFDM
164 * Band: 2.4GHz, 5.2GHz
165 * section 4 - 10 are regulatory tx power apply to specified channels
166 * For example:
167 * 1L - Channel 1 Legacy
168 * 1HT - Channel 1 HT
169 * (1,+1) - Channel 1 HT40 "_above_"
170 *
171 * Section 1: all CCK channels
172 * Section 2: all 2.4 GHz OFDM (Legacy, HT and HT40) channels
173 * Section 3: all 5.2 GHz OFDM (Legacy, HT and HT40) channels
174 * Section 4: 2.4 GHz 20MHz channels: 1L, 1HT, 2L, 2HT, 10L, 10HT, 11L, 11HT
175 * Section 5: 2.4 GHz 40MHz channels: (1,+1) (2,+1) (6,+1) (7,+1) (9,+1)
176 * Section 6: 5.2 GHz 20MHz channels: 36L, 64L, 100L, 36HT, 64HT, 100HT
177 * Section 7: 5.2 GHz 40MHz channels: (36,+1) (60,+1) (100,+1)
178 * Section 8: 2.4 GHz channel: 13L, 13HT
179 * Section 9: 2.4 GHz channel: 140L, 140HT
180 * Section 10: 2.4 GHz 40MHz channels: (132,+1) (44,+1)
181 *
182 */
183static const struct iwl_txpwr_section enhinfo[] = {
184 { EEPROM_LB_CCK_20_COMMON, 1, IEEE80211_BAND_2GHZ, true, true, false },
185 { EEPROM_LB_OFDM_COMMON, 3, IEEE80211_BAND_2GHZ, true, false, false },
186 { EEPROM_HB_OFDM_COMMON, 3, IEEE80211_BAND_5GHZ, true, false, false },
187 { EEPROM_LB_OFDM_20_BAND, 8, IEEE80211_BAND_2GHZ,
188 false, false, false,
189 {1, 1, 2, 2, 10, 10, 11, 11 } },
190 { EEPROM_LB_OFDM_HT40_BAND, 5, IEEE80211_BAND_2GHZ,
191 false, false, true,
192 { 1, 2, 6, 7, 9 } },
193 { EEPROM_HB_OFDM_20_BAND, 6, IEEE80211_BAND_5GHZ,
194 false, false, false,
195 { 36, 64, 100, 36, 64, 100 } },
196 { EEPROM_HB_OFDM_HT40_BAND, 3, IEEE80211_BAND_5GHZ,
197 false, false, true,
198 { 36, 60, 100 } },
199 { EEPROM_LB_OFDM_20_CHANNEL_13, 2, IEEE80211_BAND_2GHZ,
200 false, false, false,
201 { 13, 13 } },
202 { EEPROM_HB_OFDM_20_CHANNEL_140, 2, IEEE80211_BAND_5GHZ,
203 false, false, false,
204 { 140, 140 } },
205 { EEPROM_HB_OFDM_HT40_BAND_1, 2, IEEE80211_BAND_5GHZ,
206 false, false, true,
207 { 132, 44 } },
208};
209
138/****************************************************************************** 210/******************************************************************************
139 * 211 *
140 * EEPROM related functions 212 * EEPROM related functions
@@ -643,6 +715,178 @@ static int iwl_mod_ht40_chan_info(struct iwl_priv *priv,
643 return 0; 715 return 0;
644} 716}
645 717
718/**
719 * iwl_get_max_txpower_avg - get the highest tx power from all chains.
720 * find the highest tx power from all chains for the channel
721 */
722static s8 iwl_get_max_txpower_avg(struct iwl_priv *priv,
723 struct iwl_eeprom_enhanced_txpwr *enhanced_txpower, int element)
724{
725 s8 max_txpower_avg = 0; /* (dBm) */
726
727 IWL_DEBUG_INFO(priv, "%d - "
728 "chain_a: %d dB chain_b: %d dB "
729 "chain_c: %d dB mimo2: %d dB mimo3: %d dB\n",
730 element,
731 enhanced_txpower[element].chain_a_max >> 1,
732 enhanced_txpower[element].chain_b_max >> 1,
733 enhanced_txpower[element].chain_c_max >> 1,
734 enhanced_txpower[element].mimo2_max >> 1,
735 enhanced_txpower[element].mimo3_max >> 1);
736 /* Take the highest tx power from any valid chains */
737 if ((priv->cfg->valid_tx_ant & ANT_A) &&
738 (enhanced_txpower[element].chain_a_max > max_txpower_avg))
739 max_txpower_avg = enhanced_txpower[element].chain_a_max;
740 if ((priv->cfg->valid_tx_ant & ANT_B) &&
741 (enhanced_txpower[element].chain_b_max > max_txpower_avg))
742 max_txpower_avg = enhanced_txpower[element].chain_b_max;
743 if ((priv->cfg->valid_tx_ant & ANT_C) &&
744 (enhanced_txpower[element].chain_c_max > max_txpower_avg))
745 max_txpower_avg = enhanced_txpower[element].chain_c_max;
746 if (((priv->cfg->valid_tx_ant == ANT_AB) |
747 (priv->cfg->valid_tx_ant == ANT_BC) |
748 (priv->cfg->valid_tx_ant == ANT_AC)) &&
749 (enhanced_txpower[element].mimo2_max > max_txpower_avg))
750 max_txpower_avg = enhanced_txpower[element].mimo2_max;
751 if ((priv->cfg->valid_tx_ant == ANT_ABC) &&
752 (enhanced_txpower[element].mimo3_max > max_txpower_avg))
753 max_txpower_avg = enhanced_txpower[element].mimo3_max;
754
755 /* max. tx power in EEPROM is in 1/2 dBm format
756 * convert from 1/2 dBm to dBm
757 */
758 return max_txpower_avg >> 1;
759}
760
761/**
762 * iwl_update_common_txpower: update channel tx power
763 * update tx power per band based on EEPROM enhanced tx power info.
764 */
765static s8 iwl_update_common_txpower(struct iwl_priv *priv,
766 struct iwl_eeprom_enhanced_txpwr *enhanced_txpower,
767 int section, int element)
768{
769 struct iwl_channel_info *ch_info;
770 int ch;
771 bool is_ht40 = false;
772 s8 max_txpower_avg; /* (dBm) */
773
774 /* it is common section, contain all type (Legacy, HT and HT40)
775 * based on the element in the section to determine
776 * is it HT 40 or not
777 */
778 if (element == EEPROM_TXPOWER_COMMON_HT40_INDEX)
779 is_ht40 = true;
780 max_txpower_avg =
781 iwl_get_max_txpower_avg(priv, enhanced_txpower, element);
782 ch_info = priv->channel_info;
783
784 for (ch = 0; ch < priv->channel_count; ch++) {
785 /* find matching band and update tx power if needed */
786 if ((ch_info->band == enhinfo[section].band) &&
787 (ch_info->max_power_avg < max_txpower_avg) && (!is_ht40)) {
788 /* Update regulatory-based run-time data */
789 ch_info->max_power_avg = ch_info->curr_txpow =
790 max_txpower_avg;
791 ch_info->scan_power = max_txpower_avg;
792 }
793 if ((ch_info->band == enhinfo[section].band) && is_ht40 &&
794 ch_info->ht40_max_power_avg &&
795 (ch_info->ht40_max_power_avg < max_txpower_avg)) {
796 /* Update regulatory-based run-time data */
797 ch_info->ht40_max_power_avg = max_txpower_avg;
798 ch_info->ht40_curr_txpow = max_txpower_avg;
799 ch_info->ht40_scan_power = max_txpower_avg;
800 }
801 ch_info++;
802 }
803 return max_txpower_avg;
804}
805
806/**
807 * iwl_update_channel_txpower: update channel tx power
808 * update channel tx power based on EEPROM enhanced tx power info.
809 */
810static s8 iwl_update_channel_txpower(struct iwl_priv *priv,
811 struct iwl_eeprom_enhanced_txpwr *enhanced_txpower,
812 int section, int element)
813{
814 struct iwl_channel_info *ch_info;
815 int ch;
816 u8 channel;
817 s8 max_txpower_avg; /* (dBm) */
818
819 channel = enhinfo[section].iwl_eeprom_section_channel[element];
820 max_txpower_avg =
821 iwl_get_max_txpower_avg(priv, enhanced_txpower, element);
822
823 ch_info = priv->channel_info;
824 for (ch = 0; ch < priv->channel_count; ch++) {
825 /* find matching channel and update tx power if needed */
826 if (ch_info->channel == channel) {
827 if ((ch_info->max_power_avg < max_txpower_avg) &&
828 (!enhinfo[section].is_ht40)) {
829 /* Update regulatory-based run-time data */
830 ch_info->max_power_avg = max_txpower_avg;
831 ch_info->curr_txpow = max_txpower_avg;
832 ch_info->scan_power = max_txpower_avg;
833 }
834 if ((enhinfo[section].is_ht40) &&
835 (ch_info->ht40_max_power_avg) &&
836 (ch_info->ht40_max_power_avg < max_txpower_avg)) {
837 /* Update regulatory-based run-time data */
838 ch_info->ht40_max_power_avg = max_txpower_avg;
839 ch_info->ht40_curr_txpow = max_txpower_avg;
840 ch_info->ht40_scan_power = max_txpower_avg;
841 }
842 break;
843 }
844 ch_info++;
845 }
846 return max_txpower_avg;
847}
848
849/**
850 * iwlcore_eeprom_enhanced_txpower: process enhanced tx power info
851 */
852void iwlcore_eeprom_enhanced_txpower(struct iwl_priv *priv)
853{
854 int eeprom_section_count = 0;
855 int section, element;
856 struct iwl_eeprom_enhanced_txpwr *enhanced_txpower;
857 u32 offset;
858 s8 max_txpower_avg; /* (dBm) */
859
860 /* Loop through all the sections
861 * adjust bands and channel's max tx power
862 * Set the tx_power_user_lmt to the highest power
863 * supported by any channels and chains
864 */
865 for (section = 0; section < ARRAY_SIZE(enhinfo); section++) {
866 eeprom_section_count = enhinfo[section].count;
867 offset = enhinfo[section].offset;
868 enhanced_txpower = (struct iwl_eeprom_enhanced_txpwr *)
869 iwl_eeprom_query_addr(priv, offset);
870
871 for (element = 0; element < eeprom_section_count; element++) {
872 if (enhinfo[section].is_common)
873 max_txpower_avg =
874 iwl_update_common_txpower(priv,
875 enhanced_txpower, section, element);
876 else
877 max_txpower_avg =
878 iwl_update_channel_txpower(priv,
879 enhanced_txpower, section, element);
880
881 /* Update the tx_power_user_lmt to the highest power
882 * supported by any channel */
883 if (max_txpower_avg > priv->tx_power_user_lmt)
884 priv->tx_power_user_lmt = max_txpower_avg;
885 }
886 }
887}
888EXPORT_SYMBOL(iwlcore_eeprom_enhanced_txpower);
889
646#define CHECK_AND_PRINT_I(x) ((eeprom_ch_info[ch].flags & EEPROM_CHANNEL_##x) \ 890#define CHECK_AND_PRINT_I(x) ((eeprom_ch_info[ch].flags & EEPROM_CHANNEL_##x) \
647 ? # x " " : "") 891 ? # x " " : "")
648 892
@@ -790,6 +1034,14 @@ int iwl_init_channel_map(struct iwl_priv *priv)
790 } 1034 }
791 } 1035 }
792 1036
1037 /* for newer device (6000 series and up)
1038 * EEPROM contain enhanced tx power information
1039 * driver need to process addition information
1040 * to determine the max channel tx power limits
1041 */
1042 if (priv->cfg->ops->lib->eeprom_ops.update_enhanced_txpower)
1043 priv->cfg->ops->lib->eeprom_ops.update_enhanced_txpower(priv);
1044
793 return 0; 1045 return 0;
794} 1046}
795EXPORT_SYMBOL(iwl_init_channel_map); 1047EXPORT_SYMBOL(iwl_init_channel_map);