diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/dvm/devices.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/dvm/devices.c | 740 |
1 files changed, 740 insertions, 0 deletions
diff --git a/drivers/net/wireless/iwlwifi/dvm/devices.c b/drivers/net/wireless/iwlwifi/dvm/devices.c new file mode 100644 index 000000000000..ac5675d86ec3 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/dvm/devices.c | |||
@@ -0,0 +1,740 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * Copyright(c) 2008 - 2012 Intel Corporation. All rights reserved. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms of version 2 of the GNU General Public License as | ||
7 | * published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | * more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License along with | ||
15 | * this program; if not, write to the Free Software Foundation, Inc., | ||
16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA | ||
17 | * | ||
18 | * The full GNU General Public License is included in this distribution in the | ||
19 | * file called LICENSE. | ||
20 | * | ||
21 | * Contact Information: | ||
22 | * Intel Linux Wireless <ilw@linux.intel.com> | ||
23 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||
24 | * | ||
25 | *****************************************************************************/ | ||
26 | |||
27 | /* | ||
28 | * DVM device-specific data & functions | ||
29 | */ | ||
30 | #include "iwl-io.h" | ||
31 | #include "iwl-prph.h" | ||
32 | |||
33 | #include "agn.h" | ||
34 | #include "dev.h" | ||
35 | #include "commands.h" | ||
36 | |||
37 | /* | ||
38 | * 1000 series | ||
39 | * =========== | ||
40 | */ | ||
41 | |||
42 | /* | ||
43 | * For 1000, use advance thermal throttling critical temperature threshold, | ||
44 | * but legacy thermal management implementation for now. | ||
45 | * This is for the reason of 1000 uCode using advance thermal throttling API | ||
46 | * but not implement ct_kill_exit based on ct_kill exit temperature | ||
47 | * so the thermal throttling will still based on legacy thermal throttling | ||
48 | * management. | ||
49 | * The code here need to be modified once 1000 uCode has the advanced thermal | ||
50 | * throttling algorithm in place | ||
51 | */ | ||
52 | static void iwl1000_set_ct_threshold(struct iwl_priv *priv) | ||
53 | { | ||
54 | /* want Celsius */ | ||
55 | priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD_LEGACY; | ||
56 | priv->hw_params.ct_kill_exit_threshold = CT_KILL_EXIT_THRESHOLD; | ||
57 | } | ||
58 | |||
59 | /* NIC configuration for 1000 series */ | ||
60 | static void iwl1000_nic_config(struct iwl_priv *priv) | ||
61 | { | ||
62 | /* set CSR_HW_CONFIG_REG for uCode use */ | ||
63 | iwl_set_bit(priv->trans, CSR_HW_IF_CONFIG_REG, | ||
64 | CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI | | ||
65 | CSR_HW_IF_CONFIG_REG_BIT_MAC_SI); | ||
66 | |||
67 | /* Setting digital SVR for 1000 card to 1.32V */ | ||
68 | /* locking is acquired in iwl_set_bits_mask_prph() function */ | ||
69 | iwl_set_bits_mask_prph(priv->trans, APMG_DIGITAL_SVR_REG, | ||
70 | APMG_SVR_DIGITAL_VOLTAGE_1_32, | ||
71 | ~APMG_SVR_VOLTAGE_CONFIG_BIT_MSK); | ||
72 | } | ||
73 | |||
74 | /** | ||
75 | * iwl_beacon_time_mask_low - mask of lower 32 bit of beacon time | ||
76 | * @priv -- pointer to iwl_priv data structure | ||
77 | * @tsf_bits -- number of bits need to shift for masking) | ||
78 | */ | ||
79 | static inline u32 iwl_beacon_time_mask_low(struct iwl_priv *priv, | ||
80 | u16 tsf_bits) | ||
81 | { | ||
82 | return (1 << tsf_bits) - 1; | ||
83 | } | ||
84 | |||
85 | /** | ||
86 | * iwl_beacon_time_mask_high - mask of higher 32 bit of beacon time | ||
87 | * @priv -- pointer to iwl_priv data structure | ||
88 | * @tsf_bits -- number of bits need to shift for masking) | ||
89 | */ | ||
90 | static inline u32 iwl_beacon_time_mask_high(struct iwl_priv *priv, | ||
91 | u16 tsf_bits) | ||
92 | { | ||
93 | return ((1 << (32 - tsf_bits)) - 1) << tsf_bits; | ||
94 | } | ||
95 | |||
96 | /* | ||
97 | * extended beacon time format | ||
98 | * time in usec will be changed into a 32-bit value in extended:internal format | ||
99 | * the extended part is the beacon counts | ||
100 | * the internal part is the time in usec within one beacon interval | ||
101 | */ | ||
102 | static u32 iwl_usecs_to_beacons(struct iwl_priv *priv, u32 usec, | ||
103 | u32 beacon_interval) | ||
104 | { | ||
105 | u32 quot; | ||
106 | u32 rem; | ||
107 | u32 interval = beacon_interval * TIME_UNIT; | ||
108 | |||
109 | if (!interval || !usec) | ||
110 | return 0; | ||
111 | |||
112 | quot = (usec / interval) & | ||
113 | (iwl_beacon_time_mask_high(priv, IWLAGN_EXT_BEACON_TIME_POS) >> | ||
114 | IWLAGN_EXT_BEACON_TIME_POS); | ||
115 | rem = (usec % interval) & iwl_beacon_time_mask_low(priv, | ||
116 | IWLAGN_EXT_BEACON_TIME_POS); | ||
117 | |||
118 | return (quot << IWLAGN_EXT_BEACON_TIME_POS) + rem; | ||
119 | } | ||
120 | |||
121 | /* base is usually what we get from ucode with each received frame, | ||
122 | * the same as HW timer counter counting down | ||
123 | */ | ||
124 | static __le32 iwl_add_beacon_time(struct iwl_priv *priv, u32 base, | ||
125 | u32 addon, u32 beacon_interval) | ||
126 | { | ||
127 | u32 base_low = base & iwl_beacon_time_mask_low(priv, | ||
128 | IWLAGN_EXT_BEACON_TIME_POS); | ||
129 | u32 addon_low = addon & iwl_beacon_time_mask_low(priv, | ||
130 | IWLAGN_EXT_BEACON_TIME_POS); | ||
131 | u32 interval = beacon_interval * TIME_UNIT; | ||
132 | u32 res = (base & iwl_beacon_time_mask_high(priv, | ||
133 | IWLAGN_EXT_BEACON_TIME_POS)) + | ||
134 | (addon & iwl_beacon_time_mask_high(priv, | ||
135 | IWLAGN_EXT_BEACON_TIME_POS)); | ||
136 | |||
137 | if (base_low > addon_low) | ||
138 | res += base_low - addon_low; | ||
139 | else if (base_low < addon_low) { | ||
140 | res += interval + base_low - addon_low; | ||
141 | res += (1 << IWLAGN_EXT_BEACON_TIME_POS); | ||
142 | } else | ||
143 | res += (1 << IWLAGN_EXT_BEACON_TIME_POS); | ||
144 | |||
145 | return cpu_to_le32(res); | ||
146 | } | ||
147 | |||
148 | static const struct iwl_sensitivity_ranges iwl1000_sensitivity = { | ||
149 | .min_nrg_cck = 95, | ||
150 | .auto_corr_min_ofdm = 90, | ||
151 | .auto_corr_min_ofdm_mrc = 170, | ||
152 | .auto_corr_min_ofdm_x1 = 120, | ||
153 | .auto_corr_min_ofdm_mrc_x1 = 240, | ||
154 | |||
155 | .auto_corr_max_ofdm = 120, | ||
156 | .auto_corr_max_ofdm_mrc = 210, | ||
157 | .auto_corr_max_ofdm_x1 = 155, | ||
158 | .auto_corr_max_ofdm_mrc_x1 = 290, | ||
159 | |||
160 | .auto_corr_min_cck = 125, | ||
161 | .auto_corr_max_cck = 200, | ||
162 | .auto_corr_min_cck_mrc = 170, | ||
163 | .auto_corr_max_cck_mrc = 400, | ||
164 | .nrg_th_cck = 95, | ||
165 | .nrg_th_ofdm = 95, | ||
166 | |||
167 | .barker_corr_th_min = 190, | ||
168 | .barker_corr_th_min_mrc = 390, | ||
169 | .nrg_th_cca = 62, | ||
170 | }; | ||
171 | |||
172 | static void iwl1000_hw_set_hw_params(struct iwl_priv *priv) | ||
173 | { | ||
174 | priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ); | ||
175 | |||
176 | priv->hw_params.tx_chains_num = | ||
177 | num_of_ant(priv->hw_params.valid_tx_ant); | ||
178 | if (priv->cfg->rx_with_siso_diversity) | ||
179 | priv->hw_params.rx_chains_num = 1; | ||
180 | else | ||
181 | priv->hw_params.rx_chains_num = | ||
182 | num_of_ant(priv->hw_params.valid_rx_ant); | ||
183 | |||
184 | iwl1000_set_ct_threshold(priv); | ||
185 | |||
186 | /* Set initial sensitivity parameters */ | ||
187 | priv->hw_params.sens = &iwl1000_sensitivity; | ||
188 | } | ||
189 | |||
190 | struct iwl_lib_ops iwl1000_lib = { | ||
191 | .set_hw_params = iwl1000_hw_set_hw_params, | ||
192 | .nic_config = iwl1000_nic_config, | ||
193 | .eeprom_ops = { | ||
194 | .regulatory_bands = { | ||
195 | EEPROM_REG_BAND_1_CHANNELS, | ||
196 | EEPROM_REG_BAND_2_CHANNELS, | ||
197 | EEPROM_REG_BAND_3_CHANNELS, | ||
198 | EEPROM_REG_BAND_4_CHANNELS, | ||
199 | EEPROM_REG_BAND_5_CHANNELS, | ||
200 | EEPROM_REG_BAND_24_HT40_CHANNELS, | ||
201 | EEPROM_REGULATORY_BAND_NO_HT40, | ||
202 | }, | ||
203 | }, | ||
204 | .temperature = iwlagn_temperature, | ||
205 | }; | ||
206 | |||
207 | |||
208 | /* | ||
209 | * 2000 series | ||
210 | * =========== | ||
211 | */ | ||
212 | |||
213 | static void iwl2000_set_ct_threshold(struct iwl_priv *priv) | ||
214 | { | ||
215 | /* want Celsius */ | ||
216 | priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD; | ||
217 | priv->hw_params.ct_kill_exit_threshold = CT_KILL_EXIT_THRESHOLD; | ||
218 | } | ||
219 | |||
220 | /* NIC configuration for 2000 series */ | ||
221 | static void iwl2000_nic_config(struct iwl_priv *priv) | ||
222 | { | ||
223 | iwl_rf_config(priv); | ||
224 | |||
225 | iwl_set_bit(priv->trans, CSR_GP_DRIVER_REG, | ||
226 | CSR_GP_DRIVER_REG_BIT_RADIO_IQ_INVER); | ||
227 | } | ||
228 | |||
229 | static const struct iwl_sensitivity_ranges iwl2000_sensitivity = { | ||
230 | .min_nrg_cck = 97, | ||
231 | .auto_corr_min_ofdm = 80, | ||
232 | .auto_corr_min_ofdm_mrc = 128, | ||
233 | .auto_corr_min_ofdm_x1 = 105, | ||
234 | .auto_corr_min_ofdm_mrc_x1 = 192, | ||
235 | |||
236 | .auto_corr_max_ofdm = 145, | ||
237 | .auto_corr_max_ofdm_mrc = 232, | ||
238 | .auto_corr_max_ofdm_x1 = 110, | ||
239 | .auto_corr_max_ofdm_mrc_x1 = 232, | ||
240 | |||
241 | .auto_corr_min_cck = 125, | ||
242 | .auto_corr_max_cck = 175, | ||
243 | .auto_corr_min_cck_mrc = 160, | ||
244 | .auto_corr_max_cck_mrc = 310, | ||
245 | .nrg_th_cck = 97, | ||
246 | .nrg_th_ofdm = 100, | ||
247 | |||
248 | .barker_corr_th_min = 190, | ||
249 | .barker_corr_th_min_mrc = 390, | ||
250 | .nrg_th_cca = 62, | ||
251 | }; | ||
252 | |||
253 | static void iwl2000_hw_set_hw_params(struct iwl_priv *priv) | ||
254 | { | ||
255 | priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ); | ||
256 | |||
257 | priv->hw_params.tx_chains_num = | ||
258 | num_of_ant(priv->hw_params.valid_tx_ant); | ||
259 | if (priv->cfg->rx_with_siso_diversity) | ||
260 | priv->hw_params.rx_chains_num = 1; | ||
261 | else | ||
262 | priv->hw_params.rx_chains_num = | ||
263 | num_of_ant(priv->hw_params.valid_rx_ant); | ||
264 | |||
265 | iwl2000_set_ct_threshold(priv); | ||
266 | |||
267 | /* Set initial sensitivity parameters */ | ||
268 | priv->hw_params.sens = &iwl2000_sensitivity; | ||
269 | } | ||
270 | |||
271 | struct iwl_lib_ops iwl2000_lib = { | ||
272 | .set_hw_params = iwl2000_hw_set_hw_params, | ||
273 | .nic_config = iwl2000_nic_config, | ||
274 | .eeprom_ops = { | ||
275 | .regulatory_bands = { | ||
276 | EEPROM_REG_BAND_1_CHANNELS, | ||
277 | EEPROM_REG_BAND_2_CHANNELS, | ||
278 | EEPROM_REG_BAND_3_CHANNELS, | ||
279 | EEPROM_REG_BAND_4_CHANNELS, | ||
280 | EEPROM_REG_BAND_5_CHANNELS, | ||
281 | EEPROM_6000_REG_BAND_24_HT40_CHANNELS, | ||
282 | EEPROM_REGULATORY_BAND_NO_HT40, | ||
283 | }, | ||
284 | .enhanced_txpower = true, | ||
285 | }, | ||
286 | .temperature = iwlagn_temperature, | ||
287 | }; | ||
288 | |||
289 | struct iwl_lib_ops iwl2030_lib = { | ||
290 | .set_hw_params = iwl2000_hw_set_hw_params, | ||
291 | .nic_config = iwl2000_nic_config, | ||
292 | .eeprom_ops = { | ||
293 | .regulatory_bands = { | ||
294 | EEPROM_REG_BAND_1_CHANNELS, | ||
295 | EEPROM_REG_BAND_2_CHANNELS, | ||
296 | EEPROM_REG_BAND_3_CHANNELS, | ||
297 | EEPROM_REG_BAND_4_CHANNELS, | ||
298 | EEPROM_REG_BAND_5_CHANNELS, | ||
299 | EEPROM_6000_REG_BAND_24_HT40_CHANNELS, | ||
300 | EEPROM_REGULATORY_BAND_NO_HT40, | ||
301 | }, | ||
302 | .enhanced_txpower = true, | ||
303 | }, | ||
304 | .temperature = iwlagn_temperature, | ||
305 | }; | ||
306 | |||
307 | /* | ||
308 | * 5000 series | ||
309 | * =========== | ||
310 | */ | ||
311 | |||
312 | /* NIC configuration for 5000 series */ | ||
313 | static void iwl5000_nic_config(struct iwl_priv *priv) | ||
314 | { | ||
315 | iwl_rf_config(priv); | ||
316 | |||
317 | /* W/A : NIC is stuck in a reset state after Early PCIe power off | ||
318 | * (PCIe power is lost before PERST# is asserted), | ||
319 | * causing ME FW to lose ownership and not being able to obtain it back. | ||
320 | */ | ||
321 | iwl_set_bits_mask_prph(priv->trans, APMG_PS_CTRL_REG, | ||
322 | APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS, | ||
323 | ~APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS); | ||
324 | } | ||
325 | |||
326 | static const struct iwl_sensitivity_ranges iwl5000_sensitivity = { | ||
327 | .min_nrg_cck = 100, | ||
328 | .auto_corr_min_ofdm = 90, | ||
329 | .auto_corr_min_ofdm_mrc = 170, | ||
330 | .auto_corr_min_ofdm_x1 = 105, | ||
331 | .auto_corr_min_ofdm_mrc_x1 = 220, | ||
332 | |||
333 | .auto_corr_max_ofdm = 120, | ||
334 | .auto_corr_max_ofdm_mrc = 210, | ||
335 | .auto_corr_max_ofdm_x1 = 120, | ||
336 | .auto_corr_max_ofdm_mrc_x1 = 240, | ||
337 | |||
338 | .auto_corr_min_cck = 125, | ||
339 | .auto_corr_max_cck = 200, | ||
340 | .auto_corr_min_cck_mrc = 200, | ||
341 | .auto_corr_max_cck_mrc = 400, | ||
342 | .nrg_th_cck = 100, | ||
343 | .nrg_th_ofdm = 100, | ||
344 | |||
345 | .barker_corr_th_min = 190, | ||
346 | .barker_corr_th_min_mrc = 390, | ||
347 | .nrg_th_cca = 62, | ||
348 | }; | ||
349 | |||
350 | static struct iwl_sensitivity_ranges iwl5150_sensitivity = { | ||
351 | .min_nrg_cck = 95, | ||
352 | .auto_corr_min_ofdm = 90, | ||
353 | .auto_corr_min_ofdm_mrc = 170, | ||
354 | .auto_corr_min_ofdm_x1 = 105, | ||
355 | .auto_corr_min_ofdm_mrc_x1 = 220, | ||
356 | |||
357 | .auto_corr_max_ofdm = 120, | ||
358 | .auto_corr_max_ofdm_mrc = 210, | ||
359 | /* max = min for performance bug in 5150 DSP */ | ||
360 | .auto_corr_max_ofdm_x1 = 105, | ||
361 | .auto_corr_max_ofdm_mrc_x1 = 220, | ||
362 | |||
363 | .auto_corr_min_cck = 125, | ||
364 | .auto_corr_max_cck = 200, | ||
365 | .auto_corr_min_cck_mrc = 170, | ||
366 | .auto_corr_max_cck_mrc = 400, | ||
367 | .nrg_th_cck = 95, | ||
368 | .nrg_th_ofdm = 95, | ||
369 | |||
370 | .barker_corr_th_min = 190, | ||
371 | .barker_corr_th_min_mrc = 390, | ||
372 | .nrg_th_cca = 62, | ||
373 | }; | ||
374 | |||
375 | #define IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF (-5) | ||
376 | |||
377 | static s32 iwl_temp_calib_to_offset(struct iwl_priv *priv) | ||
378 | { | ||
379 | u16 temperature, voltage; | ||
380 | __le16 *temp_calib = (__le16 *)iwl_eeprom_query_addr(priv, | ||
381 | EEPROM_KELVIN_TEMPERATURE); | ||
382 | |||
383 | temperature = le16_to_cpu(temp_calib[0]); | ||
384 | voltage = le16_to_cpu(temp_calib[1]); | ||
385 | |||
386 | /* offset = temp - volt / coeff */ | ||
387 | return (s32)(temperature - | ||
388 | voltage / IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF); | ||
389 | } | ||
390 | |||
391 | static void iwl5150_set_ct_threshold(struct iwl_priv *priv) | ||
392 | { | ||
393 | const s32 volt2temp_coef = IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF; | ||
394 | s32 threshold = (s32)CELSIUS_TO_KELVIN(CT_KILL_THRESHOLD_LEGACY) - | ||
395 | iwl_temp_calib_to_offset(priv); | ||
396 | |||
397 | priv->hw_params.ct_kill_threshold = threshold * volt2temp_coef; | ||
398 | } | ||
399 | |||
400 | static void iwl5000_set_ct_threshold(struct iwl_priv *priv) | ||
401 | { | ||
402 | /* want Celsius */ | ||
403 | priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD_LEGACY; | ||
404 | } | ||
405 | |||
406 | static void iwl5000_hw_set_hw_params(struct iwl_priv *priv) | ||
407 | { | ||
408 | priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ) | | ||
409 | BIT(IEEE80211_BAND_5GHZ); | ||
410 | |||
411 | priv->hw_params.tx_chains_num = | ||
412 | num_of_ant(priv->hw_params.valid_tx_ant); | ||
413 | priv->hw_params.rx_chains_num = | ||
414 | num_of_ant(priv->hw_params.valid_rx_ant); | ||
415 | |||
416 | iwl5000_set_ct_threshold(priv); | ||
417 | |||
418 | /* Set initial sensitivity parameters */ | ||
419 | priv->hw_params.sens = &iwl5000_sensitivity; | ||
420 | } | ||
421 | |||
422 | static void iwl5150_hw_set_hw_params(struct iwl_priv *priv) | ||
423 | { | ||
424 | priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ) | | ||
425 | BIT(IEEE80211_BAND_5GHZ); | ||
426 | |||
427 | priv->hw_params.tx_chains_num = | ||
428 | num_of_ant(priv->hw_params.valid_tx_ant); | ||
429 | priv->hw_params.rx_chains_num = | ||
430 | num_of_ant(priv->hw_params.valid_rx_ant); | ||
431 | |||
432 | iwl5150_set_ct_threshold(priv); | ||
433 | |||
434 | /* Set initial sensitivity parameters */ | ||
435 | priv->hw_params.sens = &iwl5150_sensitivity; | ||
436 | } | ||
437 | |||
438 | static void iwl5150_temperature(struct iwl_priv *priv) | ||
439 | { | ||
440 | u32 vt = 0; | ||
441 | s32 offset = iwl_temp_calib_to_offset(priv); | ||
442 | |||
443 | vt = le32_to_cpu(priv->statistics.common.temperature); | ||
444 | vt = vt / IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF + offset; | ||
445 | /* now vt hold the temperature in Kelvin */ | ||
446 | priv->temperature = KELVIN_TO_CELSIUS(vt); | ||
447 | iwl_tt_handler(priv); | ||
448 | } | ||
449 | |||
450 | static int iwl5000_hw_channel_switch(struct iwl_priv *priv, | ||
451 | struct ieee80211_channel_switch *ch_switch) | ||
452 | { | ||
453 | /* | ||
454 | * MULTI-FIXME | ||
455 | * See iwlagn_mac_channel_switch. | ||
456 | */ | ||
457 | struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; | ||
458 | struct iwl5000_channel_switch_cmd cmd; | ||
459 | u32 switch_time_in_usec, ucode_switch_time; | ||
460 | u16 ch; | ||
461 | u32 tsf_low; | ||
462 | u8 switch_count; | ||
463 | u16 beacon_interval = le16_to_cpu(ctx->timing.beacon_interval); | ||
464 | struct ieee80211_vif *vif = ctx->vif; | ||
465 | struct iwl_host_cmd hcmd = { | ||
466 | .id = REPLY_CHANNEL_SWITCH, | ||
467 | .len = { sizeof(cmd), }, | ||
468 | .flags = CMD_SYNC, | ||
469 | .data = { &cmd, }, | ||
470 | }; | ||
471 | |||
472 | cmd.band = priv->band == IEEE80211_BAND_2GHZ; | ||
473 | ch = ch_switch->channel->hw_value; | ||
474 | IWL_DEBUG_11H(priv, "channel switch from %d to %d\n", | ||
475 | ctx->active.channel, ch); | ||
476 | cmd.channel = cpu_to_le16(ch); | ||
477 | cmd.rxon_flags = ctx->staging.flags; | ||
478 | cmd.rxon_filter_flags = ctx->staging.filter_flags; | ||
479 | switch_count = ch_switch->count; | ||
480 | tsf_low = ch_switch->timestamp & 0x0ffffffff; | ||
481 | /* | ||
482 | * calculate the ucode channel switch time | ||
483 | * adding TSF as one of the factor for when to switch | ||
484 | */ | ||
485 | if ((priv->ucode_beacon_time > tsf_low) && beacon_interval) { | ||
486 | if (switch_count > ((priv->ucode_beacon_time - tsf_low) / | ||
487 | beacon_interval)) { | ||
488 | switch_count -= (priv->ucode_beacon_time - | ||
489 | tsf_low) / beacon_interval; | ||
490 | } else | ||
491 | switch_count = 0; | ||
492 | } | ||
493 | if (switch_count <= 1) | ||
494 | cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time); | ||
495 | else { | ||
496 | switch_time_in_usec = | ||
497 | vif->bss_conf.beacon_int * switch_count * TIME_UNIT; | ||
498 | ucode_switch_time = iwl_usecs_to_beacons(priv, | ||
499 | switch_time_in_usec, | ||
500 | beacon_interval); | ||
501 | cmd.switch_time = iwl_add_beacon_time(priv, | ||
502 | priv->ucode_beacon_time, | ||
503 | ucode_switch_time, | ||
504 | beacon_interval); | ||
505 | } | ||
506 | IWL_DEBUG_11H(priv, "uCode time for the switch is 0x%x\n", | ||
507 | cmd.switch_time); | ||
508 | cmd.expect_beacon = ch_switch->channel->flags & IEEE80211_CHAN_RADAR; | ||
509 | |||
510 | return iwl_dvm_send_cmd(priv, &hcmd); | ||
511 | } | ||
512 | |||
513 | struct iwl_lib_ops iwl5000_lib = { | ||
514 | .set_hw_params = iwl5000_hw_set_hw_params, | ||
515 | .set_channel_switch = iwl5000_hw_channel_switch, | ||
516 | .nic_config = iwl5000_nic_config, | ||
517 | .eeprom_ops = { | ||
518 | .regulatory_bands = { | ||
519 | EEPROM_REG_BAND_1_CHANNELS, | ||
520 | EEPROM_REG_BAND_2_CHANNELS, | ||
521 | EEPROM_REG_BAND_3_CHANNELS, | ||
522 | EEPROM_REG_BAND_4_CHANNELS, | ||
523 | EEPROM_REG_BAND_5_CHANNELS, | ||
524 | EEPROM_REG_BAND_24_HT40_CHANNELS, | ||
525 | EEPROM_REG_BAND_52_HT40_CHANNELS | ||
526 | }, | ||
527 | }, | ||
528 | .temperature = iwlagn_temperature, | ||
529 | }; | ||
530 | |||
531 | struct iwl_lib_ops iwl5150_lib = { | ||
532 | .set_hw_params = iwl5150_hw_set_hw_params, | ||
533 | .set_channel_switch = iwl5000_hw_channel_switch, | ||
534 | .nic_config = iwl5000_nic_config, | ||
535 | .eeprom_ops = { | ||
536 | .regulatory_bands = { | ||
537 | EEPROM_REG_BAND_1_CHANNELS, | ||
538 | EEPROM_REG_BAND_2_CHANNELS, | ||
539 | EEPROM_REG_BAND_3_CHANNELS, | ||
540 | EEPROM_REG_BAND_4_CHANNELS, | ||
541 | EEPROM_REG_BAND_5_CHANNELS, | ||
542 | EEPROM_REG_BAND_24_HT40_CHANNELS, | ||
543 | EEPROM_REG_BAND_52_HT40_CHANNELS | ||
544 | }, | ||
545 | }, | ||
546 | .temperature = iwl5150_temperature, | ||
547 | }; | ||
548 | |||
549 | |||
550 | |||
551 | /* | ||
552 | * 6000 series | ||
553 | * =========== | ||
554 | */ | ||
555 | |||
556 | static void iwl6000_set_ct_threshold(struct iwl_priv *priv) | ||
557 | { | ||
558 | /* want Celsius */ | ||
559 | priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD; | ||
560 | priv->hw_params.ct_kill_exit_threshold = CT_KILL_EXIT_THRESHOLD; | ||
561 | } | ||
562 | |||
563 | /* NIC configuration for 6000 series */ | ||
564 | static void iwl6000_nic_config(struct iwl_priv *priv) | ||
565 | { | ||
566 | iwl_rf_config(priv); | ||
567 | |||
568 | switch (priv->cfg->device_family) { | ||
569 | case IWL_DEVICE_FAMILY_6005: | ||
570 | case IWL_DEVICE_FAMILY_6030: | ||
571 | case IWL_DEVICE_FAMILY_6000: | ||
572 | break; | ||
573 | case IWL_DEVICE_FAMILY_6000i: | ||
574 | /* 2x2 IPA phy type */ | ||
575 | iwl_write32(priv->trans, CSR_GP_DRIVER_REG, | ||
576 | CSR_GP_DRIVER_REG_BIT_RADIO_SKU_2x2_IPA); | ||
577 | break; | ||
578 | case IWL_DEVICE_FAMILY_6050: | ||
579 | /* Indicate calibration version to uCode. */ | ||
580 | if (iwl_eeprom_calib_version(priv) >= 6) | ||
581 | iwl_set_bit(priv->trans, CSR_GP_DRIVER_REG, | ||
582 | CSR_GP_DRIVER_REG_BIT_CALIB_VERSION6); | ||
583 | break; | ||
584 | case IWL_DEVICE_FAMILY_6150: | ||
585 | /* Indicate calibration version to uCode. */ | ||
586 | if (iwl_eeprom_calib_version(priv) >= 6) | ||
587 | iwl_set_bit(priv->trans, CSR_GP_DRIVER_REG, | ||
588 | CSR_GP_DRIVER_REG_BIT_CALIB_VERSION6); | ||
589 | iwl_set_bit(priv->trans, CSR_GP_DRIVER_REG, | ||
590 | CSR_GP_DRIVER_REG_BIT_6050_1x2); | ||
591 | break; | ||
592 | default: | ||
593 | WARN_ON(1); | ||
594 | } | ||
595 | } | ||
596 | |||
597 | static const struct iwl_sensitivity_ranges iwl6000_sensitivity = { | ||
598 | .min_nrg_cck = 110, | ||
599 | .auto_corr_min_ofdm = 80, | ||
600 | .auto_corr_min_ofdm_mrc = 128, | ||
601 | .auto_corr_min_ofdm_x1 = 105, | ||
602 | .auto_corr_min_ofdm_mrc_x1 = 192, | ||
603 | |||
604 | .auto_corr_max_ofdm = 145, | ||
605 | .auto_corr_max_ofdm_mrc = 232, | ||
606 | .auto_corr_max_ofdm_x1 = 110, | ||
607 | .auto_corr_max_ofdm_mrc_x1 = 232, | ||
608 | |||
609 | .auto_corr_min_cck = 125, | ||
610 | .auto_corr_max_cck = 175, | ||
611 | .auto_corr_min_cck_mrc = 160, | ||
612 | .auto_corr_max_cck_mrc = 310, | ||
613 | .nrg_th_cck = 110, | ||
614 | .nrg_th_ofdm = 110, | ||
615 | |||
616 | .barker_corr_th_min = 190, | ||
617 | .barker_corr_th_min_mrc = 336, | ||
618 | .nrg_th_cca = 62, | ||
619 | }; | ||
620 | |||
621 | static void iwl6000_hw_set_hw_params(struct iwl_priv *priv) | ||
622 | { | ||
623 | priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ) | | ||
624 | BIT(IEEE80211_BAND_5GHZ); | ||
625 | |||
626 | priv->hw_params.tx_chains_num = | ||
627 | num_of_ant(priv->hw_params.valid_tx_ant); | ||
628 | if (priv->cfg->rx_with_siso_diversity) | ||
629 | priv->hw_params.rx_chains_num = 1; | ||
630 | else | ||
631 | priv->hw_params.rx_chains_num = | ||
632 | num_of_ant(priv->hw_params.valid_rx_ant); | ||
633 | |||
634 | iwl6000_set_ct_threshold(priv); | ||
635 | |||
636 | /* Set initial sensitivity parameters */ | ||
637 | priv->hw_params.sens = &iwl6000_sensitivity; | ||
638 | |||
639 | } | ||
640 | |||
641 | static int iwl6000_hw_channel_switch(struct iwl_priv *priv, | ||
642 | struct ieee80211_channel_switch *ch_switch) | ||
643 | { | ||
644 | /* | ||
645 | * MULTI-FIXME | ||
646 | * See iwlagn_mac_channel_switch. | ||
647 | */ | ||
648 | struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; | ||
649 | struct iwl6000_channel_switch_cmd cmd; | ||
650 | u32 switch_time_in_usec, ucode_switch_time; | ||
651 | u16 ch; | ||
652 | u32 tsf_low; | ||
653 | u8 switch_count; | ||
654 | u16 beacon_interval = le16_to_cpu(ctx->timing.beacon_interval); | ||
655 | struct ieee80211_vif *vif = ctx->vif; | ||
656 | struct iwl_host_cmd hcmd = { | ||
657 | .id = REPLY_CHANNEL_SWITCH, | ||
658 | .len = { sizeof(cmd), }, | ||
659 | .flags = CMD_SYNC, | ||
660 | .data = { &cmd, }, | ||
661 | }; | ||
662 | |||
663 | cmd.band = priv->band == IEEE80211_BAND_2GHZ; | ||
664 | ch = ch_switch->channel->hw_value; | ||
665 | IWL_DEBUG_11H(priv, "channel switch from %u to %u\n", | ||
666 | ctx->active.channel, ch); | ||
667 | cmd.channel = cpu_to_le16(ch); | ||
668 | cmd.rxon_flags = ctx->staging.flags; | ||
669 | cmd.rxon_filter_flags = ctx->staging.filter_flags; | ||
670 | switch_count = ch_switch->count; | ||
671 | tsf_low = ch_switch->timestamp & 0x0ffffffff; | ||
672 | /* | ||
673 | * calculate the ucode channel switch time | ||
674 | * adding TSF as one of the factor for when to switch | ||
675 | */ | ||
676 | if ((priv->ucode_beacon_time > tsf_low) && beacon_interval) { | ||
677 | if (switch_count > ((priv->ucode_beacon_time - tsf_low) / | ||
678 | beacon_interval)) { | ||
679 | switch_count -= (priv->ucode_beacon_time - | ||
680 | tsf_low) / beacon_interval; | ||
681 | } else | ||
682 | switch_count = 0; | ||
683 | } | ||
684 | if (switch_count <= 1) | ||
685 | cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time); | ||
686 | else { | ||
687 | switch_time_in_usec = | ||
688 | vif->bss_conf.beacon_int * switch_count * TIME_UNIT; | ||
689 | ucode_switch_time = iwl_usecs_to_beacons(priv, | ||
690 | switch_time_in_usec, | ||
691 | beacon_interval); | ||
692 | cmd.switch_time = iwl_add_beacon_time(priv, | ||
693 | priv->ucode_beacon_time, | ||
694 | ucode_switch_time, | ||
695 | beacon_interval); | ||
696 | } | ||
697 | IWL_DEBUG_11H(priv, "uCode time for the switch is 0x%x\n", | ||
698 | cmd.switch_time); | ||
699 | cmd.expect_beacon = ch_switch->channel->flags & IEEE80211_CHAN_RADAR; | ||
700 | |||
701 | return iwl_dvm_send_cmd(priv, &hcmd); | ||
702 | } | ||
703 | |||
704 | struct iwl_lib_ops iwl6000_lib = { | ||
705 | .set_hw_params = iwl6000_hw_set_hw_params, | ||
706 | .set_channel_switch = iwl6000_hw_channel_switch, | ||
707 | .nic_config = iwl6000_nic_config, | ||
708 | .eeprom_ops = { | ||
709 | .regulatory_bands = { | ||
710 | EEPROM_REG_BAND_1_CHANNELS, | ||
711 | EEPROM_REG_BAND_2_CHANNELS, | ||
712 | EEPROM_REG_BAND_3_CHANNELS, | ||
713 | EEPROM_REG_BAND_4_CHANNELS, | ||
714 | EEPROM_REG_BAND_5_CHANNELS, | ||
715 | EEPROM_6000_REG_BAND_24_HT40_CHANNELS, | ||
716 | EEPROM_REG_BAND_52_HT40_CHANNELS | ||
717 | }, | ||
718 | .enhanced_txpower = true, | ||
719 | }, | ||
720 | .temperature = iwlagn_temperature, | ||
721 | }; | ||
722 | |||
723 | struct iwl_lib_ops iwl6030_lib = { | ||
724 | .set_hw_params = iwl6000_hw_set_hw_params, | ||
725 | .set_channel_switch = iwl6000_hw_channel_switch, | ||
726 | .nic_config = iwl6000_nic_config, | ||
727 | .eeprom_ops = { | ||
728 | .regulatory_bands = { | ||
729 | EEPROM_REG_BAND_1_CHANNELS, | ||
730 | EEPROM_REG_BAND_2_CHANNELS, | ||
731 | EEPROM_REG_BAND_3_CHANNELS, | ||
732 | EEPROM_REG_BAND_4_CHANNELS, | ||
733 | EEPROM_REG_BAND_5_CHANNELS, | ||
734 | EEPROM_6000_REG_BAND_24_HT40_CHANNELS, | ||
735 | EEPROM_REG_BAND_52_HT40_CHANNELS | ||
736 | }, | ||
737 | .enhanced_txpower = true, | ||
738 | }, | ||
739 | .temperature = iwlagn_temperature, | ||
740 | }; | ||