1
/******************************************************************************
5
* Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
7
* This program is free software; you can redistribute it and/or modify
8
* it under the terms of version 2 of the GNU General Public License as
9
* published by the Free Software Foundation.
11
* This program is distributed in the hope that it will be useful, but
12
* WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
* General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, write to the Free Software
18
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
21
* The full GNU General Public License is included in this distribution
22
* in the file called LICENSE.GPL.
24
* Contact Information:
25
* Intel Linux Wireless <ilw@linux.intel.com>
26
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
28
*****************************************************************************/
30
#include <linux/kernel.h>
31
#include <linux/module.h>
32
#include <linux/init.h>
33
#include <linux/sched.h>
37
#include "iwl-agn-calib.h"
40
#include "iwl-helpers.h"
41
#include "iwl-agn-hw.h"
44
void iwl_rx_missed_beacon_notif(struct iwl_priv *priv,
45
struct iwl_rx_mem_buffer *rxb)
48
struct iwl_rx_packet *pkt = rxb_addr(rxb);
49
struct iwl_missed_beacon_notif *missed_beacon;
51
missed_beacon = &pkt->u.missed_beacon;
52
if (le32_to_cpu(missed_beacon->consecutive_missed_beacons) >
53
priv->missed_beacon_threshold) {
55
"missed bcn cnsq %d totl %d rcd %d expctd %d\n",
56
le32_to_cpu(missed_beacon->consecutive_missed_beacons),
57
le32_to_cpu(missed_beacon->total_missed_becons),
58
le32_to_cpu(missed_beacon->num_recvd_beacons),
59
le32_to_cpu(missed_beacon->num_expected_beacons));
60
if (!test_bit(STATUS_SCANNING, &priv->status))
61
iwl_init_sensitivity(priv);
65
/* Calculate noise level, based on measurements during network silence just
66
* before arriving beacon. This measurement can be done only if we know
67
* exactly when to expect beacons, therefore only when we're associated. */
68
static void iwl_rx_calc_noise(struct iwl_priv *priv)
70
struct statistics_rx_non_phy *rx_info;
71
int num_active_rx = 0;
72
int total_silence = 0;
73
int bcn_silence_a, bcn_silence_b, bcn_silence_c;
76
if (priv->cfg->bt_params &&
77
priv->cfg->bt_params->bt_statistics)
78
rx_info = &(priv->_agn.statistics_bt.rx.general.common);
80
rx_info = &(priv->_agn.statistics.rx.general);
82
le32_to_cpu(rx_info->beacon_silence_rssi_a) & IN_BAND_FILTER;
84
le32_to_cpu(rx_info->beacon_silence_rssi_b) & IN_BAND_FILTER;
86
le32_to_cpu(rx_info->beacon_silence_rssi_c) & IN_BAND_FILTER;
89
total_silence += bcn_silence_a;
93
total_silence += bcn_silence_b;
97
total_silence += bcn_silence_c;
101
/* Average among active antennas */
103
last_rx_noise = (total_silence / num_active_rx) - 107;
105
last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE;
107
IWL_DEBUG_CALIB(priv, "inband silence a %u, b %u, c %u, dBm %d\n",
108
bcn_silence_a, bcn_silence_b, bcn_silence_c,
112
#ifdef CONFIG_IWLWIFI_DEBUGFS
114
* based on the assumption of all statistics counter are in DWORD
115
* FIXME: This function is for debugging, do not deal with
116
* the case of counters roll-over.
118
static void iwl_accumulative_statistics(struct iwl_priv *priv,
124
u32 *delta, *max_delta;
125
struct statistics_general_common *general, *accum_general;
126
struct statistics_tx *tx, *accum_tx;
128
if (priv->cfg->bt_params &&
129
priv->cfg->bt_params->bt_statistics) {
130
prev_stats = (__le32 *)&priv->_agn.statistics_bt;
131
accum_stats = (u32 *)&priv->_agn.accum_statistics_bt;
132
size = sizeof(struct iwl_bt_notif_statistics);
133
general = &priv->_agn.statistics_bt.general.common;
134
accum_general = &priv->_agn.accum_statistics_bt.general.common;
135
tx = &priv->_agn.statistics_bt.tx;
136
accum_tx = &priv->_agn.accum_statistics_bt.tx;
137
delta = (u32 *)&priv->_agn.delta_statistics_bt;
138
max_delta = (u32 *)&priv->_agn.max_delta_bt;
140
prev_stats = (__le32 *)&priv->_agn.statistics;
141
accum_stats = (u32 *)&priv->_agn.accum_statistics;
142
size = sizeof(struct iwl_notif_statistics);
143
general = &priv->_agn.statistics.general.common;
144
accum_general = &priv->_agn.accum_statistics.general.common;
145
tx = &priv->_agn.statistics.tx;
146
accum_tx = &priv->_agn.accum_statistics.tx;
147
delta = (u32 *)&priv->_agn.delta_statistics;
148
max_delta = (u32 *)&priv->_agn.max_delta;
150
for (i = sizeof(__le32); i < size;
151
i += sizeof(__le32), stats++, prev_stats++, delta++,
152
max_delta++, accum_stats++) {
153
if (le32_to_cpu(*stats) > le32_to_cpu(*prev_stats)) {
154
*delta = (le32_to_cpu(*stats) -
155
le32_to_cpu(*prev_stats));
156
*accum_stats += *delta;
157
if (*delta > *max_delta)
162
/* reset accumulative statistics for "no-counter" type statistics */
163
accum_general->temperature = general->temperature;
164
accum_general->temperature_m = general->temperature_m;
165
accum_general->ttl_timestamp = general->ttl_timestamp;
166
accum_tx->tx_power.ant_a = tx->tx_power.ant_a;
167
accum_tx->tx_power.ant_b = tx->tx_power.ant_b;
168
accum_tx->tx_power.ant_c = tx->tx_power.ant_c;
172
#define REG_RECALIB_PERIOD (60)
175
* iwl_good_plcp_health - checks for plcp error.
177
* When the plcp error is exceeding the thresholds, reset the radio
178
* to improve the throughput.
180
bool iwl_good_plcp_health(struct iwl_priv *priv,
181
struct iwl_rx_packet *pkt)
184
int combined_plcp_delta;
185
unsigned int plcp_msec;
186
unsigned long plcp_received_jiffies;
188
if (priv->cfg->base_params->plcp_delta_threshold ==
189
IWL_MAX_PLCP_ERR_THRESHOLD_DISABLE) {
190
IWL_DEBUG_RADIO(priv, "plcp_err check disabled\n");
195
* check for plcp_err and trigger radio reset if it exceeds
196
* the plcp error threshold plcp_delta.
198
plcp_received_jiffies = jiffies;
199
plcp_msec = jiffies_to_msecs((long) plcp_received_jiffies -
200
(long) priv->plcp_jiffies);
201
priv->plcp_jiffies = plcp_received_jiffies;
203
* check to make sure plcp_msec is not 0 to prevent division
207
struct statistics_rx_phy *ofdm;
208
struct statistics_rx_ht_phy *ofdm_ht;
210
if (priv->cfg->bt_params &&
211
priv->cfg->bt_params->bt_statistics) {
212
ofdm = &pkt->u.stats_bt.rx.ofdm;
213
ofdm_ht = &pkt->u.stats_bt.rx.ofdm_ht;
214
combined_plcp_delta =
215
(le32_to_cpu(ofdm->plcp_err) -
216
le32_to_cpu(priv->_agn.statistics_bt.
218
(le32_to_cpu(ofdm_ht->plcp_err) -
219
le32_to_cpu(priv->_agn.statistics_bt.
220
rx.ofdm_ht.plcp_err));
222
ofdm = &pkt->u.stats.rx.ofdm;
223
ofdm_ht = &pkt->u.stats.rx.ofdm_ht;
224
combined_plcp_delta =
225
(le32_to_cpu(ofdm->plcp_err) -
226
le32_to_cpu(priv->_agn.statistics.
228
(le32_to_cpu(ofdm_ht->plcp_err) -
229
le32_to_cpu(priv->_agn.statistics.
230
rx.ofdm_ht.plcp_err));
233
if ((combined_plcp_delta > 0) &&
234
((combined_plcp_delta * 100) / plcp_msec) >
235
priv->cfg->base_params->plcp_delta_threshold) {
237
* if plcp_err exceed the threshold,
238
* the following data is printed in csv format:
239
* Text: plcp_err exceeded %d,
240
* Received ofdm.plcp_err,
241
* Current ofdm.plcp_err,
242
* Received ofdm_ht.plcp_err,
243
* Current ofdm_ht.plcp_err,
244
* combined_plcp_delta,
247
IWL_DEBUG_RADIO(priv, "plcp_err exceeded %u, "
248
"%u, %u, %u, %u, %d, %u mSecs\n",
249
priv->cfg->base_params->plcp_delta_threshold,
250
le32_to_cpu(ofdm->plcp_err),
251
le32_to_cpu(ofdm->plcp_err),
252
le32_to_cpu(ofdm_ht->plcp_err),
253
le32_to_cpu(ofdm_ht->plcp_err),
254
combined_plcp_delta, plcp_msec);
262
void iwl_rx_statistics(struct iwl_priv *priv,
263
struct iwl_rx_mem_buffer *rxb)
266
struct iwl_rx_packet *pkt = rxb_addr(rxb);
268
if (priv->cfg->bt_params &&
269
priv->cfg->bt_params->bt_statistics) {
271
"Statistics notification received (%d vs %d).\n",
272
(int)sizeof(struct iwl_bt_notif_statistics),
273
le32_to_cpu(pkt->len_n_flags) &
274
FH_RSCSR_FRAME_SIZE_MSK);
276
change = ((priv->_agn.statistics_bt.general.common.temperature !=
277
pkt->u.stats_bt.general.common.temperature) ||
278
((priv->_agn.statistics_bt.flag &
279
STATISTICS_REPLY_FLG_HT40_MODE_MSK) !=
280
(pkt->u.stats_bt.flag &
281
STATISTICS_REPLY_FLG_HT40_MODE_MSK)));
282
#ifdef CONFIG_IWLWIFI_DEBUGFS
283
iwl_accumulative_statistics(priv, (__le32 *)&pkt->u.stats_bt);
288
"Statistics notification received (%d vs %d).\n",
289
(int)sizeof(struct iwl_notif_statistics),
290
le32_to_cpu(pkt->len_n_flags) &
291
FH_RSCSR_FRAME_SIZE_MSK);
293
change = ((priv->_agn.statistics.general.common.temperature !=
294
pkt->u.stats.general.common.temperature) ||
295
((priv->_agn.statistics.flag &
296
STATISTICS_REPLY_FLG_HT40_MODE_MSK) !=
298
STATISTICS_REPLY_FLG_HT40_MODE_MSK)));
299
#ifdef CONFIG_IWLWIFI_DEBUGFS
300
iwl_accumulative_statistics(priv, (__le32 *)&pkt->u.stats);
305
iwl_recover_from_statistics(priv, pkt);
307
if (priv->cfg->bt_params &&
308
priv->cfg->bt_params->bt_statistics)
309
memcpy(&priv->_agn.statistics_bt, &pkt->u.stats_bt,
310
sizeof(priv->_agn.statistics_bt));
312
memcpy(&priv->_agn.statistics, &pkt->u.stats,
313
sizeof(priv->_agn.statistics));
315
set_bit(STATUS_STATISTICS, &priv->status);
317
/* Reschedule the statistics timer to occur in
318
* REG_RECALIB_PERIOD seconds to ensure we get a
319
* thermal update even if the uCode doesn't give
321
mod_timer(&priv->statistics_periodic, jiffies +
322
msecs_to_jiffies(REG_RECALIB_PERIOD * 1000));
324
if (unlikely(!test_bit(STATUS_SCANNING, &priv->status)) &&
325
(pkt->hdr.cmd == STATISTICS_NOTIFICATION)) {
326
iwl_rx_calc_noise(priv);
327
queue_work(priv->workqueue, &priv->run_time_calib_work);
329
if (priv->cfg->ops->lib->temp_ops.temperature && change)
330
priv->cfg->ops->lib->temp_ops.temperature(priv);
333
void iwl_reply_statistics(struct iwl_priv *priv,
334
struct iwl_rx_mem_buffer *rxb)
336
struct iwl_rx_packet *pkt = rxb_addr(rxb);
338
if (le32_to_cpu(pkt->u.stats.flag) & UCODE_STATISTICS_CLEAR_MSK) {
339
#ifdef CONFIG_IWLWIFI_DEBUGFS
340
memset(&priv->_agn.accum_statistics, 0,
341
sizeof(struct iwl_notif_statistics));
342
memset(&priv->_agn.delta_statistics, 0,
343
sizeof(struct iwl_notif_statistics));
344
memset(&priv->_agn.max_delta, 0,
345
sizeof(struct iwl_notif_statistics));
346
memset(&priv->_agn.accum_statistics_bt, 0,
347
sizeof(struct iwl_bt_notif_statistics));
348
memset(&priv->_agn.delta_statistics_bt, 0,
349
sizeof(struct iwl_bt_notif_statistics));
350
memset(&priv->_agn.max_delta_bt, 0,
351
sizeof(struct iwl_bt_notif_statistics));
353
IWL_DEBUG_RX(priv, "Statistics have been cleared\n");
355
iwl_rx_statistics(priv, rxb);