Commit | Line | Data |
---|---|---|
df48c323 | 1 | /****************************************************************************** |
df48c323 TW |
2 | * |
3 | * GPL LICENSE SUMMARY | |
4 | * | |
4e318262 | 5 | * Copyright(c) 2008 - 2012 Intel Corporation. All rights reserved. |
df48c323 TW |
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: | |
759ef89f | 25 | * Intel Linux Wireless <ilw@linux.intel.com> |
df48c323 TW |
26 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 |
27 | *****************************************************************************/ | |
28 | ||
29 | #include <linux/kernel.h> | |
30 | #include <linux/module.h> | |
d43c36dc | 31 | #include <linux/sched.h> |
5a0e3ad6 | 32 | #include <linux/slab.h> |
1d0a082d | 33 | #include <net/mac80211.h> |
df48c323 | 34 | |
6bc913bd | 35 | #include "iwl-eeprom.h" |
19335774 | 36 | #include "iwl-debug.h" |
df48c323 | 37 | #include "iwl-core.h" |
b661c819 | 38 | #include "iwl-io.h" |
5da4b55f | 39 | #include "iwl-power.h" |
48f20d35 | 40 | #include "iwl-shared.h" |
9d143e9a | 41 | #include "iwl-agn.h" |
bdfbf092 | 42 | #include "iwl-trans.h" |
df48c323 | 43 | |
727882d6 | 44 | |
d8052319 | 45 | |
20594eb0 WYG |
46 | #ifdef CONFIG_IWLWIFI_DEBUGFS |
47 | ||
48 | #define IWL_TRAFFIC_DUMP_SIZE (IWL_TRAFFIC_ENTRY_SIZE * IWL_TRAFFIC_ENTRIES) | |
49 | ||
50 | void iwl_reset_traffic_log(struct iwl_priv *priv) | |
51 | { | |
52 | priv->tx_traffic_idx = 0; | |
53 | priv->rx_traffic_idx = 0; | |
54 | if (priv->tx_traffic) | |
55 | memset(priv->tx_traffic, 0, IWL_TRAFFIC_DUMP_SIZE); | |
56 | if (priv->rx_traffic) | |
57 | memset(priv->rx_traffic, 0, IWL_TRAFFIC_DUMP_SIZE); | |
58 | } | |
59 | ||
60 | int iwl_alloc_traffic_mem(struct iwl_priv *priv) | |
61 | { | |
62 | u32 traffic_size = IWL_TRAFFIC_DUMP_SIZE; | |
63 | ||
a8bceb39 | 64 | if (iwl_have_debug_level(IWL_DL_TX)) { |
20594eb0 WYG |
65 | if (!priv->tx_traffic) { |
66 | priv->tx_traffic = | |
67 | kzalloc(traffic_size, GFP_KERNEL); | |
68 | if (!priv->tx_traffic) | |
69 | return -ENOMEM; | |
70 | } | |
71 | } | |
a8bceb39 | 72 | if (iwl_have_debug_level(IWL_DL_RX)) { |
20594eb0 WYG |
73 | if (!priv->rx_traffic) { |
74 | priv->rx_traffic = | |
75 | kzalloc(traffic_size, GFP_KERNEL); | |
76 | if (!priv->rx_traffic) | |
77 | return -ENOMEM; | |
78 | } | |
79 | } | |
80 | iwl_reset_traffic_log(priv); | |
81 | return 0; | |
82 | } | |
20594eb0 WYG |
83 | |
84 | void iwl_free_traffic_mem(struct iwl_priv *priv) | |
85 | { | |
86 | kfree(priv->tx_traffic); | |
87 | priv->tx_traffic = NULL; | |
88 | ||
89 | kfree(priv->rx_traffic); | |
90 | priv->rx_traffic = NULL; | |
91 | } | |
20594eb0 WYG |
92 | |
93 | void iwl_dbg_log_tx_data_frame(struct iwl_priv *priv, | |
94 | u16 length, struct ieee80211_hdr *header) | |
95 | { | |
96 | __le16 fc; | |
97 | u16 len; | |
98 | ||
a8bceb39 | 99 | if (likely(!iwl_have_debug_level(IWL_DL_TX))) |
20594eb0 WYG |
100 | return; |
101 | ||
102 | if (!priv->tx_traffic) | |
103 | return; | |
104 | ||
105 | fc = header->frame_control; | |
106 | if (ieee80211_is_data(fc)) { | |
107 | len = (length > IWL_TRAFFIC_ENTRY_SIZE) | |
108 | ? IWL_TRAFFIC_ENTRY_SIZE : length; | |
109 | memcpy((priv->tx_traffic + | |
110 | (priv->tx_traffic_idx * IWL_TRAFFIC_ENTRY_SIZE)), | |
111 | header, len); | |
112 | priv->tx_traffic_idx = | |
113 | (priv->tx_traffic_idx + 1) % IWL_TRAFFIC_ENTRIES; | |
114 | } | |
115 | } | |
20594eb0 WYG |
116 | |
117 | void iwl_dbg_log_rx_data_frame(struct iwl_priv *priv, | |
118 | u16 length, struct ieee80211_hdr *header) | |
119 | { | |
120 | __le16 fc; | |
121 | u16 len; | |
122 | ||
a8bceb39 | 123 | if (likely(!iwl_have_debug_level(IWL_DL_RX))) |
20594eb0 WYG |
124 | return; |
125 | ||
126 | if (!priv->rx_traffic) | |
127 | return; | |
128 | ||
129 | fc = header->frame_control; | |
130 | if (ieee80211_is_data(fc)) { | |
131 | len = (length > IWL_TRAFFIC_ENTRY_SIZE) | |
132 | ? IWL_TRAFFIC_ENTRY_SIZE : length; | |
133 | memcpy((priv->rx_traffic + | |
134 | (priv->rx_traffic_idx * IWL_TRAFFIC_ENTRY_SIZE)), | |
135 | header, len); | |
136 | priv->rx_traffic_idx = | |
137 | (priv->rx_traffic_idx + 1) % IWL_TRAFFIC_ENTRIES; | |
138 | } | |
139 | } | |
22fdf3c9 WYG |
140 | |
141 | const char *get_mgmt_string(int cmd) | |
142 | { | |
d9fb6465 | 143 | #define IWL_CMD(x) case x: return #x |
22fdf3c9 WYG |
144 | switch (cmd) { |
145 | IWL_CMD(MANAGEMENT_ASSOC_REQ); | |
146 | IWL_CMD(MANAGEMENT_ASSOC_RESP); | |
147 | IWL_CMD(MANAGEMENT_REASSOC_REQ); | |
148 | IWL_CMD(MANAGEMENT_REASSOC_RESP); | |
149 | IWL_CMD(MANAGEMENT_PROBE_REQ); | |
150 | IWL_CMD(MANAGEMENT_PROBE_RESP); | |
151 | IWL_CMD(MANAGEMENT_BEACON); | |
152 | IWL_CMD(MANAGEMENT_ATIM); | |
153 | IWL_CMD(MANAGEMENT_DISASSOC); | |
154 | IWL_CMD(MANAGEMENT_AUTH); | |
155 | IWL_CMD(MANAGEMENT_DEAUTH); | |
156 | IWL_CMD(MANAGEMENT_ACTION); | |
157 | default: | |
158 | return "UNKNOWN"; | |
159 | ||
160 | } | |
d9fb6465 | 161 | #undef IWL_CMD |
22fdf3c9 WYG |
162 | } |
163 | ||
164 | const char *get_ctrl_string(int cmd) | |
165 | { | |
d9fb6465 | 166 | #define IWL_CMD(x) case x: return #x |
22fdf3c9 WYG |
167 | switch (cmd) { |
168 | IWL_CMD(CONTROL_BACK_REQ); | |
169 | IWL_CMD(CONTROL_BACK); | |
170 | IWL_CMD(CONTROL_PSPOLL); | |
171 | IWL_CMD(CONTROL_RTS); | |
172 | IWL_CMD(CONTROL_CTS); | |
173 | IWL_CMD(CONTROL_ACK); | |
174 | IWL_CMD(CONTROL_CFEND); | |
175 | IWL_CMD(CONTROL_CFENDACK); | |
176 | default: | |
177 | return "UNKNOWN"; | |
178 | ||
179 | } | |
d9fb6465 | 180 | #undef IWL_CMD |
22fdf3c9 WYG |
181 | } |
182 | ||
7163b8a4 | 183 | void iwl_clear_traffic_stats(struct iwl_priv *priv) |
22fdf3c9 WYG |
184 | { |
185 | memset(&priv->tx_stats, 0, sizeof(struct traffic_stats)); | |
22fdf3c9 WYG |
186 | memset(&priv->rx_stats, 0, sizeof(struct traffic_stats)); |
187 | } | |
188 | ||
189 | /* | |
190 | * if CONFIG_IWLWIFI_DEBUGFS defined, iwl_update_stats function will | |
191 | * record all the MGMT, CTRL and DATA pkt for both TX and Rx pass. | |
192 | * Use debugFs to display the rx/rx_statistics | |
193 | * if CONFIG_IWLWIFI_DEBUGFS not being defined, then no MGMT and CTRL | |
194 | * information will be recorded, but DATA pkt still will be recorded | |
195 | * for the reason of iwl_led.c need to control the led blinking based on | |
196 | * number of tx and rx data. | |
197 | * | |
198 | */ | |
199 | void iwl_update_stats(struct iwl_priv *priv, bool is_tx, __le16 fc, u16 len) | |
200 | { | |
201 | struct traffic_stats *stats; | |
202 | ||
203 | if (is_tx) | |
204 | stats = &priv->tx_stats; | |
205 | else | |
206 | stats = &priv->rx_stats; | |
207 | ||
208 | if (ieee80211_is_mgmt(fc)) { | |
209 | switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) { | |
210 | case cpu_to_le16(IEEE80211_STYPE_ASSOC_REQ): | |
211 | stats->mgmt[MANAGEMENT_ASSOC_REQ]++; | |
212 | break; | |
213 | case cpu_to_le16(IEEE80211_STYPE_ASSOC_RESP): | |
214 | stats->mgmt[MANAGEMENT_ASSOC_RESP]++; | |
215 | break; | |
216 | case cpu_to_le16(IEEE80211_STYPE_REASSOC_REQ): | |
217 | stats->mgmt[MANAGEMENT_REASSOC_REQ]++; | |
218 | break; | |
219 | case cpu_to_le16(IEEE80211_STYPE_REASSOC_RESP): | |
220 | stats->mgmt[MANAGEMENT_REASSOC_RESP]++; | |
221 | break; | |
222 | case cpu_to_le16(IEEE80211_STYPE_PROBE_REQ): | |
223 | stats->mgmt[MANAGEMENT_PROBE_REQ]++; | |
224 | break; | |
225 | case cpu_to_le16(IEEE80211_STYPE_PROBE_RESP): | |
226 | stats->mgmt[MANAGEMENT_PROBE_RESP]++; | |
227 | break; | |
228 | case cpu_to_le16(IEEE80211_STYPE_BEACON): | |
229 | stats->mgmt[MANAGEMENT_BEACON]++; | |
230 | break; | |
231 | case cpu_to_le16(IEEE80211_STYPE_ATIM): | |
232 | stats->mgmt[MANAGEMENT_ATIM]++; | |
233 | break; | |
234 | case cpu_to_le16(IEEE80211_STYPE_DISASSOC): | |
235 | stats->mgmt[MANAGEMENT_DISASSOC]++; | |
236 | break; | |
237 | case cpu_to_le16(IEEE80211_STYPE_AUTH): | |
238 | stats->mgmt[MANAGEMENT_AUTH]++; | |
239 | break; | |
240 | case cpu_to_le16(IEEE80211_STYPE_DEAUTH): | |
241 | stats->mgmt[MANAGEMENT_DEAUTH]++; | |
242 | break; | |
243 | case cpu_to_le16(IEEE80211_STYPE_ACTION): | |
244 | stats->mgmt[MANAGEMENT_ACTION]++; | |
245 | break; | |
246 | } | |
247 | } else if (ieee80211_is_ctl(fc)) { | |
248 | switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) { | |
249 | case cpu_to_le16(IEEE80211_STYPE_BACK_REQ): | |
250 | stats->ctrl[CONTROL_BACK_REQ]++; | |
251 | break; | |
252 | case cpu_to_le16(IEEE80211_STYPE_BACK): | |
253 | stats->ctrl[CONTROL_BACK]++; | |
254 | break; | |
255 | case cpu_to_le16(IEEE80211_STYPE_PSPOLL): | |
256 | stats->ctrl[CONTROL_PSPOLL]++; | |
257 | break; | |
258 | case cpu_to_le16(IEEE80211_STYPE_RTS): | |
259 | stats->ctrl[CONTROL_RTS]++; | |
260 | break; | |
261 | case cpu_to_le16(IEEE80211_STYPE_CTS): | |
262 | stats->ctrl[CONTROL_CTS]++; | |
263 | break; | |
264 | case cpu_to_le16(IEEE80211_STYPE_ACK): | |
265 | stats->ctrl[CONTROL_ACK]++; | |
266 | break; | |
267 | case cpu_to_le16(IEEE80211_STYPE_CFEND): | |
268 | stats->ctrl[CONTROL_CFEND]++; | |
269 | break; | |
270 | case cpu_to_le16(IEEE80211_STYPE_CFENDACK): | |
271 | stats->ctrl[CONTROL_CFENDACK]++; | |
272 | break; | |
273 | } | |
274 | } else { | |
275 | /* data */ | |
276 | stats->data_cnt++; | |
277 | stats->data_bytes += len; | |
278 | } | |
279 | } | |
20594eb0 WYG |
280 | #endif |
281 | ||
317d09f7 WYG |
282 | int iwl_cmd_echo_test(struct iwl_priv *priv) |
283 | { | |
7e4005cc | 284 | int ret; |
317d09f7 WYG |
285 | struct iwl_host_cmd cmd = { |
286 | .id = REPLY_ECHO, | |
89db3b97 | 287 | .len = { 0 }, |
317d09f7 WYG |
288 | .flags = CMD_SYNC, |
289 | }; | |
290 | ||
e10a0533 | 291 | ret = iwl_dvm_send_cmd(priv, &cmd); |
7e4005cc WYG |
292 | if (ret) |
293 | IWL_ERR(priv, "echo testing fail: 0X%x\n", ret); | |
294 | else | |
295 | IWL_DEBUG_INFO(priv, "echo testing pass\n"); | |
296 | return ret; | |
317d09f7 | 297 | } |