1 /******************************************************************************
5 * Copyright(c) 2008 - 2012 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
27 *****************************************************************************/
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>
35 #include "iwl-eeprom.h"
36 #include "iwl-debug.h"
39 #include "iwl-power.h"
41 #include "iwl-trans.h"
43 #ifdef CONFIG_IWLWIFI_DEBUGFS
45 #define IWL_TRAFFIC_DUMP_SIZE (IWL_TRAFFIC_ENTRY_SIZE * IWL_TRAFFIC_ENTRIES)
47 void iwl_reset_traffic_log(struct iwl_priv *priv)
49 priv->tx_traffic_idx = 0;
50 priv->rx_traffic_idx = 0;
52 memset(priv->tx_traffic, 0, IWL_TRAFFIC_DUMP_SIZE);
54 memset(priv->rx_traffic, 0, IWL_TRAFFIC_DUMP_SIZE);
57 int iwl_alloc_traffic_mem(struct iwl_priv *priv)
59 u32 traffic_size = IWL_TRAFFIC_DUMP_SIZE;
61 if (iwl_have_debug_level(IWL_DL_TX)) {
62 if (!priv->tx_traffic) {
64 kzalloc(traffic_size, GFP_KERNEL);
65 if (!priv->tx_traffic)
69 if (iwl_have_debug_level(IWL_DL_RX)) {
70 if (!priv->rx_traffic) {
72 kzalloc(traffic_size, GFP_KERNEL);
73 if (!priv->rx_traffic)
77 iwl_reset_traffic_log(priv);
81 void iwl_free_traffic_mem(struct iwl_priv *priv)
83 kfree(priv->tx_traffic);
84 priv->tx_traffic = NULL;
86 kfree(priv->rx_traffic);
87 priv->rx_traffic = NULL;
90 void iwl_dbg_log_tx_data_frame(struct iwl_priv *priv,
91 u16 length, struct ieee80211_hdr *header)
96 if (likely(!iwl_have_debug_level(IWL_DL_TX)))
99 if (!priv->tx_traffic)
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)),
109 priv->tx_traffic_idx =
110 (priv->tx_traffic_idx + 1) % IWL_TRAFFIC_ENTRIES;
114 void iwl_dbg_log_rx_data_frame(struct iwl_priv *priv,
115 u16 length, struct ieee80211_hdr *header)
120 if (likely(!iwl_have_debug_level(IWL_DL_RX)))
123 if (!priv->rx_traffic)
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)),
133 priv->rx_traffic_idx =
134 (priv->rx_traffic_idx + 1) % IWL_TRAFFIC_ENTRIES;
138 const char *get_mgmt_string(int cmd)
140 #define IWL_CMD(x) case x: return #x
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);
161 const char *get_ctrl_string(int cmd)
163 #define IWL_CMD(x) case x: return #x
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);
180 void iwl_clear_traffic_stats(struct iwl_priv *priv)
182 memset(&priv->tx_stats, 0, sizeof(struct traffic_stats));
183 memset(&priv->rx_stats, 0, sizeof(struct traffic_stats));
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.
196 void iwl_update_stats(struct iwl_priv *priv, bool is_tx, __le16 fc, u16 len)
198 struct traffic_stats *stats;
201 stats = &priv->tx_stats;
203 stats = &priv->rx_stats;
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]++;
210 case cpu_to_le16(IEEE80211_STYPE_ASSOC_RESP):
211 stats->mgmt[MANAGEMENT_ASSOC_RESP]++;
213 case cpu_to_le16(IEEE80211_STYPE_REASSOC_REQ):
214 stats->mgmt[MANAGEMENT_REASSOC_REQ]++;
216 case cpu_to_le16(IEEE80211_STYPE_REASSOC_RESP):
217 stats->mgmt[MANAGEMENT_REASSOC_RESP]++;
219 case cpu_to_le16(IEEE80211_STYPE_PROBE_REQ):
220 stats->mgmt[MANAGEMENT_PROBE_REQ]++;
222 case cpu_to_le16(IEEE80211_STYPE_PROBE_RESP):
223 stats->mgmt[MANAGEMENT_PROBE_RESP]++;
225 case cpu_to_le16(IEEE80211_STYPE_BEACON):
226 stats->mgmt[MANAGEMENT_BEACON]++;
228 case cpu_to_le16(IEEE80211_STYPE_ATIM):
229 stats->mgmt[MANAGEMENT_ATIM]++;
231 case cpu_to_le16(IEEE80211_STYPE_DISASSOC):
232 stats->mgmt[MANAGEMENT_DISASSOC]++;
234 case cpu_to_le16(IEEE80211_STYPE_AUTH):
235 stats->mgmt[MANAGEMENT_AUTH]++;
237 case cpu_to_le16(IEEE80211_STYPE_DEAUTH):
238 stats->mgmt[MANAGEMENT_DEAUTH]++;
240 case cpu_to_le16(IEEE80211_STYPE_ACTION):
241 stats->mgmt[MANAGEMENT_ACTION]++;
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]++;
249 case cpu_to_le16(IEEE80211_STYPE_BACK):
250 stats->ctrl[CONTROL_BACK]++;
252 case cpu_to_le16(IEEE80211_STYPE_PSPOLL):
253 stats->ctrl[CONTROL_PSPOLL]++;
255 case cpu_to_le16(IEEE80211_STYPE_RTS):
256 stats->ctrl[CONTROL_RTS]++;
258 case cpu_to_le16(IEEE80211_STYPE_CTS):
259 stats->ctrl[CONTROL_CTS]++;
261 case cpu_to_le16(IEEE80211_STYPE_ACK):
262 stats->ctrl[CONTROL_ACK]++;
264 case cpu_to_le16(IEEE80211_STYPE_CFEND):
265 stats->ctrl[CONTROL_CFEND]++;
267 case cpu_to_le16(IEEE80211_STYPE_CFENDACK):
268 stats->ctrl[CONTROL_CFENDACK]++;
274 stats->data_bytes += len;