~ubuntu-branches/ubuntu/precise/linux-ti-omap4/precise

« back to all changes in this revision

Viewing changes to drivers/net/wireless/iwlwifi/iwl-agn-rx.c

  • Committer: Bazaar Package Importer
  • Author(s): Paolo Pisati
  • Date: 2011-06-29 15:23:51 UTC
  • mfrom: (26.1.1 natty-proposed)
  • Revision ID: james.westby@ubuntu.com-20110629152351-xs96tm303d95rpbk
Tags: 3.0.0-1200.2
* Rebased against 3.0.0-6.7
* BSP from TI based on 3.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/******************************************************************************
2
 
 *
3
 
 * GPL LICENSE SUMMARY
4
 
 *
5
 
 * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
6
 
 *
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.
10
 
 *
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.
15
 
 *
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,
19
 
 * USA
20
 
 *
21
 
 * The full GNU General Public License is included in this distribution
22
 
 * in the file called LICENSE.GPL.
23
 
 *
24
 
 * Contact Information:
25
 
 *  Intel Linux Wireless <ilw@linux.intel.com>
26
 
 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
27
 
 *
28
 
 *****************************************************************************/
29
 
 
30
 
#include <linux/kernel.h>
31
 
#include <linux/module.h>
32
 
#include <linux/init.h>
33
 
#include <linux/sched.h>
34
 
 
35
 
#include "iwl-dev.h"
36
 
#include "iwl-core.h"
37
 
#include "iwl-agn-calib.h"
38
 
#include "iwl-sta.h"
39
 
#include "iwl-io.h"
40
 
#include "iwl-helpers.h"
41
 
#include "iwl-agn-hw.h"
42
 
#include "iwl-agn.h"
43
 
 
44
 
void iwl_rx_missed_beacon_notif(struct iwl_priv *priv,
45
 
                                struct iwl_rx_mem_buffer *rxb)
46
 
 
47
 
{
48
 
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
49
 
        struct iwl_missed_beacon_notif *missed_beacon;
50
 
 
51
 
        missed_beacon = &pkt->u.missed_beacon;
52
 
        if (le32_to_cpu(missed_beacon->consecutive_missed_beacons) >
53
 
            priv->missed_beacon_threshold) {
54
 
                IWL_DEBUG_CALIB(priv,
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);
62
 
        }
63
 
}
64
 
 
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)
69
 
{
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;
74
 
        int last_rx_noise;
75
 
 
76
 
        if (priv->cfg->bt_params &&
77
 
            priv->cfg->bt_params->bt_statistics)
78
 
                rx_info = &(priv->_agn.statistics_bt.rx.general.common);
79
 
        else
80
 
                rx_info = &(priv->_agn.statistics.rx.general);
81
 
        bcn_silence_a =
82
 
                le32_to_cpu(rx_info->beacon_silence_rssi_a) & IN_BAND_FILTER;
83
 
        bcn_silence_b =
84
 
                le32_to_cpu(rx_info->beacon_silence_rssi_b) & IN_BAND_FILTER;
85
 
        bcn_silence_c =
86
 
                le32_to_cpu(rx_info->beacon_silence_rssi_c) & IN_BAND_FILTER;
87
 
 
88
 
        if (bcn_silence_a) {
89
 
                total_silence += bcn_silence_a;
90
 
                num_active_rx++;
91
 
        }
92
 
        if (bcn_silence_b) {
93
 
                total_silence += bcn_silence_b;
94
 
                num_active_rx++;
95
 
        }
96
 
        if (bcn_silence_c) {
97
 
                total_silence += bcn_silence_c;
98
 
                num_active_rx++;
99
 
        }
100
 
 
101
 
        /* Average among active antennas */
102
 
        if (num_active_rx)
103
 
                last_rx_noise = (total_silence / num_active_rx) - 107;
104
 
        else
105
 
                last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE;
106
 
 
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,
109
 
                        last_rx_noise);
110
 
}
111
 
 
112
 
#ifdef CONFIG_IWLWIFI_DEBUGFS
113
 
/*
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.
117
 
 */
118
 
static void iwl_accumulative_statistics(struct iwl_priv *priv,
119
 
                                        __le32 *stats)
120
 
{
121
 
        int i, size;
122
 
        __le32 *prev_stats;
123
 
        u32 *accum_stats;
124
 
        u32 *delta, *max_delta;
125
 
        struct statistics_general_common *general, *accum_general;
126
 
        struct statistics_tx *tx, *accum_tx;
127
 
 
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;
139
 
        } else {
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;
149
 
        }
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)
158
 
                                *max_delta = *delta;
159
 
                }
160
 
        }
161
 
 
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;
169
 
}
170
 
#endif
171
 
 
172
 
#define REG_RECALIB_PERIOD (60)
173
 
 
174
 
/**
175
 
 * iwl_good_plcp_health - checks for plcp error.
176
 
 *
177
 
 * When the plcp error is exceeding the thresholds, reset the radio
178
 
 * to improve the throughput.
179
 
 */
180
 
bool iwl_good_plcp_health(struct iwl_priv *priv,
181
 
                                struct iwl_rx_packet *pkt)
182
 
{
183
 
        bool rc = true;
184
 
        int combined_plcp_delta;
185
 
        unsigned int plcp_msec;
186
 
        unsigned long plcp_received_jiffies;
187
 
 
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");
191
 
                return rc;
192
 
        }
193
 
 
194
 
        /*
195
 
         * check for plcp_err and trigger radio reset if it exceeds
196
 
         * the plcp error threshold plcp_delta.
197
 
         */
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;
202
 
        /*
203
 
         * check to make sure plcp_msec is not 0 to prevent division
204
 
         * by zero.
205
 
         */
206
 
        if (plcp_msec) {
207
 
                struct statistics_rx_phy *ofdm;
208
 
                struct statistics_rx_ht_phy *ofdm_ht;
209
 
 
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.
217
 
                                       rx.ofdm.plcp_err)) +
218
 
                           (le32_to_cpu(ofdm_ht->plcp_err) -
219
 
                           le32_to_cpu(priv->_agn.statistics_bt.
220
 
                                       rx.ofdm_ht.plcp_err));
221
 
                } else {
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.
227
 
                                        rx.ofdm.plcp_err)) +
228
 
                            (le32_to_cpu(ofdm_ht->plcp_err) -
229
 
                            le32_to_cpu(priv->_agn.statistics.
230
 
                                        rx.ofdm_ht.plcp_err));
231
 
                }
232
 
 
233
 
                if ((combined_plcp_delta > 0) &&
234
 
                    ((combined_plcp_delta * 100) / plcp_msec) >
235
 
                        priv->cfg->base_params->plcp_delta_threshold) {
236
 
                        /*
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,
245
 
                         *    plcp_msec
246
 
                         */
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);
255
 
 
256
 
                        rc = false;
257
 
                }
258
 
        }
259
 
        return rc;
260
 
}
261
 
 
262
 
void iwl_rx_statistics(struct iwl_priv *priv,
263
 
                              struct iwl_rx_mem_buffer *rxb)
264
 
{
265
 
        int change;
266
 
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
267
 
 
268
 
        if (priv->cfg->bt_params &&
269
 
            priv->cfg->bt_params->bt_statistics) {
270
 
                IWL_DEBUG_RX(priv,
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);
275
 
 
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);
284
 
#endif
285
 
 
286
 
        } else {
287
 
                IWL_DEBUG_RX(priv,
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);
292
 
 
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) !=
297
 
                           (pkt->u.stats.flag &
298
 
                           STATISTICS_REPLY_FLG_HT40_MODE_MSK)));
299
 
#ifdef CONFIG_IWLWIFI_DEBUGFS
300
 
                iwl_accumulative_statistics(priv, (__le32 *)&pkt->u.stats);
301
 
#endif
302
 
 
303
 
        }
304
 
 
305
 
        iwl_recover_from_statistics(priv, pkt);
306
 
 
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));
311
 
        else
312
 
                memcpy(&priv->_agn.statistics, &pkt->u.stats,
313
 
                        sizeof(priv->_agn.statistics));
314
 
 
315
 
        set_bit(STATUS_STATISTICS, &priv->status);
316
 
 
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
320
 
         * us one */
321
 
        mod_timer(&priv->statistics_periodic, jiffies +
322
 
                  msecs_to_jiffies(REG_RECALIB_PERIOD * 1000));
323
 
 
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);
328
 
        }
329
 
        if (priv->cfg->ops->lib->temp_ops.temperature && change)
330
 
                priv->cfg->ops->lib->temp_ops.temperature(priv);
331
 
}
332
 
 
333
 
void iwl_reply_statistics(struct iwl_priv *priv,
334
 
                              struct iwl_rx_mem_buffer *rxb)
335
 
{
336
 
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
337
 
 
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));
352
 
#endif
353
 
                IWL_DEBUG_RX(priv, "Statistics have been cleared\n");
354
 
        }
355
 
        iwl_rx_statistics(priv, rxb);
356
 
}