diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/dvm/devices.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/dvm/devices.c | 601 |
1 files changed, 601 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..0521a6be09d2 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/dvm/devices.c | |||
@@ -0,0 +1,601 @@ | |||
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 | #include "iwl-eeprom-parse.h" | ||
33 | |||
34 | #include "agn.h" | ||
35 | #include "dev.h" | ||
36 | #include "commands.h" | ||
37 | |||
38 | |||
39 | /* | ||
40 | * 1000 series | ||
41 | * =========== | ||
42 | */ | ||
43 | |||
44 | /* | ||
45 | * For 1000, use advance thermal throttling critical temperature threshold, | ||
46 | * but legacy thermal management implementation for now. | ||
47 | * This is for the reason of 1000 uCode using advance thermal throttling API | ||
48 | * but not implement ct_kill_exit based on ct_kill exit temperature | ||
49 | * so the thermal throttling will still based on legacy thermal throttling | ||
50 | * management. | ||
51 | * The code here need to be modified once 1000 uCode has the advanced thermal | ||
52 | * throttling algorithm in place | ||
53 | */ | ||
54 | static void iwl1000_set_ct_threshold(struct iwl_priv *priv) | ||
55 | { | ||
56 | /* want Celsius */ | ||
57 | priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD_LEGACY; | ||
58 | priv->hw_params.ct_kill_exit_threshold = CT_KILL_EXIT_THRESHOLD; | ||
59 | } | ||
60 | |||
61 | /* NIC configuration for 1000 series */ | ||
62 | static void iwl1000_nic_config(struct iwl_priv *priv) | ||
63 | { | ||
64 | /* Setting digital SVR for 1000 card to 1.32V */ | ||
65 | /* locking is acquired in iwl_set_bits_mask_prph() function */ | ||
66 | iwl_set_bits_mask_prph(priv->trans, APMG_DIGITAL_SVR_REG, | ||
67 | APMG_SVR_DIGITAL_VOLTAGE_1_32, | ||
68 | ~APMG_SVR_VOLTAGE_CONFIG_BIT_MSK); | ||
69 | } | ||
70 | |||
71 | /** | ||
72 | * iwl_beacon_time_mask_low - mask of lower 32 bit of beacon time | ||
73 | * @priv -- pointer to iwl_priv data structure | ||
74 | * @tsf_bits -- number of bits need to shift for masking) | ||
75 | */ | ||
76 | static inline u32 iwl_beacon_time_mask_low(struct iwl_priv *priv, | ||
77 | u16 tsf_bits) | ||
78 | { | ||
79 | return (1 << tsf_bits) - 1; | ||
80 | } | ||
81 | |||
82 | /** | ||
83 | * iwl_beacon_time_mask_high - mask of higher 32 bit of beacon time | ||
84 | * @priv -- pointer to iwl_priv data structure | ||
85 | * @tsf_bits -- number of bits need to shift for masking) | ||
86 | */ | ||
87 | static inline u32 iwl_beacon_time_mask_high(struct iwl_priv *priv, | ||
88 | u16 tsf_bits) | ||
89 | { | ||
90 | return ((1 << (32 - tsf_bits)) - 1) << tsf_bits; | ||
91 | } | ||
92 | |||
93 | /* | ||
94 | * extended beacon time format | ||
95 | * time in usec will be changed into a 32-bit value in extended:internal format | ||
96 | * the extended part is the beacon counts | ||
97 | * the internal part is the time in usec within one beacon interval | ||
98 | */ | ||
99 | static u32 iwl_usecs_to_beacons(struct iwl_priv *priv, u32 usec, | ||
100 | u32 beacon_interval) | ||
101 | { | ||
102 | u32 quot; | ||
103 | u32 rem; | ||
104 | u32 interval = beacon_interval * TIME_UNIT; | ||
105 | |||
106 | if (!interval || !usec) | ||
107 | return 0; | ||
108 | |||
109 | quot = (usec / interval) & | ||
110 | (iwl_beacon_time_mask_high(priv, IWLAGN_EXT_BEACON_TIME_POS) >> | ||
111 | IWLAGN_EXT_BEACON_TIME_POS); | ||
112 | rem = (usec % interval) & iwl_beacon_time_mask_low(priv, | ||
113 | IWLAGN_EXT_BEACON_TIME_POS); | ||
114 | |||
115 | return (quot << IWLAGN_EXT_BEACON_TIME_POS) + rem; | ||
116 | } | ||
117 | |||
118 | /* base is usually what we get from ucode with each received frame, | ||
119 | * the same as HW timer counter counting down | ||
120 | */ | ||
121 | static __le32 iwl_add_beacon_time(struct iwl_priv *priv, u32 base, | ||
122 | u32 addon, u32 beacon_interval) | ||
123 | { | ||
124 | u32 base_low = base & iwl_beacon_time_mask_low(priv, | ||
125 | IWLAGN_EXT_BEACON_TIME_POS); | ||
126 | u32 addon_low = addon & iwl_beacon_time_mask_low(priv, | ||
127 | IWLAGN_EXT_BEACON_TIME_POS); | ||
128 | u32 interval = beacon_interval * TIME_UNIT; | ||
129 | u32 res = (base & iwl_beacon_time_mask_high(priv, | ||
130 | IWLAGN_EXT_BEACON_TIME_POS)) + | ||
131 | (addon & iwl_beacon_time_mask_high(priv, | ||
132 | IWLAGN_EXT_BEACON_TIME_POS)); | ||
133 | |||
134 | if (base_low > addon_low) | ||
135 | res += base_low - addon_low; | ||
136 | else if (base_low < addon_low) { | ||
137 | res += interval + base_low - addon_low; | ||
138 | res += (1 << IWLAGN_EXT_BEACON_TIME_POS); | ||
139 | } else | ||
140 | res += (1 << IWLAGN_EXT_BEACON_TIME_POS); | ||
141 | |||
142 | return cpu_to_le32(res); | ||
143 | } | ||
144 | |||
145 | static const struct iwl_sensitivity_ranges iwl1000_sensitivity = { | ||
146 | .min_nrg_cck = 95, | ||
147 | .auto_corr_min_ofdm = 90, | ||
148 | .auto_corr_min_ofdm_mrc = 170, | ||
149 | .auto_corr_min_ofdm_x1 = 120, | ||
150 | .auto_corr_min_ofdm_mrc_x1 = 240, | ||
151 | |||
152 | .auto_corr_max_ofdm = 120, | ||
153 | .auto_corr_max_ofdm_mrc = 210, | ||
154 | .auto_corr_max_ofdm_x1 = 155, | ||
155 | .auto_corr_max_ofdm_mrc_x1 = 290, | ||
156 | |||
157 | .auto_corr_min_cck = 125, | ||
158 | .auto_corr_max_cck = 200, | ||
159 | .auto_corr_min_cck_mrc = 170, | ||
160 | .auto_corr_max_cck_mrc = 400, | ||
161 | .nrg_th_cck = 95, | ||
162 | .nrg_th_ofdm = 95, | ||
163 | |||
164 | .barker_corr_th_min = 190, | ||
165 | .barker_corr_th_min_mrc = 390, | ||
166 | .nrg_th_cca = 62, | ||
167 | }; | ||
168 | |||
169 | static void iwl1000_hw_set_hw_params(struct iwl_priv *priv) | ||
170 | { | ||
171 | iwl1000_set_ct_threshold(priv); | ||
172 | |||
173 | /* Set initial sensitivity parameters */ | ||
174 | priv->hw_params.sens = &iwl1000_sensitivity; | ||
175 | } | ||
176 | |||
177 | struct iwl_lib_ops iwl1000_lib = { | ||
178 | .set_hw_params = iwl1000_hw_set_hw_params, | ||
179 | .nic_config = iwl1000_nic_config, | ||
180 | .temperature = iwlagn_temperature, | ||
181 | }; | ||
182 | |||
183 | |||
184 | /* | ||
185 | * 2000 series | ||
186 | * =========== | ||
187 | */ | ||
188 | |||
189 | static void iwl2000_set_ct_threshold(struct iwl_priv *priv) | ||
190 | { | ||
191 | /* want Celsius */ | ||
192 | priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD; | ||
193 | priv->hw_params.ct_kill_exit_threshold = CT_KILL_EXIT_THRESHOLD; | ||
194 | } | ||
195 | |||
196 | /* NIC configuration for 2000 series */ | ||
197 | static void iwl2000_nic_config(struct iwl_priv *priv) | ||
198 | { | ||
199 | iwl_set_bit(priv->trans, CSR_GP_DRIVER_REG, | ||
200 | CSR_GP_DRIVER_REG_BIT_RADIO_IQ_INVER); | ||
201 | } | ||
202 | |||
203 | static const struct iwl_sensitivity_ranges iwl2000_sensitivity = { | ||
204 | .min_nrg_cck = 97, | ||
205 | .auto_corr_min_ofdm = 80, | ||
206 | .auto_corr_min_ofdm_mrc = 128, | ||
207 | .auto_corr_min_ofdm_x1 = 105, | ||
208 | .auto_corr_min_ofdm_mrc_x1 = 192, | ||
209 | |||
210 | .auto_corr_max_ofdm = 145, | ||
211 | .auto_corr_max_ofdm_mrc = 232, | ||
212 | .auto_corr_max_ofdm_x1 = 110, | ||
213 | .auto_corr_max_ofdm_mrc_x1 = 232, | ||
214 | |||
215 | .auto_corr_min_cck = 125, | ||
216 | .auto_corr_max_cck = 175, | ||
217 | .auto_corr_min_cck_mrc = 160, | ||
218 | .auto_corr_max_cck_mrc = 310, | ||
219 | .nrg_th_cck = 97, | ||
220 | .nrg_th_ofdm = 100, | ||
221 | |||
222 | .barker_corr_th_min = 190, | ||
223 | .barker_corr_th_min_mrc = 390, | ||
224 | .nrg_th_cca = 62, | ||
225 | }; | ||
226 | |||
227 | static void iwl2000_hw_set_hw_params(struct iwl_priv *priv) | ||
228 | { | ||
229 | iwl2000_set_ct_threshold(priv); | ||
230 | |||
231 | /* Set initial sensitivity parameters */ | ||
232 | priv->hw_params.sens = &iwl2000_sensitivity; | ||
233 | } | ||
234 | |||
235 | struct iwl_lib_ops iwl2000_lib = { | ||
236 | .set_hw_params = iwl2000_hw_set_hw_params, | ||
237 | .nic_config = iwl2000_nic_config, | ||
238 | .temperature = iwlagn_temperature, | ||
239 | }; | ||
240 | |||
241 | struct iwl_lib_ops iwl2030_lib = { | ||
242 | .set_hw_params = iwl2000_hw_set_hw_params, | ||
243 | .nic_config = iwl2000_nic_config, | ||
244 | .temperature = iwlagn_temperature, | ||
245 | }; | ||
246 | |||
247 | /* | ||
248 | * 5000 series | ||
249 | * =========== | ||
250 | */ | ||
251 | |||
252 | /* NIC configuration for 5000 series */ | ||
253 | static void iwl5000_nic_config(struct iwl_priv *priv) | ||
254 | { | ||
255 | /* W/A : NIC is stuck in a reset state after Early PCIe power off | ||
256 | * (PCIe power is lost before PERST# is asserted), | ||
257 | * causing ME FW to lose ownership and not being able to obtain it back. | ||
258 | */ | ||
259 | iwl_set_bits_mask_prph(priv->trans, APMG_PS_CTRL_REG, | ||
260 | APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS, | ||
261 | ~APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS); | ||
262 | } | ||
263 | |||
264 | static const struct iwl_sensitivity_ranges iwl5000_sensitivity = { | ||
265 | .min_nrg_cck = 100, | ||
266 | .auto_corr_min_ofdm = 90, | ||
267 | .auto_corr_min_ofdm_mrc = 170, | ||
268 | .auto_corr_min_ofdm_x1 = 105, | ||
269 | .auto_corr_min_ofdm_mrc_x1 = 220, | ||
270 | |||
271 | .auto_corr_max_ofdm = 120, | ||
272 | .auto_corr_max_ofdm_mrc = 210, | ||
273 | .auto_corr_max_ofdm_x1 = 120, | ||
274 | .auto_corr_max_ofdm_mrc_x1 = 240, | ||
275 | |||
276 | .auto_corr_min_cck = 125, | ||
277 | .auto_corr_max_cck = 200, | ||
278 | .auto_corr_min_cck_mrc = 200, | ||
279 | .auto_corr_max_cck_mrc = 400, | ||
280 | .nrg_th_cck = 100, | ||
281 | .nrg_th_ofdm = 100, | ||
282 | |||
283 | .barker_corr_th_min = 190, | ||
284 | .barker_corr_th_min_mrc = 390, | ||
285 | .nrg_th_cca = 62, | ||
286 | }; | ||
287 | |||
288 | static struct iwl_sensitivity_ranges iwl5150_sensitivity = { | ||
289 | .min_nrg_cck = 95, | ||
290 | .auto_corr_min_ofdm = 90, | ||
291 | .auto_corr_min_ofdm_mrc = 170, | ||
292 | .auto_corr_min_ofdm_x1 = 105, | ||
293 | .auto_corr_min_ofdm_mrc_x1 = 220, | ||
294 | |||
295 | .auto_corr_max_ofdm = 120, | ||
296 | .auto_corr_max_ofdm_mrc = 210, | ||
297 | /* max = min for performance bug in 5150 DSP */ | ||
298 | .auto_corr_max_ofdm_x1 = 105, | ||
299 | .auto_corr_max_ofdm_mrc_x1 = 220, | ||
300 | |||
301 | .auto_corr_min_cck = 125, | ||
302 | .auto_corr_max_cck = 200, | ||
303 | .auto_corr_min_cck_mrc = 170, | ||
304 | .auto_corr_max_cck_mrc = 400, | ||
305 | .nrg_th_cck = 95, | ||
306 | .nrg_th_ofdm = 95, | ||
307 | |||
308 | .barker_corr_th_min = 190, | ||
309 | .barker_corr_th_min_mrc = 390, | ||
310 | .nrg_th_cca = 62, | ||
311 | }; | ||
312 | |||
313 | #define IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF (-5) | ||
314 | |||
315 | static s32 iwl_temp_calib_to_offset(struct iwl_priv *priv) | ||
316 | { | ||
317 | u16 temperature, voltage; | ||
318 | |||
319 | temperature = le16_to_cpu(priv->eeprom_data->kelvin_temperature); | ||
320 | voltage = le16_to_cpu(priv->eeprom_data->kelvin_voltage); | ||
321 | |||
322 | /* offset = temp - volt / coeff */ | ||
323 | return (s32)(temperature - | ||
324 | voltage / IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF); | ||
325 | } | ||
326 | |||
327 | static void iwl5150_set_ct_threshold(struct iwl_priv *priv) | ||
328 | { | ||
329 | const s32 volt2temp_coef = IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF; | ||
330 | s32 threshold = (s32)CELSIUS_TO_KELVIN(CT_KILL_THRESHOLD_LEGACY) - | ||
331 | iwl_temp_calib_to_offset(priv); | ||
332 | |||
333 | priv->hw_params.ct_kill_threshold = threshold * volt2temp_coef; | ||
334 | } | ||
335 | |||
336 | static void iwl5000_set_ct_threshold(struct iwl_priv *priv) | ||
337 | { | ||
338 | /* want Celsius */ | ||
339 | priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD_LEGACY; | ||
340 | } | ||
341 | |||
342 | static void iwl5000_hw_set_hw_params(struct iwl_priv *priv) | ||
343 | { | ||
344 | iwl5000_set_ct_threshold(priv); | ||
345 | |||
346 | /* Set initial sensitivity parameters */ | ||
347 | priv->hw_params.sens = &iwl5000_sensitivity; | ||
348 | } | ||
349 | |||
350 | static void iwl5150_hw_set_hw_params(struct iwl_priv *priv) | ||
351 | { | ||
352 | iwl5150_set_ct_threshold(priv); | ||
353 | |||
354 | /* Set initial sensitivity parameters */ | ||
355 | priv->hw_params.sens = &iwl5150_sensitivity; | ||
356 | } | ||
357 | |||
358 | static void iwl5150_temperature(struct iwl_priv *priv) | ||
359 | { | ||
360 | u32 vt = 0; | ||
361 | s32 offset = iwl_temp_calib_to_offset(priv); | ||
362 | |||
363 | vt = le32_to_cpu(priv->statistics.common.temperature); | ||
364 | vt = vt / IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF + offset; | ||
365 | /* now vt hold the temperature in Kelvin */ | ||
366 | priv->temperature = KELVIN_TO_CELSIUS(vt); | ||
367 | iwl_tt_handler(priv); | ||
368 | } | ||
369 | |||
370 | static int iwl5000_hw_channel_switch(struct iwl_priv *priv, | ||
371 | struct ieee80211_channel_switch *ch_switch) | ||
372 | { | ||
373 | /* | ||
374 | * MULTI-FIXME | ||
375 | * See iwlagn_mac_channel_switch. | ||
376 | */ | ||
377 | struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; | ||
378 | struct iwl5000_channel_switch_cmd cmd; | ||
379 | u32 switch_time_in_usec, ucode_switch_time; | ||
380 | u16 ch; | ||
381 | u32 tsf_low; | ||
382 | u8 switch_count; | ||
383 | u16 beacon_interval = le16_to_cpu(ctx->timing.beacon_interval); | ||
384 | struct ieee80211_vif *vif = ctx->vif; | ||
385 | struct iwl_host_cmd hcmd = { | ||
386 | .id = REPLY_CHANNEL_SWITCH, | ||
387 | .len = { sizeof(cmd), }, | ||
388 | .flags = CMD_SYNC, | ||
389 | .data = { &cmd, }, | ||
390 | }; | ||
391 | |||
392 | cmd.band = priv->band == IEEE80211_BAND_2GHZ; | ||
393 | ch = ch_switch->channel->hw_value; | ||
394 | IWL_DEBUG_11H(priv, "channel switch from %d to %d\n", | ||
395 | ctx->active.channel, ch); | ||
396 | cmd.channel = cpu_to_le16(ch); | ||
397 | cmd.rxon_flags = ctx->staging.flags; | ||
398 | cmd.rxon_filter_flags = ctx->staging.filter_flags; | ||
399 | switch_count = ch_switch->count; | ||
400 | tsf_low = ch_switch->timestamp & 0x0ffffffff; | ||
401 | /* | ||
402 | * calculate the ucode channel switch time | ||
403 | * adding TSF as one of the factor for when to switch | ||
404 | */ | ||
405 | if ((priv->ucode_beacon_time > tsf_low) && beacon_interval) { | ||
406 | if (switch_count > ((priv->ucode_beacon_time - tsf_low) / | ||
407 | beacon_interval)) { | ||
408 | switch_count -= (priv->ucode_beacon_time - | ||
409 | tsf_low) / beacon_interval; | ||
410 | } else | ||
411 | switch_count = 0; | ||
412 | } | ||
413 | if (switch_count <= 1) | ||
414 | cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time); | ||
415 | else { | ||
416 | switch_time_in_usec = | ||
417 | vif->bss_conf.beacon_int * switch_count * TIME_UNIT; | ||
418 | ucode_switch_time = iwl_usecs_to_beacons(priv, | ||
419 | switch_time_in_usec, | ||
420 | beacon_interval); | ||
421 | cmd.switch_time = iwl_add_beacon_time(priv, | ||
422 | priv->ucode_beacon_time, | ||
423 | ucode_switch_time, | ||
424 | beacon_interval); | ||
425 | } | ||
426 | IWL_DEBUG_11H(priv, "uCode time for the switch is 0x%x\n", | ||
427 | cmd.switch_time); | ||
428 | cmd.expect_beacon = ch_switch->channel->flags & IEEE80211_CHAN_RADAR; | ||
429 | |||
430 | return iwl_dvm_send_cmd(priv, &hcmd); | ||
431 | } | ||
432 | |||
433 | struct iwl_lib_ops iwl5000_lib = { | ||
434 | .set_hw_params = iwl5000_hw_set_hw_params, | ||
435 | .set_channel_switch = iwl5000_hw_channel_switch, | ||
436 | .nic_config = iwl5000_nic_config, | ||
437 | .temperature = iwlagn_temperature, | ||
438 | }; | ||
439 | |||
440 | struct iwl_lib_ops iwl5150_lib = { | ||
441 | .set_hw_params = iwl5150_hw_set_hw_params, | ||
442 | .set_channel_switch = iwl5000_hw_channel_switch, | ||
443 | .nic_config = iwl5000_nic_config, | ||
444 | .temperature = iwl5150_temperature, | ||
445 | }; | ||
446 | |||
447 | |||
448 | |||
449 | /* | ||
450 | * 6000 series | ||
451 | * =========== | ||
452 | */ | ||
453 | |||
454 | static void iwl6000_set_ct_threshold(struct iwl_priv *priv) | ||
455 | { | ||
456 | /* want Celsius */ | ||
457 | priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD; | ||
458 | priv->hw_params.ct_kill_exit_threshold = CT_KILL_EXIT_THRESHOLD; | ||
459 | } | ||
460 | |||
461 | /* NIC configuration for 6000 series */ | ||
462 | static void iwl6000_nic_config(struct iwl_priv *priv) | ||
463 | { | ||
464 | switch (priv->cfg->device_family) { | ||
465 | case IWL_DEVICE_FAMILY_6005: | ||
466 | case IWL_DEVICE_FAMILY_6030: | ||
467 | case IWL_DEVICE_FAMILY_6000: | ||
468 | break; | ||
469 | case IWL_DEVICE_FAMILY_6000i: | ||
470 | /* 2x2 IPA phy type */ | ||
471 | iwl_write32(priv->trans, CSR_GP_DRIVER_REG, | ||
472 | CSR_GP_DRIVER_REG_BIT_RADIO_SKU_2x2_IPA); | ||
473 | break; | ||
474 | case IWL_DEVICE_FAMILY_6050: | ||
475 | /* Indicate calibration version to uCode. */ | ||
476 | if (priv->eeprom_data->calib_version >= 6) | ||
477 | iwl_set_bit(priv->trans, CSR_GP_DRIVER_REG, | ||
478 | CSR_GP_DRIVER_REG_BIT_CALIB_VERSION6); | ||
479 | break; | ||
480 | case IWL_DEVICE_FAMILY_6150: | ||
481 | /* Indicate calibration version to uCode. */ | ||
482 | if (priv->eeprom_data->calib_version >= 6) | ||
483 | iwl_set_bit(priv->trans, CSR_GP_DRIVER_REG, | ||
484 | CSR_GP_DRIVER_REG_BIT_CALIB_VERSION6); | ||
485 | iwl_set_bit(priv->trans, CSR_GP_DRIVER_REG, | ||
486 | CSR_GP_DRIVER_REG_BIT_6050_1x2); | ||
487 | break; | ||
488 | default: | ||
489 | WARN_ON(1); | ||
490 | } | ||
491 | } | ||
492 | |||
493 | static const struct iwl_sensitivity_ranges iwl6000_sensitivity = { | ||
494 | .min_nrg_cck = 110, | ||
495 | .auto_corr_min_ofdm = 80, | ||
496 | .auto_corr_min_ofdm_mrc = 128, | ||
497 | .auto_corr_min_ofdm_x1 = 105, | ||
498 | .auto_corr_min_ofdm_mrc_x1 = 192, | ||
499 | |||
500 | .auto_corr_max_ofdm = 145, | ||
501 | .auto_corr_max_ofdm_mrc = 232, | ||
502 | .auto_corr_max_ofdm_x1 = 110, | ||
503 | .auto_corr_max_ofdm_mrc_x1 = 232, | ||
504 | |||
505 | .auto_corr_min_cck = 125, | ||
506 | .auto_corr_max_cck = 175, | ||
507 | .auto_corr_min_cck_mrc = 160, | ||
508 | .auto_corr_max_cck_mrc = 310, | ||
509 | .nrg_th_cck = 110, | ||
510 | .nrg_th_ofdm = 110, | ||
511 | |||
512 | .barker_corr_th_min = 190, | ||
513 | .barker_corr_th_min_mrc = 336, | ||
514 | .nrg_th_cca = 62, | ||
515 | }; | ||
516 | |||
517 | static void iwl6000_hw_set_hw_params(struct iwl_priv *priv) | ||
518 | { | ||
519 | iwl6000_set_ct_threshold(priv); | ||
520 | |||
521 | /* Set initial sensitivity parameters */ | ||
522 | priv->hw_params.sens = &iwl6000_sensitivity; | ||
523 | |||
524 | } | ||
525 | |||
526 | static int iwl6000_hw_channel_switch(struct iwl_priv *priv, | ||
527 | struct ieee80211_channel_switch *ch_switch) | ||
528 | { | ||
529 | /* | ||
530 | * MULTI-FIXME | ||
531 | * See iwlagn_mac_channel_switch. | ||
532 | */ | ||
533 | struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; | ||
534 | struct iwl6000_channel_switch_cmd cmd; | ||
535 | u32 switch_time_in_usec, ucode_switch_time; | ||
536 | u16 ch; | ||
537 | u32 tsf_low; | ||
538 | u8 switch_count; | ||
539 | u16 beacon_interval = le16_to_cpu(ctx->timing.beacon_interval); | ||
540 | struct ieee80211_vif *vif = ctx->vif; | ||
541 | struct iwl_host_cmd hcmd = { | ||
542 | .id = REPLY_CHANNEL_SWITCH, | ||
543 | .len = { sizeof(cmd), }, | ||
544 | .flags = CMD_SYNC, | ||
545 | .data = { &cmd, }, | ||
546 | }; | ||
547 | |||
548 | cmd.band = priv->band == IEEE80211_BAND_2GHZ; | ||
549 | ch = ch_switch->channel->hw_value; | ||
550 | IWL_DEBUG_11H(priv, "channel switch from %u to %u\n", | ||
551 | ctx->active.channel, ch); | ||
552 | cmd.channel = cpu_to_le16(ch); | ||
553 | cmd.rxon_flags = ctx->staging.flags; | ||
554 | cmd.rxon_filter_flags = ctx->staging.filter_flags; | ||
555 | switch_count = ch_switch->count; | ||
556 | tsf_low = ch_switch->timestamp & 0x0ffffffff; | ||
557 | /* | ||
558 | * calculate the ucode channel switch time | ||
559 | * adding TSF as one of the factor for when to switch | ||
560 | */ | ||
561 | if ((priv->ucode_beacon_time > tsf_low) && beacon_interval) { | ||
562 | if (switch_count > ((priv->ucode_beacon_time - tsf_low) / | ||
563 | beacon_interval)) { | ||
564 | switch_count -= (priv->ucode_beacon_time - | ||
565 | tsf_low) / beacon_interval; | ||
566 | } else | ||
567 | switch_count = 0; | ||
568 | } | ||
569 | if (switch_count <= 1) | ||
570 | cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time); | ||
571 | else { | ||
572 | switch_time_in_usec = | ||
573 | vif->bss_conf.beacon_int * switch_count * TIME_UNIT; | ||
574 | ucode_switch_time = iwl_usecs_to_beacons(priv, | ||
575 | switch_time_in_usec, | ||
576 | beacon_interval); | ||
577 | cmd.switch_time = iwl_add_beacon_time(priv, | ||
578 | priv->ucode_beacon_time, | ||
579 | ucode_switch_time, | ||
580 | beacon_interval); | ||
581 | } | ||
582 | IWL_DEBUG_11H(priv, "uCode time for the switch is 0x%x\n", | ||
583 | cmd.switch_time); | ||
584 | cmd.expect_beacon = ch_switch->channel->flags & IEEE80211_CHAN_RADAR; | ||
585 | |||
586 | return iwl_dvm_send_cmd(priv, &hcmd); | ||
587 | } | ||
588 | |||
589 | struct iwl_lib_ops iwl6000_lib = { | ||
590 | .set_hw_params = iwl6000_hw_set_hw_params, | ||
591 | .set_channel_switch = iwl6000_hw_channel_switch, | ||
592 | .nic_config = iwl6000_nic_config, | ||
593 | .temperature = iwlagn_temperature, | ||
594 | }; | ||
595 | |||
596 | struct iwl_lib_ops iwl6030_lib = { | ||
597 | .set_hw_params = iwl6000_hw_set_hw_params, | ||
598 | .set_channel_switch = iwl6000_hw_channel_switch, | ||
599 | .nic_config = iwl6000_nic_config, | ||
600 | .temperature = iwlagn_temperature, | ||
601 | }; | ||