aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/iwl-eeprom.c
diff options
context:
space:
mode:
authorWey-Yi Guy <wey-yi.w.guy@intel.com>2009-08-21 16:34:23 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-08-28 14:40:39 -0400
commitab9fd1bf76ffebf6c3b3d5800092387edf1201b9 (patch)
treeafd95c882ca8d9b9ec671ce4f84d2a0433026ebf /drivers/net/wireless/iwlwifi/iwl-eeprom.c
parentc4d9b50986b4264f32883d19ac260a11647860e1 (diff)
iwlwifi: read enhanced tx power info from EEPROM image
For 6000 series and up, additional enhanced regulatory tx power limitation information is added to EEPROM image. In order to setup the tx power limitation per channel correctly. Read the enhanced tx power information from EEPROM image and update accordingly. The information is provided per SISO (a,b,c) chain based, it also has information for both MIMO2 and MIMO3. For tx power regulatory limitation, take the highest number from all the chains and update. Also update tx_power_user_lmt to the highest power supported by any channels and chains Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com> Signed-off-by: Reinette Chatre <reinette.chatre@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
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);