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