iwlwifi: dynamically determine lib_ops
[pandora-kernel.git] / drivers / net / wireless / iwlwifi / iwl-agn-devices.c
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-core.h"
31 #include "iwl-agn.h"
32 #include "iwl-dev.h"
33 #include "iwl-commands.h"
34 #include "iwl-io.h"
35 #include "iwl-prph.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(trans(priv), 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(trans(priv), APMG_DIGITAL_SVR_REG,
70                                 APMG_SVR_DIGITAL_VOLTAGE_1_32,
71                                 ~APMG_SVR_VOLTAGE_CONFIG_BIT_MSK);
72 }
73
74 static const struct iwl_sensitivity_ranges iwl1000_sensitivity = {
75         .min_nrg_cck = 95,
76         .auto_corr_min_ofdm = 90,
77         .auto_corr_min_ofdm_mrc = 170,
78         .auto_corr_min_ofdm_x1 = 120,
79         .auto_corr_min_ofdm_mrc_x1 = 240,
80
81         .auto_corr_max_ofdm = 120,
82         .auto_corr_max_ofdm_mrc = 210,
83         .auto_corr_max_ofdm_x1 = 155,
84         .auto_corr_max_ofdm_mrc_x1 = 290,
85
86         .auto_corr_min_cck = 125,
87         .auto_corr_max_cck = 200,
88         .auto_corr_min_cck_mrc = 170,
89         .auto_corr_max_cck_mrc = 400,
90         .nrg_th_cck = 95,
91         .nrg_th_ofdm = 95,
92
93         .barker_corr_th_min = 190,
94         .barker_corr_th_min_mrc = 390,
95         .nrg_th_cca = 62,
96 };
97
98 static void iwl1000_hw_set_hw_params(struct iwl_priv *priv)
99 {
100         priv->hw_params.ht40_channel =  BIT(IEEE80211_BAND_2GHZ);
101
102         priv->hw_params.tx_chains_num =
103                 num_of_ant(priv->hw_params.valid_tx_ant);
104         if (cfg(priv)->rx_with_siso_diversity)
105                 priv->hw_params.rx_chains_num = 1;
106         else
107                 priv->hw_params.rx_chains_num =
108                         num_of_ant(priv->hw_params.valid_rx_ant);
109
110         iwl1000_set_ct_threshold(priv);
111
112         /* Set initial sensitivity parameters */
113         priv->hw_params.sens = &iwl1000_sensitivity;
114 }
115
116 struct iwl_lib_ops iwl1000_lib = {
117         .set_hw_params = iwl1000_hw_set_hw_params,
118         .nic_config = iwl1000_nic_config,
119         .eeprom_ops = {
120                 .regulatory_bands = {
121                         EEPROM_REG_BAND_1_CHANNELS,
122                         EEPROM_REG_BAND_2_CHANNELS,
123                         EEPROM_REG_BAND_3_CHANNELS,
124                         EEPROM_REG_BAND_4_CHANNELS,
125                         EEPROM_REG_BAND_5_CHANNELS,
126                         EEPROM_REG_BAND_24_HT40_CHANNELS,
127                         EEPROM_REGULATORY_BAND_NO_HT40,
128                 },
129         },
130         .temperature = iwlagn_temperature,
131 };
132
133
134 /*
135  * 2000 series
136  * ===========
137  */
138
139 static void iwl2000_set_ct_threshold(struct iwl_priv *priv)
140 {
141         /* want Celsius */
142         priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD;
143         priv->hw_params.ct_kill_exit_threshold = CT_KILL_EXIT_THRESHOLD;
144 }
145
146 /* NIC configuration for 2000 series */
147 static void iwl2000_nic_config(struct iwl_priv *priv)
148 {
149         iwl_rf_config(priv);
150
151         iwl_set_bit(trans(priv), CSR_GP_DRIVER_REG,
152                     CSR_GP_DRIVER_REG_BIT_RADIO_IQ_INVER);
153 }
154
155 static const struct iwl_sensitivity_ranges iwl2000_sensitivity = {
156         .min_nrg_cck = 97,
157         .auto_corr_min_ofdm = 80,
158         .auto_corr_min_ofdm_mrc = 128,
159         .auto_corr_min_ofdm_x1 = 105,
160         .auto_corr_min_ofdm_mrc_x1 = 192,
161
162         .auto_corr_max_ofdm = 145,
163         .auto_corr_max_ofdm_mrc = 232,
164         .auto_corr_max_ofdm_x1 = 110,
165         .auto_corr_max_ofdm_mrc_x1 = 232,
166
167         .auto_corr_min_cck = 125,
168         .auto_corr_max_cck = 175,
169         .auto_corr_min_cck_mrc = 160,
170         .auto_corr_max_cck_mrc = 310,
171         .nrg_th_cck = 97,
172         .nrg_th_ofdm = 100,
173
174         .barker_corr_th_min = 190,
175         .barker_corr_th_min_mrc = 390,
176         .nrg_th_cca = 62,
177 };
178
179 static void iwl2000_hw_set_hw_params(struct iwl_priv *priv)
180 {
181         priv->hw_params.ht40_channel =  BIT(IEEE80211_BAND_2GHZ);
182
183         priv->hw_params.tx_chains_num =
184                 num_of_ant(priv->hw_params.valid_tx_ant);
185         if (cfg(priv)->rx_with_siso_diversity)
186                 priv->hw_params.rx_chains_num = 1;
187         else
188                 priv->hw_params.rx_chains_num =
189                         num_of_ant(priv->hw_params.valid_rx_ant);
190
191         iwl2000_set_ct_threshold(priv);
192
193         /* Set initial sensitivity parameters */
194         priv->hw_params.sens = &iwl2000_sensitivity;
195 }
196
197 struct iwl_lib_ops iwl2000_lib = {
198         .set_hw_params = iwl2000_hw_set_hw_params,
199         .nic_config = iwl2000_nic_config,
200         .eeprom_ops = {
201                 .regulatory_bands = {
202                         EEPROM_REG_BAND_1_CHANNELS,
203                         EEPROM_REG_BAND_2_CHANNELS,
204                         EEPROM_REG_BAND_3_CHANNELS,
205                         EEPROM_REG_BAND_4_CHANNELS,
206                         EEPROM_REG_BAND_5_CHANNELS,
207                         EEPROM_6000_REG_BAND_24_HT40_CHANNELS,
208                         EEPROM_REGULATORY_BAND_NO_HT40,
209                 },
210                 .enhanced_txpower = true,
211         },
212         .temperature = iwlagn_temperature,
213 };
214
215 struct iwl_lib_ops iwl2030_lib = {
216         .set_hw_params = iwl2000_hw_set_hw_params,
217         .nic_config = iwl2000_nic_config,
218         .eeprom_ops = {
219                 .regulatory_bands = {
220                         EEPROM_REG_BAND_1_CHANNELS,
221                         EEPROM_REG_BAND_2_CHANNELS,
222                         EEPROM_REG_BAND_3_CHANNELS,
223                         EEPROM_REG_BAND_4_CHANNELS,
224                         EEPROM_REG_BAND_5_CHANNELS,
225                         EEPROM_6000_REG_BAND_24_HT40_CHANNELS,
226                         EEPROM_REGULATORY_BAND_NO_HT40,
227                 },
228                 .enhanced_txpower = true,
229         },
230         .temperature = iwlagn_temperature,
231 };
232
233 /*
234  * 5000 series
235  * ===========
236  */
237
238 /* NIC configuration for 5000 series */
239 static void iwl5000_nic_config(struct iwl_priv *priv)
240 {
241         iwl_rf_config(priv);
242
243         /* W/A : NIC is stuck in a reset state after Early PCIe power off
244          * (PCIe power is lost before PERST# is asserted),
245          * causing ME FW to lose ownership and not being able to obtain it back.
246          */
247         iwl_set_bits_mask_prph(trans(priv), APMG_PS_CTRL_REG,
248                                 APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS,
249                                 ~APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS);
250 }
251
252 static const struct iwl_sensitivity_ranges iwl5000_sensitivity = {
253         .min_nrg_cck = 100,
254         .auto_corr_min_ofdm = 90,
255         .auto_corr_min_ofdm_mrc = 170,
256         .auto_corr_min_ofdm_x1 = 105,
257         .auto_corr_min_ofdm_mrc_x1 = 220,
258
259         .auto_corr_max_ofdm = 120,
260         .auto_corr_max_ofdm_mrc = 210,
261         .auto_corr_max_ofdm_x1 = 120,
262         .auto_corr_max_ofdm_mrc_x1 = 240,
263
264         .auto_corr_min_cck = 125,
265         .auto_corr_max_cck = 200,
266         .auto_corr_min_cck_mrc = 200,
267         .auto_corr_max_cck_mrc = 400,
268         .nrg_th_cck = 100,
269         .nrg_th_ofdm = 100,
270
271         .barker_corr_th_min = 190,
272         .barker_corr_th_min_mrc = 390,
273         .nrg_th_cca = 62,
274 };
275
276 static struct iwl_sensitivity_ranges iwl5150_sensitivity = {
277         .min_nrg_cck = 95,
278         .auto_corr_min_ofdm = 90,
279         .auto_corr_min_ofdm_mrc = 170,
280         .auto_corr_min_ofdm_x1 = 105,
281         .auto_corr_min_ofdm_mrc_x1 = 220,
282
283         .auto_corr_max_ofdm = 120,
284         .auto_corr_max_ofdm_mrc = 210,
285         /* max = min for performance bug in 5150 DSP */
286         .auto_corr_max_ofdm_x1 = 105,
287         .auto_corr_max_ofdm_mrc_x1 = 220,
288
289         .auto_corr_min_cck = 125,
290         .auto_corr_max_cck = 200,
291         .auto_corr_min_cck_mrc = 170,
292         .auto_corr_max_cck_mrc = 400,
293         .nrg_th_cck = 95,
294         .nrg_th_ofdm = 95,
295
296         .barker_corr_th_min = 190,
297         .barker_corr_th_min_mrc = 390,
298         .nrg_th_cca = 62,
299 };
300
301 #define IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF   (-5)
302
303 static s32 iwl_temp_calib_to_offset(struct iwl_priv *priv)
304 {
305         u16 temperature, voltage;
306         __le16 *temp_calib = (__le16 *)iwl_eeprom_query_addr(priv,
307                                 EEPROM_KELVIN_TEMPERATURE);
308
309         temperature = le16_to_cpu(temp_calib[0]);
310         voltage = le16_to_cpu(temp_calib[1]);
311
312         /* offset = temp - volt / coeff */
313         return (s32)(temperature -
314                         voltage / IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF);
315 }
316
317 static void iwl5150_set_ct_threshold(struct iwl_priv *priv)
318 {
319         const s32 volt2temp_coef = IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF;
320         s32 threshold = (s32)CELSIUS_TO_KELVIN(CT_KILL_THRESHOLD_LEGACY) -
321                         iwl_temp_calib_to_offset(priv);
322
323         priv->hw_params.ct_kill_threshold = threshold * volt2temp_coef;
324 }
325
326 static void iwl5000_set_ct_threshold(struct iwl_priv *priv)
327 {
328         /* want Celsius */
329         priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD_LEGACY;
330 }
331
332 static void iwl5000_hw_set_hw_params(struct iwl_priv *priv)
333 {
334         priv->hw_params.ht40_channel =  BIT(IEEE80211_BAND_2GHZ) |
335                                         BIT(IEEE80211_BAND_5GHZ);
336
337         priv->hw_params.tx_chains_num =
338                 num_of_ant(priv->hw_params.valid_tx_ant);
339         priv->hw_params.rx_chains_num =
340                 num_of_ant(priv->hw_params.valid_rx_ant);
341
342         iwl5000_set_ct_threshold(priv);
343
344         /* Set initial sensitivity parameters */
345         priv->hw_params.sens = &iwl5000_sensitivity;
346 }
347
348 static void iwl5150_hw_set_hw_params(struct iwl_priv *priv)
349 {
350         priv->hw_params.ht40_channel =  BIT(IEEE80211_BAND_2GHZ) |
351                                         BIT(IEEE80211_BAND_5GHZ);
352
353         priv->hw_params.tx_chains_num =
354                 num_of_ant(priv->hw_params.valid_tx_ant);
355         priv->hw_params.rx_chains_num =
356                 num_of_ant(priv->hw_params.valid_rx_ant);
357
358         iwl5150_set_ct_threshold(priv);
359
360         /* Set initial sensitivity parameters */
361         priv->hw_params.sens = &iwl5150_sensitivity;
362 }
363
364 static void iwl5150_temperature(struct iwl_priv *priv)
365 {
366         u32 vt = 0;
367         s32 offset =  iwl_temp_calib_to_offset(priv);
368
369         vt = le32_to_cpu(priv->statistics.common.temperature);
370         vt = vt / IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF + offset;
371         /* now vt hold the temperature in Kelvin */
372         priv->temperature = KELVIN_TO_CELSIUS(vt);
373         iwl_tt_handler(priv);
374 }
375
376 static int iwl5000_hw_channel_switch(struct iwl_priv *priv,
377                                      struct ieee80211_channel_switch *ch_switch)
378 {
379         /*
380          * MULTI-FIXME
381          * See iwlagn_mac_channel_switch.
382          */
383         struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
384         struct iwl5000_channel_switch_cmd cmd;
385         const struct iwl_channel_info *ch_info;
386         u32 switch_time_in_usec, ucode_switch_time;
387         u16 ch;
388         u32 tsf_low;
389         u8 switch_count;
390         u16 beacon_interval = le16_to_cpu(ctx->timing.beacon_interval);
391         struct ieee80211_vif *vif = ctx->vif;
392         struct iwl_host_cmd hcmd = {
393                 .id = REPLY_CHANNEL_SWITCH,
394                 .len = { sizeof(cmd), },
395                 .flags = CMD_SYNC,
396                 .data = { &cmd, },
397         };
398
399         cmd.band = priv->band == IEEE80211_BAND_2GHZ;
400         ch = ch_switch->channel->hw_value;
401         IWL_DEBUG_11H(priv, "channel switch from %d to %d\n",
402                       ctx->active.channel, ch);
403         cmd.channel = cpu_to_le16(ch);
404         cmd.rxon_flags = ctx->staging.flags;
405         cmd.rxon_filter_flags = ctx->staging.filter_flags;
406         switch_count = ch_switch->count;
407         tsf_low = ch_switch->timestamp & 0x0ffffffff;
408         /*
409          * calculate the ucode channel switch time
410          * adding TSF as one of the factor for when to switch
411          */
412         if ((priv->ucode_beacon_time > tsf_low) && beacon_interval) {
413                 if (switch_count > ((priv->ucode_beacon_time - tsf_low) /
414                     beacon_interval)) {
415                         switch_count -= (priv->ucode_beacon_time -
416                                 tsf_low) / beacon_interval;
417                 } else
418                         switch_count = 0;
419         }
420         if (switch_count <= 1)
421                 cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time);
422         else {
423                 switch_time_in_usec =
424                         vif->bss_conf.beacon_int * switch_count * TIME_UNIT;
425                 ucode_switch_time = iwl_usecs_to_beacons(priv,
426                                                          switch_time_in_usec,
427                                                          beacon_interval);
428                 cmd.switch_time = iwl_add_beacon_time(priv,
429                                                       priv->ucode_beacon_time,
430                                                       ucode_switch_time,
431                                                       beacon_interval);
432         }
433         IWL_DEBUG_11H(priv, "uCode time for the switch is 0x%x\n",
434                       cmd.switch_time);
435         ch_info = iwl_get_channel_info(priv, priv->band, ch);
436         if (ch_info)
437                 cmd.expect_beacon = is_channel_radar(ch_info);
438         else {
439                 IWL_ERR(priv, "invalid channel switch from %u to %u\n",
440                         ctx->active.channel, ch);
441                 return -EFAULT;
442         }
443
444         return iwl_dvm_send_cmd(priv, &hcmd);
445 }
446
447 struct iwl_lib_ops iwl5000_lib = {
448         .set_hw_params = iwl5000_hw_set_hw_params,
449         .set_channel_switch = iwl5000_hw_channel_switch,
450         .nic_config = iwl5000_nic_config,
451         .eeprom_ops = {
452                 .regulatory_bands = {
453                         EEPROM_REG_BAND_1_CHANNELS,
454                         EEPROM_REG_BAND_2_CHANNELS,
455                         EEPROM_REG_BAND_3_CHANNELS,
456                         EEPROM_REG_BAND_4_CHANNELS,
457                         EEPROM_REG_BAND_5_CHANNELS,
458                         EEPROM_REG_BAND_24_HT40_CHANNELS,
459                         EEPROM_REG_BAND_52_HT40_CHANNELS
460                 },
461         },
462         .temperature = iwlagn_temperature,
463 };
464
465 struct iwl_lib_ops iwl5150_lib = {
466         .set_hw_params = iwl5150_hw_set_hw_params,
467         .set_channel_switch = iwl5000_hw_channel_switch,
468         .nic_config = iwl5000_nic_config,
469         .eeprom_ops = {
470                 .regulatory_bands = {
471                         EEPROM_REG_BAND_1_CHANNELS,
472                         EEPROM_REG_BAND_2_CHANNELS,
473                         EEPROM_REG_BAND_3_CHANNELS,
474                         EEPROM_REG_BAND_4_CHANNELS,
475                         EEPROM_REG_BAND_5_CHANNELS,
476                         EEPROM_REG_BAND_24_HT40_CHANNELS,
477                         EEPROM_REG_BAND_52_HT40_CHANNELS
478                 },
479         },
480         .temperature = iwl5150_temperature,
481 };
482
483
484
485 /*
486  * 6000 series
487  * ===========
488  */
489
490 static void iwl6000_set_ct_threshold(struct iwl_priv *priv)
491 {
492         /* want Celsius */
493         priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD;
494         priv->hw_params.ct_kill_exit_threshold = CT_KILL_EXIT_THRESHOLD;
495 }
496
497 /* NIC configuration for 6000 series */
498 static void iwl6000_nic_config(struct iwl_priv *priv)
499 {
500         iwl_rf_config(priv);
501
502         switch (cfg(priv)->device_family) {
503         case IWL_DEVICE_FAMILY_6005:
504         case IWL_DEVICE_FAMILY_6030:
505         case IWL_DEVICE_FAMILY_6000:
506                 break;
507         case IWL_DEVICE_FAMILY_6000i:
508                 /* 2x2 IPA phy type */
509                 iwl_write32(trans(priv), CSR_GP_DRIVER_REG,
510                              CSR_GP_DRIVER_REG_BIT_RADIO_SKU_2x2_IPA);
511                 break;
512         case IWL_DEVICE_FAMILY_6050:
513                 /* Indicate calibration version to uCode. */
514                 if (iwl_eeprom_calib_version(priv) >= 6)
515                         iwl_set_bit(trans(priv), CSR_GP_DRIVER_REG,
516                                         CSR_GP_DRIVER_REG_BIT_CALIB_VERSION6);
517                 break;
518         case IWL_DEVICE_FAMILY_6150:
519                 /* Indicate calibration version to uCode. */
520                 if (iwl_eeprom_calib_version(priv) >= 6)
521                         iwl_set_bit(trans(priv), CSR_GP_DRIVER_REG,
522                                         CSR_GP_DRIVER_REG_BIT_CALIB_VERSION6);
523                 iwl_set_bit(trans(priv), CSR_GP_DRIVER_REG,
524                             CSR_GP_DRIVER_REG_BIT_6050_1x2);
525                 break;
526         default:
527                 WARN_ON(1);
528         }
529 }
530
531 static const struct iwl_sensitivity_ranges iwl6000_sensitivity = {
532         .min_nrg_cck = 110,
533         .auto_corr_min_ofdm = 80,
534         .auto_corr_min_ofdm_mrc = 128,
535         .auto_corr_min_ofdm_x1 = 105,
536         .auto_corr_min_ofdm_mrc_x1 = 192,
537
538         .auto_corr_max_ofdm = 145,
539         .auto_corr_max_ofdm_mrc = 232,
540         .auto_corr_max_ofdm_x1 = 110,
541         .auto_corr_max_ofdm_mrc_x1 = 232,
542
543         .auto_corr_min_cck = 125,
544         .auto_corr_max_cck = 175,
545         .auto_corr_min_cck_mrc = 160,
546         .auto_corr_max_cck_mrc = 310,
547         .nrg_th_cck = 110,
548         .nrg_th_ofdm = 110,
549
550         .barker_corr_th_min = 190,
551         .barker_corr_th_min_mrc = 336,
552         .nrg_th_cca = 62,
553 };
554
555 static void iwl6000_hw_set_hw_params(struct iwl_priv *priv)
556 {
557         priv->hw_params.ht40_channel =  BIT(IEEE80211_BAND_2GHZ) |
558                                         BIT(IEEE80211_BAND_5GHZ);
559
560         priv->hw_params.tx_chains_num =
561                 num_of_ant(priv->hw_params.valid_tx_ant);
562         if (cfg(priv)->rx_with_siso_diversity)
563                 priv->hw_params.rx_chains_num = 1;
564         else
565                 priv->hw_params.rx_chains_num =
566                         num_of_ant(priv->hw_params.valid_rx_ant);
567
568         iwl6000_set_ct_threshold(priv);
569
570         /* Set initial sensitivity parameters */
571         priv->hw_params.sens = &iwl6000_sensitivity;
572
573 }
574
575 static int iwl6000_hw_channel_switch(struct iwl_priv *priv,
576                                      struct ieee80211_channel_switch *ch_switch)
577 {
578         /*
579          * MULTI-FIXME
580          * See iwlagn_mac_channel_switch.
581          */
582         struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
583         struct iwl6000_channel_switch_cmd cmd;
584         const struct iwl_channel_info *ch_info;
585         u32 switch_time_in_usec, ucode_switch_time;
586         u16 ch;
587         u32 tsf_low;
588         u8 switch_count;
589         u16 beacon_interval = le16_to_cpu(ctx->timing.beacon_interval);
590         struct ieee80211_vif *vif = ctx->vif;
591         struct iwl_host_cmd hcmd = {
592                 .id = REPLY_CHANNEL_SWITCH,
593                 .len = { sizeof(cmd), },
594                 .flags = CMD_SYNC,
595                 .data = { &cmd, },
596         };
597
598         cmd.band = priv->band == IEEE80211_BAND_2GHZ;
599         ch = ch_switch->channel->hw_value;
600         IWL_DEBUG_11H(priv, "channel switch from %u to %u\n",
601                       ctx->active.channel, ch);
602         cmd.channel = cpu_to_le16(ch);
603         cmd.rxon_flags = ctx->staging.flags;
604         cmd.rxon_filter_flags = ctx->staging.filter_flags;
605         switch_count = ch_switch->count;
606         tsf_low = ch_switch->timestamp & 0x0ffffffff;
607         /*
608          * calculate the ucode channel switch time
609          * adding TSF as one of the factor for when to switch
610          */
611         if ((priv->ucode_beacon_time > tsf_low) && beacon_interval) {
612                 if (switch_count > ((priv->ucode_beacon_time - tsf_low) /
613                     beacon_interval)) {
614                         switch_count -= (priv->ucode_beacon_time -
615                                 tsf_low) / beacon_interval;
616                 } else
617                         switch_count = 0;
618         }
619         if (switch_count <= 1)
620                 cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time);
621         else {
622                 switch_time_in_usec =
623                         vif->bss_conf.beacon_int * switch_count * TIME_UNIT;
624                 ucode_switch_time = iwl_usecs_to_beacons(priv,
625                                                          switch_time_in_usec,
626                                                          beacon_interval);
627                 cmd.switch_time = iwl_add_beacon_time(priv,
628                                                       priv->ucode_beacon_time,
629                                                       ucode_switch_time,
630                                                       beacon_interval);
631         }
632         IWL_DEBUG_11H(priv, "uCode time for the switch is 0x%x\n",
633                       cmd.switch_time);
634         ch_info = iwl_get_channel_info(priv, priv->band, ch);
635         if (ch_info)
636                 cmd.expect_beacon = is_channel_radar(ch_info);
637         else {
638                 IWL_ERR(priv, "invalid channel switch from %u to %u\n",
639                         ctx->active.channel, ch);
640                 return -EFAULT;
641         }
642
643         return iwl_dvm_send_cmd(priv, &hcmd);
644 }
645
646 struct iwl_lib_ops iwl6000_lib = {
647         .set_hw_params = iwl6000_hw_set_hw_params,
648         .set_channel_switch = iwl6000_hw_channel_switch,
649         .nic_config = iwl6000_nic_config,
650         .eeprom_ops = {
651                 .regulatory_bands = {
652                         EEPROM_REG_BAND_1_CHANNELS,
653                         EEPROM_REG_BAND_2_CHANNELS,
654                         EEPROM_REG_BAND_3_CHANNELS,
655                         EEPROM_REG_BAND_4_CHANNELS,
656                         EEPROM_REG_BAND_5_CHANNELS,
657                         EEPROM_6000_REG_BAND_24_HT40_CHANNELS,
658                         EEPROM_REG_BAND_52_HT40_CHANNELS
659                 },
660                 .enhanced_txpower = true,
661         },
662         .temperature = iwlagn_temperature,
663 };
664
665 struct iwl_lib_ops iwl6030_lib = {
666         .set_hw_params = iwl6000_hw_set_hw_params,
667         .set_channel_switch = iwl6000_hw_channel_switch,
668         .nic_config = iwl6000_nic_config,
669         .eeprom_ops = {
670                 .regulatory_bands = {
671                         EEPROM_REG_BAND_1_CHANNELS,
672                         EEPROM_REG_BAND_2_CHANNELS,
673                         EEPROM_REG_BAND_3_CHANNELS,
674                         EEPROM_REG_BAND_4_CHANNELS,
675                         EEPROM_REG_BAND_5_CHANNELS,
676                         EEPROM_6000_REG_BAND_24_HT40_CHANNELS,
677                         EEPROM_REG_BAND_52_HT40_CHANNELS
678                 },
679                 .enhanced_txpower = true,
680         },
681         .temperature = iwlagn_temperature,
682 };