aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
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
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')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-6000.c1
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-eeprom.c252
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-eeprom.h80
3 files changed, 332 insertions, 1 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c
index 33ef736a4857..82b9c93dff54 100644
--- a/drivers/net/wireless/iwlwifi/iwl-6000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-6000.c
@@ -126,6 +126,7 @@ static struct iwl_lib_ops iwl6000_lib = {
126 .release_semaphore = iwlcore_eeprom_release_semaphore, 126 .release_semaphore = iwlcore_eeprom_release_semaphore,
127 .calib_version = iwl5000_eeprom_calib_version, 127 .calib_version = iwl5000_eeprom_calib_version,
128 .query_addr = iwl5000_eeprom_query_addr, 128 .query_addr = iwl5000_eeprom_query_addr,
129 .update_enhanced_txpower = iwlcore_eeprom_enhanced_txpower,
129 }, 130 },
130 .post_associate = iwl_post_associate, 131 .post_associate = iwl_post_associate,
131 .isr = iwl_isr_ict, 132 .isr = iwl_isr_ict,
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);
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h
index ca7920a8f52f..6b68db7b1b81 100644
--- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h
+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h
@@ -118,6 +118,30 @@ struct iwl_eeprom_channel {
118 s8 max_power_avg; /* max power (dBm) on this chnl, limit 31 */ 118 s8 max_power_avg; /* max power (dBm) on this chnl, limit 31 */
119} __attribute__ ((packed)); 119} __attribute__ ((packed));
120 120
121/**
122 * iwl_eeprom_enhanced_txpwr structure
123 * This structure presents the enhanced regulatory tx power limit layout
124 * in eeprom image
125 * Enhanced regulatory tx power portion of eeprom image can be broken down
126 * into individual structures; each one is 8 bytes in size and contain the
127 * following information
128 * @chain_a_max_pwr: chain a max power in 1/2 dBm
129 * @chain_b_max_pwr: chain b max power in 1/2 dBm
130 * @chain_c_max_pwr: chain c max power in 1/2 dBm
131 * @mimo2_max_pwr: mimo2 max power in 1/2 dBm
132 * @mimo3_max_pwr: mimo3 max power in 1/2 dBm
133 *
134 */
135struct iwl_eeprom_enhanced_txpwr {
136 u16 reserved;
137 s8 chain_a_max;
138 s8 chain_b_max;
139 s8 chain_c_max;
140 s8 reserved1;
141 s8 mimo2_max;
142 s8 mimo3_max;
143} __attribute__ ((packed));
144
121/* 3945 Specific */ 145/* 3945 Specific */
122#define EEPROM_3945_EEPROM_VERSION (0x2f) 146#define EEPROM_3945_EEPROM_VERSION (0x2f)
123 147
@@ -175,6 +199,59 @@ struct iwl_eeprom_channel {
175#define EEPROM_5000_REG_BAND_52_HT40_CHANNELS ((0x92)\ 199#define EEPROM_5000_REG_BAND_52_HT40_CHANNELS ((0x92)\
176 | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 22 bytes */ 200 | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 22 bytes */
177 201
202/* 6000 and up regulatory tx power - indirect access */
203/* max. elements per section */
204#define EEPROM_MAX_TXPOWER_SECTION_ELEMENTS (8)
205#define EEPROM_TXPOWER_COMMON_HT40_INDEX (2)
206
207/**
208 * Partition the enhanced tx power portion of eeprom image into
209 * 10 sections based on band, modulation, frequency and channel
210 *
211 * Section 1: all CCK channels
212 * Section 2: all 2.4 GHz OFDM (Legacy, HT and HT40 ) channels
213 * Section 3: all 5.2 GHz OFDM (Legacy, HT and HT40) channels
214 * Section 4: 2.4 GHz 20MHz channels: 1, 2, 10, 11. Both Legacy and HT
215 * Section 5: 2.4 GHz 40MHz channels: 1, 2, 6, 7, 9, (_above_)
216 * Section 6: 5.2 GHz 20MHz channels: 36, 64, 100, both Legacy and HT
217 * Section 7: 5.2 GHz 40MHz channels: 36, 60, 100 (_above_)
218 * Section 8: 2.4 GHz channel 13, Both Legacy and HT
219 * Section 9: 2.4 GHz channel 140, Both Legacy and HT
220 * Section 10: 2.4 GHz 40MHz channels: 132, 44 (_above_)
221 */
222/* 2.4 GHz band: CCK */
223#define EEPROM_LB_CCK_20_COMMON ((0xAA)\
224 | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 8 bytes */
225/* 2.4 GHz band: 20MHz-Legacy, 20MHz-HT, 40MHz-HT */
226#define EEPROM_LB_OFDM_COMMON ((0xB2)\
227 | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 24 bytes */
228/* 5.2 GHz band: 20MHz-Legacy, 20MHz-HT, 40MHz-HT */
229#define EEPROM_HB_OFDM_COMMON ((0xCA)\
230 | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 24 bytes */
231/* 2.4GHz band channels:
232 * 1Legacy, 1HT, 2Legacy, 2HT, 10Legacy, 10HT, 11Legacy, 11HT */
233#define EEPROM_LB_OFDM_20_BAND ((0xE2)\
234 | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 64 bytes */
235/* 2.4 GHz band HT40 channels: (1,+1) (2,+1) (6,+1) (7,+1) (9,+1) */
236#define EEPROM_LB_OFDM_HT40_BAND ((0x122)\
237 | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 40 bytes */
238/* 5.2GHz band channels: 36Legacy, 36HT, 64Legacy, 64HT, 100Legacy, 100HT */
239#define EEPROM_HB_OFDM_20_BAND ((0x14A)\
240 | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 48 bytes */
241/* 5.2 GHz band HT40 channels: (36,+1) (60,+1) (100,+1) */
242#define EEPROM_HB_OFDM_HT40_BAND ((0x17A)\
243 | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 24 bytes */
244/* 2.4 GHz band, channnel 13: Legacy, HT */
245#define EEPROM_LB_OFDM_20_CHANNEL_13 ((0x192)\
246 | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 16 bytes */
247/* 5.2 GHz band, channnel 140: Legacy, HT */
248#define EEPROM_HB_OFDM_20_CHANNEL_140 ((0x1A2)\
249 | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 16 bytes */
250/* 5.2 GHz band, HT40 channnels (132,+1) (44,+1) */
251#define EEPROM_HB_OFDM_HT40_BAND_1 ((0x1B2)\
252 | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 16 bytes */
253
254
178/* 5050 Specific */ 255/* 5050 Specific */
179#define EEPROM_5050_TX_POWER_VERSION (4) 256#define EEPROM_5050_TX_POWER_VERSION (4)
180#define EEPROM_5050_EEPROM_VERSION (0x21E) 257#define EEPROM_5050_EEPROM_VERSION (0x21E)
@@ -389,6 +466,7 @@ struct iwl_eeprom_ops {
389 void (*release_semaphore) (struct iwl_priv *priv); 466 void (*release_semaphore) (struct iwl_priv *priv);
390 u16 (*calib_version) (struct iwl_priv *priv); 467 u16 (*calib_version) (struct iwl_priv *priv);
391 const u8* (*query_addr) (const struct iwl_priv *priv, size_t offset); 468 const u8* (*query_addr) (const struct iwl_priv *priv, size_t offset);
469 void (*update_enhanced_txpower) (struct iwl_priv *priv);
392}; 470};
393 471
394 472
@@ -403,7 +481,7 @@ int iwlcore_eeprom_verify_signature(struct iwl_priv *priv);
403int iwlcore_eeprom_acquire_semaphore(struct iwl_priv *priv); 481int iwlcore_eeprom_acquire_semaphore(struct iwl_priv *priv);
404void iwlcore_eeprom_release_semaphore(struct iwl_priv *priv); 482void iwlcore_eeprom_release_semaphore(struct iwl_priv *priv);
405const u8 *iwlcore_eeprom_query_addr(const struct iwl_priv *priv, size_t offset); 483const u8 *iwlcore_eeprom_query_addr(const struct iwl_priv *priv, size_t offset);
406 484void iwlcore_eeprom_enhanced_txpower(struct iwl_priv *priv);
407int iwl_init_channel_map(struct iwl_priv *priv); 485int iwl_init_channel_map(struct iwl_priv *priv);
408void iwl_free_channel_map(struct iwl_priv *priv); 486void iwl_free_channel_map(struct iwl_priv *priv);
409const struct iwl_channel_info *iwl_get_channel_info( 487const struct iwl_channel_info *iwl_get_channel_info(