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