aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
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(