1 /******************************************************************************
3 * This file is provided under a dual BSD/GPLv2 license. When using or
4 * redistributing this file, you may do so under either license.
8 * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of version 2 of the GNU General Public License as
12 * published by the Free Software Foundation.
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
19 * The full GNU General Public License is included in this distribution
20 * in the file called COPYING.
22 * Contact Information:
23 * Intel Linux Wireless <linuxwifi@intel.com>
24 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
28 * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
29 * All rights reserved.
31 * Redistribution and use in source and binary forms, with or without
32 * modification, are permitted provided that the following conditions
35 * * Redistributions of source code must retain the above copyright
36 * notice, this list of conditions and the following disclaimer.
37 * * Redistributions in binary form must reproduce the above copyright
38 * notice, this list of conditions and the following disclaimer in
39 * the documentation and/or other materials provided with the
41 * * Neither the name Intel Corporation nor the names of its
42 * contributors may be used to endorse or promote products derived
43 * from this software without specific prior written permission.
45 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
46 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
47 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
48 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
49 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
50 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
51 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
52 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
53 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
54 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
55 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
56 *****************************************************************************/
58 #include <linux/slab.h>
59 #include <net/mac80211.h>
61 #include "iwl-trans.h"
67 /*****************************************************************************
68 * INIT calibrations framework
69 *****************************************************************************/
71 /* Opaque calibration results */
72 struct iwl_calib_result
{
73 struct list_head list
;
75 struct iwl_calib_hdr hdr
;
79 struct statistics_general_data
{
80 u32 beacon_silence_rssi_a
;
81 u32 beacon_silence_rssi_b
;
82 u32 beacon_silence_rssi_c
;
88 int iwl_send_calib_results(struct iwl_priv
*priv
)
90 struct iwl_host_cmd hcmd
= {
91 .id
= REPLY_PHY_CALIBRATION_CMD
,
93 struct iwl_calib_result
*res
;
95 list_for_each_entry(res
, &priv
->calib_results
, list
) {
98 hcmd
.len
[0] = res
->cmd_len
;
99 hcmd
.data
[0] = &res
->hdr
;
100 hcmd
.dataflags
[0] = IWL_HCMD_DFL_NOCOPY
;
101 ret
= iwl_dvm_send_cmd(priv
, &hcmd
);
103 IWL_ERR(priv
, "Error %d on calib cmd %d\n",
104 ret
, res
->hdr
.op_code
);
112 int iwl_calib_set(struct iwl_priv
*priv
,
113 const struct iwl_calib_hdr
*cmd
, int len
)
115 struct iwl_calib_result
*res
, *tmp
;
117 res
= kmalloc(sizeof(*res
) + len
- sizeof(struct iwl_calib_hdr
),
121 memcpy(&res
->hdr
, cmd
, len
);
124 list_for_each_entry(tmp
, &priv
->calib_results
, list
) {
125 if (tmp
->hdr
.op_code
== res
->hdr
.op_code
) {
126 list_replace(&tmp
->list
, &res
->list
);
132 /* wasn't in list already */
133 list_add_tail(&res
->list
, &priv
->calib_results
);
138 void iwl_calib_free_results(struct iwl_priv
*priv
)
140 struct iwl_calib_result
*res
, *tmp
;
142 list_for_each_entry_safe(res
, tmp
, &priv
->calib_results
, list
) {
143 list_del(&res
->list
);
148 /*****************************************************************************
149 * RUNTIME calibrations framework
150 *****************************************************************************/
152 /* "false alarms" are signals that our DSP tries to lock onto,
153 * but then determines that they are either noise, or transmissions
154 * from a distant wireless network (also "noise", really) that get
155 * "stepped on" by stronger transmissions within our own network.
156 * This algorithm attempts to set a sensitivity level that is high
157 * enough to receive all of our own network traffic, but not so
158 * high that our DSP gets too busy trying to lock onto non-network
160 static int iwl_sens_energy_cck(struct iwl_priv
*priv
,
163 struct statistics_general_data
*rx_info
)
167 u8 max_silence_rssi
= 0;
169 u8 silence_rssi_a
= 0;
170 u8 silence_rssi_b
= 0;
171 u8 silence_rssi_c
= 0;
174 /* "false_alarms" values below are cross-multiplications to assess the
175 * numbers of false alarms within the measured period of actual Rx
176 * (Rx is off when we're txing), vs the min/max expected false alarms
177 * (some should be expected if rx is sensitive enough) in a
178 * hypothetical listening period of 200 time units (TU), 204.8 msec:
180 * MIN_FA/fixed-time < false_alarms/actual-rx-time < MAX_FA/beacon-time
183 u32 false_alarms
= norm_fa
* 200 * 1024;
184 u32 max_false_alarms
= MAX_FA_CCK
* rx_enable_time
;
185 u32 min_false_alarms
= MIN_FA_CCK
* rx_enable_time
;
186 struct iwl_sensitivity_data
*data
= NULL
;
187 const struct iwl_sensitivity_ranges
*ranges
= priv
->hw_params
.sens
;
189 data
= &(priv
->sensitivity_data
);
191 data
->nrg_auto_corr_silence_diff
= 0;
193 /* Find max silence rssi among all 3 receivers.
194 * This is background noise, which may include transmissions from other
195 * networks, measured during silence before our network's beacon */
196 silence_rssi_a
= (u8
)((rx_info
->beacon_silence_rssi_a
&
197 ALL_BAND_FILTER
) >> 8);
198 silence_rssi_b
= (u8
)((rx_info
->beacon_silence_rssi_b
&
199 ALL_BAND_FILTER
) >> 8);
200 silence_rssi_c
= (u8
)((rx_info
->beacon_silence_rssi_c
&
201 ALL_BAND_FILTER
) >> 8);
203 val
= max(silence_rssi_b
, silence_rssi_c
);
204 max_silence_rssi
= max(silence_rssi_a
, (u8
) val
);
206 /* Store silence rssi in 20-beacon history table */
207 data
->nrg_silence_rssi
[data
->nrg_silence_idx
] = max_silence_rssi
;
208 data
->nrg_silence_idx
++;
209 if (data
->nrg_silence_idx
>= NRG_NUM_PREV_STAT_L
)
210 data
->nrg_silence_idx
= 0;
212 /* Find max silence rssi across 20 beacon history */
213 for (i
= 0; i
< NRG_NUM_PREV_STAT_L
; i
++) {
214 val
= data
->nrg_silence_rssi
[i
];
215 silence_ref
= max(silence_ref
, val
);
217 IWL_DEBUG_CALIB(priv
, "silence a %u, b %u, c %u, 20-bcn max %u\n",
218 silence_rssi_a
, silence_rssi_b
, silence_rssi_c
,
221 /* Find max rx energy (min value!) among all 3 receivers,
222 * measured during beacon frame.
223 * Save it in 10-beacon history table. */
224 i
= data
->nrg_energy_idx
;
225 val
= min(rx_info
->beacon_energy_b
, rx_info
->beacon_energy_c
);
226 data
->nrg_value
[i
] = min(rx_info
->beacon_energy_a
, val
);
228 data
->nrg_energy_idx
++;
229 if (data
->nrg_energy_idx
>= 10)
230 data
->nrg_energy_idx
= 0;
232 /* Find min rx energy (max value) across 10 beacon history.
233 * This is the minimum signal level that we want to receive well.
234 * Add backoff (margin so we don't miss slightly lower energy frames).
235 * This establishes an upper bound (min value) for energy threshold. */
236 max_nrg_cck
= data
->nrg_value
[0];
237 for (i
= 1; i
< 10; i
++)
238 max_nrg_cck
= (u32
) max(max_nrg_cck
, (data
->nrg_value
[i
]));
241 IWL_DEBUG_CALIB(priv
, "rx energy a %u, b %u, c %u, 10-bcn max/min %u\n",
242 rx_info
->beacon_energy_a
, rx_info
->beacon_energy_b
,
243 rx_info
->beacon_energy_c
, max_nrg_cck
- 6);
245 /* Count number of consecutive beacons with fewer-than-desired
247 if (false_alarms
< min_false_alarms
)
248 data
->num_in_cck_no_fa
++;
250 data
->num_in_cck_no_fa
= 0;
251 IWL_DEBUG_CALIB(priv
, "consecutive bcns with few false alarms = %u\n",
252 data
->num_in_cck_no_fa
);
254 /* If we got too many false alarms this time, reduce sensitivity */
255 if ((false_alarms
> max_false_alarms
) &&
256 (data
->auto_corr_cck
> AUTO_CORR_MAX_TH_CCK
)) {
257 IWL_DEBUG_CALIB(priv
, "norm FA %u > max FA %u\n",
258 false_alarms
, max_false_alarms
);
259 IWL_DEBUG_CALIB(priv
, "... reducing sensitivity\n");
260 data
->nrg_curr_state
= IWL_FA_TOO_MANY
;
261 /* Store for "fewer than desired" on later beacon */
262 data
->nrg_silence_ref
= silence_ref
;
264 /* increase energy threshold (reduce nrg value)
265 * to decrease sensitivity */
266 data
->nrg_th_cck
= data
->nrg_th_cck
- NRG_STEP_CCK
;
267 /* Else if we got fewer than desired, increase sensitivity */
268 } else if (false_alarms
< min_false_alarms
) {
269 data
->nrg_curr_state
= IWL_FA_TOO_FEW
;
271 /* Compare silence level with silence level for most recent
272 * healthy number or too many false alarms */
273 data
->nrg_auto_corr_silence_diff
= (s32
)data
->nrg_silence_ref
-
276 IWL_DEBUG_CALIB(priv
, "norm FA %u < min FA %u, silence diff %d\n",
277 false_alarms
, min_false_alarms
,
278 data
->nrg_auto_corr_silence_diff
);
280 /* Increase value to increase sensitivity, but only if:
281 * 1a) previous beacon did *not* have *too many* false alarms
282 * 1b) AND there's a significant difference in Rx levels
283 * from a previous beacon with too many, or healthy # FAs
284 * OR 2) We've seen a lot of beacons (100) with too few
286 if ((data
->nrg_prev_state
!= IWL_FA_TOO_MANY
) &&
287 ((data
->nrg_auto_corr_silence_diff
> NRG_DIFF
) ||
288 (data
->num_in_cck_no_fa
> MAX_NUMBER_CCK_NO_FA
))) {
290 IWL_DEBUG_CALIB(priv
, "... increasing sensitivity\n");
291 /* Increase nrg value to increase sensitivity */
292 val
= data
->nrg_th_cck
+ NRG_STEP_CCK
;
293 data
->nrg_th_cck
= min((u32
)ranges
->min_nrg_cck
, val
);
295 IWL_DEBUG_CALIB(priv
, "... but not changing sensitivity\n");
298 /* Else we got a healthy number of false alarms, keep status quo */
300 IWL_DEBUG_CALIB(priv
, " FA in safe zone\n");
301 data
->nrg_curr_state
= IWL_FA_GOOD_RANGE
;
303 /* Store for use in "fewer than desired" with later beacon */
304 data
->nrg_silence_ref
= silence_ref
;
306 /* If previous beacon had too many false alarms,
307 * give it some extra margin by reducing sensitivity again
308 * (but don't go below measured energy of desired Rx) */
309 if (data
->nrg_prev_state
== IWL_FA_TOO_MANY
) {
310 IWL_DEBUG_CALIB(priv
, "... increasing margin\n");
311 if (data
->nrg_th_cck
> (max_nrg_cck
+ NRG_MARGIN
))
312 data
->nrg_th_cck
-= NRG_MARGIN
;
314 data
->nrg_th_cck
= max_nrg_cck
;
318 /* Make sure the energy threshold does not go above the measured
319 * energy of the desired Rx signals (reduced by backoff margin),
320 * or else we might start missing Rx frames.
321 * Lower value is higher energy, so we use max()!
323 data
->nrg_th_cck
= max(max_nrg_cck
, data
->nrg_th_cck
);
324 IWL_DEBUG_CALIB(priv
, "new nrg_th_cck %u\n", data
->nrg_th_cck
);
326 data
->nrg_prev_state
= data
->nrg_curr_state
;
328 /* Auto-correlation CCK algorithm */
329 if (false_alarms
> min_false_alarms
) {
331 /* increase auto_corr values to decrease sensitivity
332 * so the DSP won't be disturbed by the noise
334 if (data
->auto_corr_cck
< AUTO_CORR_MAX_TH_CCK
)
335 data
->auto_corr_cck
= AUTO_CORR_MAX_TH_CCK
+ 1;
337 val
= data
->auto_corr_cck
+ AUTO_CORR_STEP_CCK
;
338 data
->auto_corr_cck
=
339 min((u32
)ranges
->auto_corr_max_cck
, val
);
341 val
= data
->auto_corr_cck_mrc
+ AUTO_CORR_STEP_CCK
;
342 data
->auto_corr_cck_mrc
=
343 min((u32
)ranges
->auto_corr_max_cck_mrc
, val
);
344 } else if ((false_alarms
< min_false_alarms
) &&
345 ((data
->nrg_auto_corr_silence_diff
> NRG_DIFF
) ||
346 (data
->num_in_cck_no_fa
> MAX_NUMBER_CCK_NO_FA
))) {
348 /* Decrease auto_corr values to increase sensitivity */
349 val
= data
->auto_corr_cck
- AUTO_CORR_STEP_CCK
;
350 data
->auto_corr_cck
=
351 max((u32
)ranges
->auto_corr_min_cck
, val
);
352 val
= data
->auto_corr_cck_mrc
- AUTO_CORR_STEP_CCK
;
353 data
->auto_corr_cck_mrc
=
354 max((u32
)ranges
->auto_corr_min_cck_mrc
, val
);
361 static int iwl_sens_auto_corr_ofdm(struct iwl_priv
*priv
,
366 u32 false_alarms
= norm_fa
* 200 * 1024;
367 u32 max_false_alarms
= MAX_FA_OFDM
* rx_enable_time
;
368 u32 min_false_alarms
= MIN_FA_OFDM
* rx_enable_time
;
369 struct iwl_sensitivity_data
*data
= NULL
;
370 const struct iwl_sensitivity_ranges
*ranges
= priv
->hw_params
.sens
;
372 data
= &(priv
->sensitivity_data
);
374 /* If we got too many false alarms this time, reduce sensitivity */
375 if (false_alarms
> max_false_alarms
) {
377 IWL_DEBUG_CALIB(priv
, "norm FA %u > max FA %u)\n",
378 false_alarms
, max_false_alarms
);
380 val
= data
->auto_corr_ofdm
+ AUTO_CORR_STEP_OFDM
;
381 data
->auto_corr_ofdm
=
382 min((u32
)ranges
->auto_corr_max_ofdm
, val
);
384 val
= data
->auto_corr_ofdm_mrc
+ AUTO_CORR_STEP_OFDM
;
385 data
->auto_corr_ofdm_mrc
=
386 min((u32
)ranges
->auto_corr_max_ofdm_mrc
, val
);
388 val
= data
->auto_corr_ofdm_x1
+ AUTO_CORR_STEP_OFDM
;
389 data
->auto_corr_ofdm_x1
=
390 min((u32
)ranges
->auto_corr_max_ofdm_x1
, val
);
392 val
= data
->auto_corr_ofdm_mrc_x1
+ AUTO_CORR_STEP_OFDM
;
393 data
->auto_corr_ofdm_mrc_x1
=
394 min((u32
)ranges
->auto_corr_max_ofdm_mrc_x1
, val
);
397 /* Else if we got fewer than desired, increase sensitivity */
398 else if (false_alarms
< min_false_alarms
) {
400 IWL_DEBUG_CALIB(priv
, "norm FA %u < min FA %u\n",
401 false_alarms
, min_false_alarms
);
403 val
= data
->auto_corr_ofdm
- AUTO_CORR_STEP_OFDM
;
404 data
->auto_corr_ofdm
=
405 max((u32
)ranges
->auto_corr_min_ofdm
, val
);
407 val
= data
->auto_corr_ofdm_mrc
- AUTO_CORR_STEP_OFDM
;
408 data
->auto_corr_ofdm_mrc
=
409 max((u32
)ranges
->auto_corr_min_ofdm_mrc
, val
);
411 val
= data
->auto_corr_ofdm_x1
- AUTO_CORR_STEP_OFDM
;
412 data
->auto_corr_ofdm_x1
=
413 max((u32
)ranges
->auto_corr_min_ofdm_x1
, val
);
415 val
= data
->auto_corr_ofdm_mrc_x1
- AUTO_CORR_STEP_OFDM
;
416 data
->auto_corr_ofdm_mrc_x1
=
417 max((u32
)ranges
->auto_corr_min_ofdm_mrc_x1
, val
);
419 IWL_DEBUG_CALIB(priv
, "min FA %u < norm FA %u < max FA %u OK\n",
420 min_false_alarms
, false_alarms
, max_false_alarms
);
425 static void iwl_prepare_legacy_sensitivity_tbl(struct iwl_priv
*priv
,
426 struct iwl_sensitivity_data
*data
,
429 tbl
[HD_AUTO_CORR32_X4_TH_ADD_MIN_INDEX
] =
430 cpu_to_le16((u16
)data
->auto_corr_ofdm
);
431 tbl
[HD_AUTO_CORR32_X4_TH_ADD_MIN_MRC_INDEX
] =
432 cpu_to_le16((u16
)data
->auto_corr_ofdm_mrc
);
433 tbl
[HD_AUTO_CORR32_X1_TH_ADD_MIN_INDEX
] =
434 cpu_to_le16((u16
)data
->auto_corr_ofdm_x1
);
435 tbl
[HD_AUTO_CORR32_X1_TH_ADD_MIN_MRC_INDEX
] =
436 cpu_to_le16((u16
)data
->auto_corr_ofdm_mrc_x1
);
438 tbl
[HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX
] =
439 cpu_to_le16((u16
)data
->auto_corr_cck
);
440 tbl
[HD_AUTO_CORR40_X4_TH_ADD_MIN_MRC_INDEX
] =
441 cpu_to_le16((u16
)data
->auto_corr_cck_mrc
);
443 tbl
[HD_MIN_ENERGY_CCK_DET_INDEX
] =
444 cpu_to_le16((u16
)data
->nrg_th_cck
);
445 tbl
[HD_MIN_ENERGY_OFDM_DET_INDEX
] =
446 cpu_to_le16((u16
)data
->nrg_th_ofdm
);
448 tbl
[HD_BARKER_CORR_TH_ADD_MIN_INDEX
] =
449 cpu_to_le16(data
->barker_corr_th_min
);
450 tbl
[HD_BARKER_CORR_TH_ADD_MIN_MRC_INDEX
] =
451 cpu_to_le16(data
->barker_corr_th_min_mrc
);
452 tbl
[HD_OFDM_ENERGY_TH_IN_INDEX
] =
453 cpu_to_le16(data
->nrg_th_cca
);
455 IWL_DEBUG_CALIB(priv
, "ofdm: ac %u mrc %u x1 %u mrc_x1 %u thresh %u\n",
456 data
->auto_corr_ofdm
, data
->auto_corr_ofdm_mrc
,
457 data
->auto_corr_ofdm_x1
, data
->auto_corr_ofdm_mrc_x1
,
460 IWL_DEBUG_CALIB(priv
, "cck: ac %u mrc %u thresh %u\n",
461 data
->auto_corr_cck
, data
->auto_corr_cck_mrc
,
465 /* Prepare a SENSITIVITY_CMD, send to uCode if values have changed */
466 static int iwl_sensitivity_write(struct iwl_priv
*priv
)
468 struct iwl_sensitivity_cmd cmd
;
469 struct iwl_sensitivity_data
*data
= NULL
;
470 struct iwl_host_cmd cmd_out
= {
471 .id
= SENSITIVITY_CMD
,
472 .len
= { sizeof(struct iwl_sensitivity_cmd
), },
477 data
= &(priv
->sensitivity_data
);
479 memset(&cmd
, 0, sizeof(cmd
));
481 iwl_prepare_legacy_sensitivity_tbl(priv
, data
, &cmd
.table
[0]);
483 /* Update uCode's "work" table, and copy it to DSP */
484 cmd
.control
= SENSITIVITY_CMD_CONTROL_WORK_TABLE
;
486 /* Don't send command to uCode if nothing has changed */
487 if (!memcmp(&cmd
.table
[0], &(priv
->sensitivity_tbl
[0]),
488 sizeof(u16
)*HD_TABLE_SIZE
)) {
489 IWL_DEBUG_CALIB(priv
, "No change in SENSITIVITY_CMD\n");
493 /* Copy table for comparison next time */
494 memcpy(&(priv
->sensitivity_tbl
[0]), &(cmd
.table
[0]),
495 sizeof(u16
)*HD_TABLE_SIZE
);
497 return iwl_dvm_send_cmd(priv
, &cmd_out
);
500 /* Prepare a SENSITIVITY_CMD, send to uCode if values have changed */
501 static int iwl_enhance_sensitivity_write(struct iwl_priv
*priv
)
503 struct iwl_enhance_sensitivity_cmd cmd
;
504 struct iwl_sensitivity_data
*data
= NULL
;
505 struct iwl_host_cmd cmd_out
= {
506 .id
= SENSITIVITY_CMD
,
507 .len
= { sizeof(struct iwl_enhance_sensitivity_cmd
), },
512 data
= &(priv
->sensitivity_data
);
514 memset(&cmd
, 0, sizeof(cmd
));
516 iwl_prepare_legacy_sensitivity_tbl(priv
, data
, &cmd
.enhance_table
[0]);
518 if (priv
->lib
->hd_v2
) {
519 cmd
.enhance_table
[HD_INA_NON_SQUARE_DET_OFDM_INDEX
] =
520 HD_INA_NON_SQUARE_DET_OFDM_DATA_V2
;
521 cmd
.enhance_table
[HD_INA_NON_SQUARE_DET_CCK_INDEX
] =
522 HD_INA_NON_SQUARE_DET_CCK_DATA_V2
;
523 cmd
.enhance_table
[HD_CORR_11_INSTEAD_OF_CORR_9_EN_INDEX
] =
524 HD_CORR_11_INSTEAD_OF_CORR_9_EN_DATA_V2
;
525 cmd
.enhance_table
[HD_OFDM_NON_SQUARE_DET_SLOPE_MRC_INDEX
] =
526 HD_OFDM_NON_SQUARE_DET_SLOPE_MRC_DATA_V2
;
527 cmd
.enhance_table
[HD_OFDM_NON_SQUARE_DET_INTERCEPT_MRC_INDEX
] =
528 HD_OFDM_NON_SQUARE_DET_INTERCEPT_MRC_DATA_V2
;
529 cmd
.enhance_table
[HD_OFDM_NON_SQUARE_DET_SLOPE_INDEX
] =
530 HD_OFDM_NON_SQUARE_DET_SLOPE_DATA_V2
;
531 cmd
.enhance_table
[HD_OFDM_NON_SQUARE_DET_INTERCEPT_INDEX
] =
532 HD_OFDM_NON_SQUARE_DET_INTERCEPT_DATA_V2
;
533 cmd
.enhance_table
[HD_CCK_NON_SQUARE_DET_SLOPE_MRC_INDEX
] =
534 HD_CCK_NON_SQUARE_DET_SLOPE_MRC_DATA_V2
;
535 cmd
.enhance_table
[HD_CCK_NON_SQUARE_DET_INTERCEPT_MRC_INDEX
] =
536 HD_CCK_NON_SQUARE_DET_INTERCEPT_MRC_DATA_V2
;
537 cmd
.enhance_table
[HD_CCK_NON_SQUARE_DET_SLOPE_INDEX
] =
538 HD_CCK_NON_SQUARE_DET_SLOPE_DATA_V2
;
539 cmd
.enhance_table
[HD_CCK_NON_SQUARE_DET_INTERCEPT_INDEX
] =
540 HD_CCK_NON_SQUARE_DET_INTERCEPT_DATA_V2
;
542 cmd
.enhance_table
[HD_INA_NON_SQUARE_DET_OFDM_INDEX
] =
543 HD_INA_NON_SQUARE_DET_OFDM_DATA_V1
;
544 cmd
.enhance_table
[HD_INA_NON_SQUARE_DET_CCK_INDEX
] =
545 HD_INA_NON_SQUARE_DET_CCK_DATA_V1
;
546 cmd
.enhance_table
[HD_CORR_11_INSTEAD_OF_CORR_9_EN_INDEX
] =
547 HD_CORR_11_INSTEAD_OF_CORR_9_EN_DATA_V1
;
548 cmd
.enhance_table
[HD_OFDM_NON_SQUARE_DET_SLOPE_MRC_INDEX
] =
549 HD_OFDM_NON_SQUARE_DET_SLOPE_MRC_DATA_V1
;
550 cmd
.enhance_table
[HD_OFDM_NON_SQUARE_DET_INTERCEPT_MRC_INDEX
] =
551 HD_OFDM_NON_SQUARE_DET_INTERCEPT_MRC_DATA_V1
;
552 cmd
.enhance_table
[HD_OFDM_NON_SQUARE_DET_SLOPE_INDEX
] =
553 HD_OFDM_NON_SQUARE_DET_SLOPE_DATA_V1
;
554 cmd
.enhance_table
[HD_OFDM_NON_SQUARE_DET_INTERCEPT_INDEX
] =
555 HD_OFDM_NON_SQUARE_DET_INTERCEPT_DATA_V1
;
556 cmd
.enhance_table
[HD_CCK_NON_SQUARE_DET_SLOPE_MRC_INDEX
] =
557 HD_CCK_NON_SQUARE_DET_SLOPE_MRC_DATA_V1
;
558 cmd
.enhance_table
[HD_CCK_NON_SQUARE_DET_INTERCEPT_MRC_INDEX
] =
559 HD_CCK_NON_SQUARE_DET_INTERCEPT_MRC_DATA_V1
;
560 cmd
.enhance_table
[HD_CCK_NON_SQUARE_DET_SLOPE_INDEX
] =
561 HD_CCK_NON_SQUARE_DET_SLOPE_DATA_V1
;
562 cmd
.enhance_table
[HD_CCK_NON_SQUARE_DET_INTERCEPT_INDEX
] =
563 HD_CCK_NON_SQUARE_DET_INTERCEPT_DATA_V1
;
566 /* Update uCode's "work" table, and copy it to DSP */
567 cmd
.control
= SENSITIVITY_CMD_CONTROL_WORK_TABLE
;
569 /* Don't send command to uCode if nothing has changed */
570 if (!memcmp(&cmd
.enhance_table
[0], &(priv
->sensitivity_tbl
[0]),
571 sizeof(u16
)*HD_TABLE_SIZE
) &&
572 !memcmp(&cmd
.enhance_table
[HD_INA_NON_SQUARE_DET_OFDM_INDEX
],
573 &(priv
->enhance_sensitivity_tbl
[0]),
574 sizeof(u16
)*ENHANCE_HD_TABLE_ENTRIES
)) {
575 IWL_DEBUG_CALIB(priv
, "No change in SENSITIVITY_CMD\n");
579 /* Copy table for comparison next time */
580 memcpy(&(priv
->sensitivity_tbl
[0]), &(cmd
.enhance_table
[0]),
581 sizeof(u16
)*HD_TABLE_SIZE
);
582 memcpy(&(priv
->enhance_sensitivity_tbl
[0]),
583 &(cmd
.enhance_table
[HD_INA_NON_SQUARE_DET_OFDM_INDEX
]),
584 sizeof(u16
)*ENHANCE_HD_TABLE_ENTRIES
);
586 return iwl_dvm_send_cmd(priv
, &cmd_out
);
589 void iwl_init_sensitivity(struct iwl_priv
*priv
)
593 struct iwl_sensitivity_data
*data
= NULL
;
594 const struct iwl_sensitivity_ranges
*ranges
= priv
->hw_params
.sens
;
596 if (priv
->calib_disabled
& IWL_SENSITIVITY_CALIB_DISABLED
)
599 IWL_DEBUG_CALIB(priv
, "Start iwl_init_sensitivity\n");
601 /* Clear driver's sensitivity algo data */
602 data
= &(priv
->sensitivity_data
);
607 memset(data
, 0, sizeof(struct iwl_sensitivity_data
));
609 data
->num_in_cck_no_fa
= 0;
610 data
->nrg_curr_state
= IWL_FA_TOO_MANY
;
611 data
->nrg_prev_state
= IWL_FA_TOO_MANY
;
612 data
->nrg_silence_ref
= 0;
613 data
->nrg_silence_idx
= 0;
614 data
->nrg_energy_idx
= 0;
616 for (i
= 0; i
< 10; i
++)
617 data
->nrg_value
[i
] = 0;
619 for (i
= 0; i
< NRG_NUM_PREV_STAT_L
; i
++)
620 data
->nrg_silence_rssi
[i
] = 0;
622 data
->auto_corr_ofdm
= ranges
->auto_corr_min_ofdm
;
623 data
->auto_corr_ofdm_mrc
= ranges
->auto_corr_min_ofdm_mrc
;
624 data
->auto_corr_ofdm_x1
= ranges
->auto_corr_min_ofdm_x1
;
625 data
->auto_corr_ofdm_mrc_x1
= ranges
->auto_corr_min_ofdm_mrc_x1
;
626 data
->auto_corr_cck
= AUTO_CORR_CCK_MIN_VAL_DEF
;
627 data
->auto_corr_cck_mrc
= ranges
->auto_corr_min_cck_mrc
;
628 data
->nrg_th_cck
= ranges
->nrg_th_cck
;
629 data
->nrg_th_ofdm
= ranges
->nrg_th_ofdm
;
630 data
->barker_corr_th_min
= ranges
->barker_corr_th_min
;
631 data
->barker_corr_th_min_mrc
= ranges
->barker_corr_th_min_mrc
;
632 data
->nrg_th_cca
= ranges
->nrg_th_cca
;
634 data
->last_bad_plcp_cnt_ofdm
= 0;
635 data
->last_fa_cnt_ofdm
= 0;
636 data
->last_bad_plcp_cnt_cck
= 0;
637 data
->last_fa_cnt_cck
= 0;
639 if (priv
->fw
->enhance_sensitivity_table
)
640 ret
|= iwl_enhance_sensitivity_write(priv
);
642 ret
|= iwl_sensitivity_write(priv
);
643 IWL_DEBUG_CALIB(priv
, "<<return 0x%X\n", ret
);
646 void iwl_sensitivity_calibration(struct iwl_priv
*priv
)
655 struct iwl_sensitivity_data
*data
= NULL
;
656 struct statistics_rx_non_phy
*rx_info
;
657 struct statistics_rx_phy
*ofdm
, *cck
;
658 struct statistics_general_data statis
;
660 if (priv
->calib_disabled
& IWL_SENSITIVITY_CALIB_DISABLED
)
663 data
= &(priv
->sensitivity_data
);
665 if (!iwl_is_any_associated(priv
)) {
666 IWL_DEBUG_CALIB(priv
, "<< - not associated\n");
670 spin_lock_bh(&priv
->statistics
.lock
);
671 rx_info
= &priv
->statistics
.rx_non_phy
;
672 ofdm
= &priv
->statistics
.rx_ofdm
;
673 cck
= &priv
->statistics
.rx_cck
;
674 if (rx_info
->interference_data_flag
!= INTERFERENCE_DATA_AVAILABLE
) {
675 IWL_DEBUG_CALIB(priv
, "<< invalid data.\n");
676 spin_unlock_bh(&priv
->statistics
.lock
);
680 /* Extract Statistics: */
681 rx_enable_time
= le32_to_cpu(rx_info
->channel_load
);
682 fa_cck
= le32_to_cpu(cck
->false_alarm_cnt
);
683 fa_ofdm
= le32_to_cpu(ofdm
->false_alarm_cnt
);
684 bad_plcp_cck
= le32_to_cpu(cck
->plcp_err
);
685 bad_plcp_ofdm
= le32_to_cpu(ofdm
->plcp_err
);
687 statis
.beacon_silence_rssi_a
=
688 le32_to_cpu(rx_info
->beacon_silence_rssi_a
);
689 statis
.beacon_silence_rssi_b
=
690 le32_to_cpu(rx_info
->beacon_silence_rssi_b
);
691 statis
.beacon_silence_rssi_c
=
692 le32_to_cpu(rx_info
->beacon_silence_rssi_c
);
693 statis
.beacon_energy_a
=
694 le32_to_cpu(rx_info
->beacon_energy_a
);
695 statis
.beacon_energy_b
=
696 le32_to_cpu(rx_info
->beacon_energy_b
);
697 statis
.beacon_energy_c
=
698 le32_to_cpu(rx_info
->beacon_energy_c
);
700 spin_unlock_bh(&priv
->statistics
.lock
);
702 IWL_DEBUG_CALIB(priv
, "rx_enable_time = %u usecs\n", rx_enable_time
);
704 if (!rx_enable_time
) {
705 IWL_DEBUG_CALIB(priv
, "<< RX Enable Time == 0!\n");
709 /* These statistics increase monotonically, and do not reset
710 * at each beacon. Calculate difference from last value, or just
711 * use the new statistics value if it has reset or wrapped around. */
712 if (data
->last_bad_plcp_cnt_cck
> bad_plcp_cck
)
713 data
->last_bad_plcp_cnt_cck
= bad_plcp_cck
;
715 bad_plcp_cck
-= data
->last_bad_plcp_cnt_cck
;
716 data
->last_bad_plcp_cnt_cck
+= bad_plcp_cck
;
719 if (data
->last_bad_plcp_cnt_ofdm
> bad_plcp_ofdm
)
720 data
->last_bad_plcp_cnt_ofdm
= bad_plcp_ofdm
;
722 bad_plcp_ofdm
-= data
->last_bad_plcp_cnt_ofdm
;
723 data
->last_bad_plcp_cnt_ofdm
+= bad_plcp_ofdm
;
726 if (data
->last_fa_cnt_ofdm
> fa_ofdm
)
727 data
->last_fa_cnt_ofdm
= fa_ofdm
;
729 fa_ofdm
-= data
->last_fa_cnt_ofdm
;
730 data
->last_fa_cnt_ofdm
+= fa_ofdm
;
733 if (data
->last_fa_cnt_cck
> fa_cck
)
734 data
->last_fa_cnt_cck
= fa_cck
;
736 fa_cck
-= data
->last_fa_cnt_cck
;
737 data
->last_fa_cnt_cck
+= fa_cck
;
740 /* Total aborted signal locks */
741 norm_fa_ofdm
= fa_ofdm
+ bad_plcp_ofdm
;
742 norm_fa_cck
= fa_cck
+ bad_plcp_cck
;
744 IWL_DEBUG_CALIB(priv
, "cck: fa %u badp %u ofdm: fa %u badp %u\n", fa_cck
,
745 bad_plcp_cck
, fa_ofdm
, bad_plcp_ofdm
);
747 iwl_sens_auto_corr_ofdm(priv
, norm_fa_ofdm
, rx_enable_time
);
748 iwl_sens_energy_cck(priv
, norm_fa_cck
, rx_enable_time
, &statis
);
749 if (priv
->fw
->enhance_sensitivity_table
)
750 iwl_enhance_sensitivity_write(priv
);
752 iwl_sensitivity_write(priv
);
755 static inline u8
find_first_chain(u8 mask
)
765 * Run disconnected antenna algorithm to find out which antennas are
768 static void iwl_find_disconn_antenna(struct iwl_priv
*priv
, u32
* average_sig
,
769 struct iwl_chain_noise_data
*data
)
771 u32 active_chains
= 0;
773 u16 max_average_sig_antenna_i
;
778 average_sig
[0] = data
->chain_signal_a
/ IWL_CAL_NUM_BEACONS
;
779 average_sig
[1] = data
->chain_signal_b
/ IWL_CAL_NUM_BEACONS
;
780 average_sig
[2] = data
->chain_signal_c
/ IWL_CAL_NUM_BEACONS
;
782 if (average_sig
[0] >= average_sig
[1]) {
783 max_average_sig
= average_sig
[0];
784 max_average_sig_antenna_i
= 0;
785 active_chains
= (1 << max_average_sig_antenna_i
);
787 max_average_sig
= average_sig
[1];
788 max_average_sig_antenna_i
= 1;
789 active_chains
= (1 << max_average_sig_antenna_i
);
792 if (average_sig
[2] >= max_average_sig
) {
793 max_average_sig
= average_sig
[2];
794 max_average_sig_antenna_i
= 2;
795 active_chains
= (1 << max_average_sig_antenna_i
);
798 IWL_DEBUG_CALIB(priv
, "average_sig: a %d b %d c %d\n",
799 average_sig
[0], average_sig
[1], average_sig
[2]);
800 IWL_DEBUG_CALIB(priv
, "max_average_sig = %d, antenna %d\n",
801 max_average_sig
, max_average_sig_antenna_i
);
803 /* Compare signal strengths for all 3 receivers. */
804 for (i
= 0; i
< NUM_RX_CHAINS
; i
++) {
805 if (i
!= max_average_sig_antenna_i
) {
806 s32 rssi_delta
= (max_average_sig
- average_sig
[i
]);
808 /* If signal is very weak, compared with
809 * strongest, mark it as disconnected. */
810 if (rssi_delta
> MAXIMUM_ALLOWED_PATHLOSS
)
811 data
->disconn_array
[i
] = 1;
813 active_chains
|= (1 << i
);
814 IWL_DEBUG_CALIB(priv
, "i = %d rssiDelta = %d "
815 "disconn_array[i] = %d\n",
816 i
, rssi_delta
, data
->disconn_array
[i
]);
821 * The above algorithm sometimes fails when the ucode
822 * reports 0 for all chains. It's not clear why that
823 * happens to start with, but it is then causing trouble
824 * because this can make us enable more chains than the
825 * hardware really has.
827 * To be safe, simply mask out any chains that we know
828 * are not on the device.
830 active_chains
&= priv
->nvm_data
->valid_rx_ant
;
833 for (i
= 0; i
< NUM_RX_CHAINS
; i
++) {
834 /* loops on all the bits of
835 * priv->hw_setting.valid_tx_ant */
836 u8 ant_msk
= (1 << i
);
837 if (!(priv
->nvm_data
->valid_tx_ant
& ant_msk
))
841 if (data
->disconn_array
[i
] == 0)
842 /* there is a Tx antenna connected */
844 if (num_tx_chains
== priv
->hw_params
.tx_chains_num
&&
845 data
->disconn_array
[i
]) {
847 * If all chains are disconnected
848 * connect the first valid tx chain
851 find_first_chain(priv
->nvm_data
->valid_tx_ant
);
852 data
->disconn_array
[first_chain
] = 0;
853 active_chains
|= BIT(first_chain
);
854 IWL_DEBUG_CALIB(priv
,
855 "All Tx chains are disconnected W/A - declare %d as connected\n",
861 if (active_chains
!= priv
->nvm_data
->valid_rx_ant
&&
862 active_chains
!= priv
->chain_noise_data
.active_chains
)
863 IWL_DEBUG_CALIB(priv
,
864 "Detected that not all antennas are connected! "
865 "Connected: %#x, valid: %#x.\n",
867 priv
->nvm_data
->valid_rx_ant
);
869 /* Save for use within RXON, TX, SCAN commands, etc. */
870 data
->active_chains
= active_chains
;
871 IWL_DEBUG_CALIB(priv
, "active_chains (bitwise) = 0x%x\n",
875 static void iwlagn_gain_computation(struct iwl_priv
*priv
,
876 u32 average_noise
[NUM_RX_CHAINS
],
881 struct iwl_chain_noise_data
*data
= &priv
->chain_noise_data
;
884 * Find Gain Code for the chains based on "default chain"
886 for (i
= default_chain
+ 1; i
< NUM_RX_CHAINS
; i
++) {
887 if ((data
->disconn_array
[i
])) {
888 data
->delta_gain_code
[i
] = 0;
892 delta_g
= (priv
->lib
->chain_noise_scale
*
893 ((s32
)average_noise
[default_chain
] -
894 (s32
)average_noise
[i
])) / 1500;
896 /* bound gain by 2 bits value max, 3rd bit is sign */
897 data
->delta_gain_code
[i
] =
898 min(abs(delta_g
), CHAIN_NOISE_MAX_DELTA_GAIN_CODE
);
902 * set negative sign ...
903 * note to Intel developers: This is uCode API format,
904 * not the format of any internal device registers.
905 * Do not change this format for e.g. 6050 or similar
906 * devices. Change format only if more resolution
907 * (i.e. more than 2 bits magnitude) is needed.
909 data
->delta_gain_code
[i
] |= (1 << 2);
912 IWL_DEBUG_CALIB(priv
, "Delta gains: ANT_B = %d ANT_C = %d\n",
913 data
->delta_gain_code
[1], data
->delta_gain_code
[2]);
915 if (!data
->radio_write
) {
916 struct iwl_calib_chain_noise_gain_cmd cmd
;
918 memset(&cmd
, 0, sizeof(cmd
));
920 iwl_set_calib_hdr(&cmd
.hdr
,
921 priv
->phy_calib_chain_noise_gain_cmd
);
922 cmd
.delta_gain_1
= data
->delta_gain_code
[1];
923 cmd
.delta_gain_2
= data
->delta_gain_code
[2];
924 iwl_dvm_send_cmd_pdu(priv
, REPLY_PHY_CALIBRATION_CMD
,
925 CMD_ASYNC
, sizeof(cmd
), &cmd
);
927 data
->radio_write
= 1;
928 data
->state
= IWL_CHAIN_NOISE_CALIBRATED
;
933 * Accumulate 16 beacons of signal and noise statistics for each of
934 * 3 receivers/antennas/rx-chains, then figure out:
935 * 1) Which antennas are connected.
936 * 2) Differential rx gain settings to balance the 3 receivers.
938 void iwl_chain_noise_calibration(struct iwl_priv
*priv
)
940 struct iwl_chain_noise_data
*data
= NULL
;
948 u32 average_sig
[NUM_RX_CHAINS
] = {INITIALIZATION_VALUE
};
949 u32 average_noise
[NUM_RX_CHAINS
] = {INITIALIZATION_VALUE
};
950 u32 min_average_noise
= MIN_AVERAGE_NOISE_MAX_VALUE
;
951 u16 min_average_noise_antenna_i
= INITIALIZATION_VALUE
;
953 u16 rxon_chnum
= INITIALIZATION_VALUE
;
954 u16 stat_chnum
= INITIALIZATION_VALUE
;
957 struct statistics_rx_non_phy
*rx_info
;
961 * When we support multiple interfaces on different channels,
962 * this must be modified/fixed.
964 struct iwl_rxon_context
*ctx
= &priv
->contexts
[IWL_RXON_CTX_BSS
];
966 if (priv
->calib_disabled
& IWL_CHAIN_NOISE_CALIB_DISABLED
)
969 data
= &(priv
->chain_noise_data
);
972 * Accumulate just the first "chain_noise_num_beacons" after
973 * the first association, then we're done forever.
975 if (data
->state
!= IWL_CHAIN_NOISE_ACCUMULATE
) {
976 if (data
->state
== IWL_CHAIN_NOISE_ALIVE
)
977 IWL_DEBUG_CALIB(priv
, "Wait for noise calib reset\n");
981 spin_lock_bh(&priv
->statistics
.lock
);
983 rx_info
= &priv
->statistics
.rx_non_phy
;
985 if (rx_info
->interference_data_flag
!= INTERFERENCE_DATA_AVAILABLE
) {
986 IWL_DEBUG_CALIB(priv
, " << Interference data unavailable\n");
987 spin_unlock_bh(&priv
->statistics
.lock
);
991 rxon_band24
= !!(ctx
->staging
.flags
& RXON_FLG_BAND_24G_MSK
);
992 rxon_chnum
= le16_to_cpu(ctx
->staging
.channel
);
994 !!(priv
->statistics
.flag
& STATISTICS_REPLY_FLG_BAND_24G_MSK
);
995 stat_chnum
= le32_to_cpu(priv
->statistics
.flag
) >> 16;
997 /* Make sure we accumulate data for just the associated channel
998 * (even if scanning). */
999 if ((rxon_chnum
!= stat_chnum
) || (rxon_band24
!= stat_band24
)) {
1000 IWL_DEBUG_CALIB(priv
, "Stats not from chan=%d, band24=%d\n",
1001 rxon_chnum
, rxon_band24
);
1002 spin_unlock_bh(&priv
->statistics
.lock
);
1007 * Accumulate beacon statistics values across
1008 * "chain_noise_num_beacons"
1010 chain_noise_a
= le32_to_cpu(rx_info
->beacon_silence_rssi_a
) &
1012 chain_noise_b
= le32_to_cpu(rx_info
->beacon_silence_rssi_b
) &
1014 chain_noise_c
= le32_to_cpu(rx_info
->beacon_silence_rssi_c
) &
1017 chain_sig_a
= le32_to_cpu(rx_info
->beacon_rssi_a
) & IN_BAND_FILTER
;
1018 chain_sig_b
= le32_to_cpu(rx_info
->beacon_rssi_b
) & IN_BAND_FILTER
;
1019 chain_sig_c
= le32_to_cpu(rx_info
->beacon_rssi_c
) & IN_BAND_FILTER
;
1021 spin_unlock_bh(&priv
->statistics
.lock
);
1023 data
->beacon_count
++;
1025 data
->chain_noise_a
= (chain_noise_a
+ data
->chain_noise_a
);
1026 data
->chain_noise_b
= (chain_noise_b
+ data
->chain_noise_b
);
1027 data
->chain_noise_c
= (chain_noise_c
+ data
->chain_noise_c
);
1029 data
->chain_signal_a
= (chain_sig_a
+ data
->chain_signal_a
);
1030 data
->chain_signal_b
= (chain_sig_b
+ data
->chain_signal_b
);
1031 data
->chain_signal_c
= (chain_sig_c
+ data
->chain_signal_c
);
1033 IWL_DEBUG_CALIB(priv
, "chan=%d, band24=%d, beacon=%d\n",
1034 rxon_chnum
, rxon_band24
, data
->beacon_count
);
1035 IWL_DEBUG_CALIB(priv
, "chain_sig: a %d b %d c %d\n",
1036 chain_sig_a
, chain_sig_b
, chain_sig_c
);
1037 IWL_DEBUG_CALIB(priv
, "chain_noise: a %d b %d c %d\n",
1038 chain_noise_a
, chain_noise_b
, chain_noise_c
);
1040 /* If this is the "chain_noise_num_beacons", determine:
1041 * 1) Disconnected antennas (using signal strengths)
1042 * 2) Differential gain (using silence noise) to balance receivers */
1043 if (data
->beacon_count
!= IWL_CAL_NUM_BEACONS
)
1046 /* Analyze signal for disconnected antenna */
1047 if (priv
->lib
->bt_params
&&
1048 priv
->lib
->bt_params
->advanced_bt_coexist
) {
1049 /* Disable disconnected antenna algorithm for advanced
1050 bt coex, assuming valid antennas are connected */
1051 data
->active_chains
= priv
->nvm_data
->valid_rx_ant
;
1052 for (i
= 0; i
< NUM_RX_CHAINS
; i
++)
1053 if (!(data
->active_chains
& (1<<i
)))
1054 data
->disconn_array
[i
] = 1;
1056 iwl_find_disconn_antenna(priv
, average_sig
, data
);
1058 /* Analyze noise for rx balance */
1059 average_noise
[0] = data
->chain_noise_a
/ IWL_CAL_NUM_BEACONS
;
1060 average_noise
[1] = data
->chain_noise_b
/ IWL_CAL_NUM_BEACONS
;
1061 average_noise
[2] = data
->chain_noise_c
/ IWL_CAL_NUM_BEACONS
;
1063 for (i
= 0; i
< NUM_RX_CHAINS
; i
++) {
1064 if (!(data
->disconn_array
[i
]) &&
1065 (average_noise
[i
] <= min_average_noise
)) {
1066 /* This means that chain i is active and has
1067 * lower noise values so far: */
1068 min_average_noise
= average_noise
[i
];
1069 min_average_noise_antenna_i
= i
;
1073 IWL_DEBUG_CALIB(priv
, "average_noise: a %d b %d c %d\n",
1074 average_noise
[0], average_noise
[1],
1077 IWL_DEBUG_CALIB(priv
, "min_average_noise = %d, antenna %d\n",
1078 min_average_noise
, min_average_noise_antenna_i
);
1080 iwlagn_gain_computation(
1081 priv
, average_noise
,
1082 find_first_chain(priv
->nvm_data
->valid_rx_ant
));
1084 /* Some power changes may have been made during the calibration.
1085 * Update and commit the RXON
1087 iwl_update_chain_flags(priv
);
1089 data
->state
= IWL_CHAIN_NOISE_DONE
;
1090 iwl_power_update_mode(priv
, false);
1093 void iwl_reset_run_time_calib(struct iwl_priv
*priv
)
1096 memset(&(priv
->sensitivity_data
), 0,
1097 sizeof(struct iwl_sensitivity_data
));
1098 memset(&(priv
->chain_noise_data
), 0,
1099 sizeof(struct iwl_chain_noise_data
));
1100 for (i
= 0; i
< NUM_RX_CHAINS
; i
++)
1101 priv
->chain_noise_data
.delta_gain_code
[i
] =
1102 CHAIN_NOISE_DELTA_GAIN_INIT_VAL
;
1104 /* Ask for statistics now, the uCode will send notification
1105 * periodically after association */
1106 iwl_send_statistics_request(priv
, CMD_ASYNC
, true);