aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/iwl-rx.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-rx.c')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-rx.c1029
1 files changed, 1029 insertions, 0 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c
new file mode 100644
index 00000000000..732f01b565d
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-rx.c
@@ -0,0 +1,1029 @@
1/******************************************************************************
2 *
3 * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved.
4 *
5 * Portions of this file are derived from the ipw3945 project, as well
6 * as portions of the ieee80211 subsystem header files.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of version 2 of the GNU General Public License as
10 * published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License along with
18 * this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
20 *
21 * The full GNU General Public License is included in this distribution in the
22 * file called LICENSE.
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/etherdevice.h>
31#include <linux/slab.h>
32#include <linux/sched.h>
33#include <net/mac80211.h>
34#include <asm/unaligned.h>
35#include "iwl-eeprom.h"
36#include "iwl-dev.h"
37#include "iwl-core.h"
38#include "iwl-sta.h"
39#include "iwl-io.h"
40#include "iwl-helpers.h"
41#include "iwl-agn-calib.h"
42#include "iwl-agn.h"
43
44
45/******************************************************************************
46 *
47 * Generic RX handler implementations
48 *
49 ******************************************************************************/
50
51static void iwl_rx_reply_error(struct iwl_priv *priv,
52 struct iwl_rx_mem_buffer *rxb)
53{
54 struct iwl_rx_packet *pkt = rxb_addr(rxb);
55
56 IWL_ERR(priv, "Error Reply type 0x%08X cmd %s (0x%02X) "
57 "seq 0x%04X ser 0x%08X\n",
58 le32_to_cpu(pkt->u.err_resp.error_type),
59 get_cmd_string(pkt->u.err_resp.cmd_id),
60 pkt->u.err_resp.cmd_id,
61 le16_to_cpu(pkt->u.err_resp.bad_cmd_seq_num),
62 le32_to_cpu(pkt->u.err_resp.error_info));
63}
64
65static void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
66{
67 struct iwl_rx_packet *pkt = rxb_addr(rxb);
68 struct iwl_csa_notification *csa = &(pkt->u.csa_notif);
69 /*
70 * MULTI-FIXME
71 * See iwl_mac_channel_switch.
72 */
73 struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
74 struct iwl_rxon_cmd *rxon = (void *)&ctx->active;
75
76 if (!test_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status))
77 return;
78
79 if (!le32_to_cpu(csa->status) && csa->channel == priv->switch_channel) {
80 rxon->channel = csa->channel;
81 ctx->staging.channel = csa->channel;
82 IWL_DEBUG_11H(priv, "CSA notif: channel %d\n",
83 le16_to_cpu(csa->channel));
84 iwl_chswitch_done(priv, true);
85 } else {
86 IWL_ERR(priv, "CSA notif (fail) : channel %d\n",
87 le16_to_cpu(csa->channel));
88 iwl_chswitch_done(priv, false);
89 }
90}
91
92
93static void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv,
94 struct iwl_rx_mem_buffer *rxb)
95{
96 struct iwl_rx_packet *pkt = rxb_addr(rxb);
97 struct iwl_spectrum_notification *report = &(pkt->u.spectrum_notif);
98
99 if (!report->state) {
100 IWL_DEBUG_11H(priv,
101 "Spectrum Measure Notification: Start\n");
102 return;
103 }
104
105 memcpy(&priv->measure_report, report, sizeof(*report));
106 priv->measurement_status |= MEASUREMENT_READY;
107}
108
109static void iwl_rx_pm_sleep_notif(struct iwl_priv *priv,
110 struct iwl_rx_mem_buffer *rxb)
111{
112#ifdef CONFIG_IWLWIFI_DEBUG
113 struct iwl_rx_packet *pkt = rxb_addr(rxb);
114 struct iwl_sleep_notification *sleep = &(pkt->u.sleep_notif);
115 IWL_DEBUG_RX(priv, "sleep mode: %d, src: %d\n",
116 sleep->pm_sleep_mode, sleep->pm_wakeup_src);
117#endif
118}
119
120static void iwl_rx_pm_debug_statistics_notif(struct iwl_priv *priv,
121 struct iwl_rx_mem_buffer *rxb)
122{
123 struct iwl_rx_packet *pkt = rxb_addr(rxb);
124 u32 len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
125 IWL_DEBUG_RADIO(priv, "Dumping %d bytes of unhandled "
126 "notification for %s:\n", len,
127 get_cmd_string(pkt->hdr.cmd));
128 iwl_print_hex_dump(priv, IWL_DL_RADIO, pkt->u.raw, len);
129}
130
131static void iwl_rx_beacon_notif(struct iwl_priv *priv,
132 struct iwl_rx_mem_buffer *rxb)
133{
134 struct iwl_rx_packet *pkt = rxb_addr(rxb);
135 struct iwlagn_beacon_notif *beacon = (void *)pkt->u.raw;
136#ifdef CONFIG_IWLWIFI_DEBUG
137 u16 status = le16_to_cpu(beacon->beacon_notify_hdr.status.status);
138 u8 rate = iwl_hw_get_rate(beacon->beacon_notify_hdr.rate_n_flags);
139
140 IWL_DEBUG_RX(priv, "beacon status %#x, retries:%d ibssmgr:%d "
141 "tsf:0x%.8x%.8x rate:%d\n",
142 status & TX_STATUS_MSK,
143 beacon->beacon_notify_hdr.failure_frame,
144 le32_to_cpu(beacon->ibss_mgr_status),
145 le32_to_cpu(beacon->high_tsf),
146 le32_to_cpu(beacon->low_tsf), rate);
147#endif
148
149 priv->ibss_manager = le32_to_cpu(beacon->ibss_mgr_status);
150
151 if (!test_bit(STATUS_EXIT_PENDING, &priv->status))
152 queue_work(priv->workqueue, &priv->beacon_update);
153}
154
155/* the threshold ratio of actual_ack_cnt to expected_ack_cnt in percent */
156#define ACK_CNT_RATIO (50)
157#define BA_TIMEOUT_CNT (5)
158#define BA_TIMEOUT_MAX (16)
159
160/**
161 * iwl_good_ack_health - checks for ACK count ratios, BA timeout retries.
162 *
163 * When the ACK count ratio is low and aggregated BA timeout retries exceeding
164 * the BA_TIMEOUT_MAX, reload firmware and bring system back to normal
165 * operation state.
166 */
167static bool iwl_good_ack_health(struct iwl_priv *priv,
168 struct statistics_tx *cur)
169{
170 int actual_delta, expected_delta, ba_timeout_delta;
171 struct statistics_tx *old;
172
173 if (priv->agg_tids_count)
174 return true;
175
176 old = &priv->statistics.tx;
177
178 actual_delta = le32_to_cpu(cur->actual_ack_cnt) -
179 le32_to_cpu(old->actual_ack_cnt);
180 expected_delta = le32_to_cpu(cur->expected_ack_cnt) -
181 le32_to_cpu(old->expected_ack_cnt);
182
183 /* Values should not be negative, but we do not trust the firmware */
184 if (actual_delta <= 0 || expected_delta <= 0)
185 return true;
186
187 ba_timeout_delta = le32_to_cpu(cur->agg.ba_timeout) -
188 le32_to_cpu(old->agg.ba_timeout);
189
190 if ((actual_delta * 100 / expected_delta) < ACK_CNT_RATIO &&
191 ba_timeout_delta > BA_TIMEOUT_CNT) {
192 IWL_DEBUG_RADIO(priv, "deltas: actual %d expected %d ba_timeout %d\n",
193 actual_delta, expected_delta, ba_timeout_delta);
194
195#ifdef CONFIG_IWLWIFI_DEBUGFS
196 /*
197 * This is ifdef'ed on DEBUGFS because otherwise the
198 * statistics aren't available. If DEBUGFS is set but
199 * DEBUG is not, these will just compile out.
200 */
201 IWL_DEBUG_RADIO(priv, "rx_detected_cnt delta %d\n",
202 priv->delta_stats.tx.rx_detected_cnt);
203 IWL_DEBUG_RADIO(priv,
204 "ack_or_ba_timeout_collision delta %d\n",
205 priv->delta_stats.tx.ack_or_ba_timeout_collision);
206#endif