drivers/net: Add export.h to files using EXPORT_SYMBOL/THIS_MODULE
[pandora-kernel.git] / drivers / net / wireless / iwlegacy / iwl-debugfs.c
1 /******************************************************************************
2  *
3  * GPL LICENSE SUMMARY
4  *
5  * Copyright(c) 2008 - 2011 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 #include <linux/ieee80211.h>
29 #include <linux/export.h>
30 #include <net/mac80211.h>
31
32
33 #include "iwl-dev.h"
34 #include "iwl-debug.h"
35 #include "iwl-core.h"
36 #include "iwl-io.h"
37
38 /* create and remove of files */
39 #define DEBUGFS_ADD_FILE(name, parent, mode) do {                       \
40         if (!debugfs_create_file(#name, mode, parent, priv,             \
41                          &iwl_legacy_dbgfs_##name##_ops))               \
42                 goto err;                                               \
43 } while (0)
44
45 #define DEBUGFS_ADD_BOOL(name, parent, ptr) do {                        \
46         struct dentry *__tmp;                                           \
47         __tmp = debugfs_create_bool(#name, S_IWUSR | S_IRUSR,           \
48                                     parent, ptr);                       \
49         if (IS_ERR(__tmp) || !__tmp)                                    \
50                 goto err;                                               \
51 } while (0)
52
53 #define DEBUGFS_ADD_X32(name, parent, ptr) do {                         \
54         struct dentry *__tmp;                                           \
55         __tmp = debugfs_create_x32(#name, S_IWUSR | S_IRUSR,            \
56                                    parent, ptr);                        \
57         if (IS_ERR(__tmp) || !__tmp)                                    \
58                 goto err;                                               \
59 } while (0)
60
61 /* file operation */
62 #define DEBUGFS_READ_FUNC(name)                                         \
63 static ssize_t iwl_legacy_dbgfs_##name##_read(struct file *file,               \
64                                         char __user *user_buf,          \
65                                         size_t count, loff_t *ppos);
66
67 #define DEBUGFS_WRITE_FUNC(name)                                        \
68 static ssize_t iwl_legacy_dbgfs_##name##_write(struct file *file,              \
69                                         const char __user *user_buf,    \
70                                         size_t count, loff_t *ppos);
71
72
73 static int
74 iwl_legacy_dbgfs_open_file_generic(struct inode *inode, struct file *file)
75 {
76         file->private_data = inode->i_private;
77         return 0;
78 }
79
80 #define DEBUGFS_READ_FILE_OPS(name)                             \
81         DEBUGFS_READ_FUNC(name);                                        \
82 static const struct file_operations iwl_legacy_dbgfs_##name##_ops = {   \
83         .read = iwl_legacy_dbgfs_##name##_read,                         \
84         .open = iwl_legacy_dbgfs_open_file_generic,                     \
85         .llseek = generic_file_llseek,                                  \
86 };
87
88 #define DEBUGFS_WRITE_FILE_OPS(name)                            \
89         DEBUGFS_WRITE_FUNC(name);                                       \
90 static const struct file_operations iwl_legacy_dbgfs_##name##_ops = {   \
91         .write = iwl_legacy_dbgfs_##name##_write,                       \
92         .open = iwl_legacy_dbgfs_open_file_generic,                     \
93         .llseek = generic_file_llseek,                                  \
94 };
95
96 #define DEBUGFS_READ_WRITE_FILE_OPS(name)                           \
97         DEBUGFS_READ_FUNC(name);                                        \
98         DEBUGFS_WRITE_FUNC(name);                                       \
99 static const struct file_operations iwl_legacy_dbgfs_##name##_ops = {   \
100         .write = iwl_legacy_dbgfs_##name##_write,                       \
101         .read = iwl_legacy_dbgfs_##name##_read,                         \
102         .open = iwl_legacy_dbgfs_open_file_generic,                     \
103         .llseek = generic_file_llseek,                                  \
104 };
105
106 static ssize_t iwl_legacy_dbgfs_tx_statistics_read(struct file *file,
107                                                 char __user *user_buf,
108                                                 size_t count, loff_t *ppos) {
109
110         struct iwl_priv *priv = file->private_data;
111         char *buf;
112         int pos = 0;
113
114         int cnt;
115         ssize_t ret;
116         const size_t bufsz = 100 +
117                 sizeof(char) * 50 * (MANAGEMENT_MAX + CONTROL_MAX);
118         buf = kzalloc(bufsz, GFP_KERNEL);
119         if (!buf)
120                 return -ENOMEM;
121         pos += scnprintf(buf + pos, bufsz - pos, "Management:\n");
122         for (cnt = 0; cnt < MANAGEMENT_MAX; cnt++) {
123                 pos += scnprintf(buf + pos, bufsz - pos,
124                                  "\t%25s\t\t: %u\n",
125                                  iwl_legacy_get_mgmt_string(cnt),
126                                  priv->tx_stats.mgmt[cnt]);
127         }
128         pos += scnprintf(buf + pos, bufsz - pos, "Control\n");
129         for (cnt = 0; cnt < CONTROL_MAX; cnt++) {
130                 pos += scnprintf(buf + pos, bufsz - pos,
131                                  "\t%25s\t\t: %u\n",
132                                  iwl_legacy_get_ctrl_string(cnt),
133                                  priv->tx_stats.ctrl[cnt]);
134         }
135         pos += scnprintf(buf + pos, bufsz - pos, "Data:\n");
136         pos += scnprintf(buf + pos, bufsz - pos, "\tcnt: %u\n",
137                          priv->tx_stats.data_cnt);
138         pos += scnprintf(buf + pos, bufsz - pos, "\tbytes: %llu\n",
139                          priv->tx_stats.data_bytes);
140         ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
141         kfree(buf);
142         return ret;
143 }
144
145 static ssize_t
146 iwl_legacy_dbgfs_clear_traffic_statistics_write(struct file *file,
147                                         const char __user *user_buf,
148                                         size_t count, loff_t *ppos)
149 {
150         struct iwl_priv *priv = file->private_data;
151         u32 clear_flag;
152         char buf[8];
153         int buf_size;
154
155         memset(buf, 0, sizeof(buf));
156         buf_size = min(count, sizeof(buf) -  1);
157         if (copy_from_user(buf, user_buf, buf_size))
158                 return -EFAULT;
159         if (sscanf(buf, "%x", &clear_flag) != 1)
160                 return -EFAULT;
161         iwl_legacy_clear_traffic_stats(priv);
162
163         return count;
164 }
165
166 static ssize_t iwl_legacy_dbgfs_rx_statistics_read(struct file *file,
167                                                 char __user *user_buf,
168                                                 size_t count, loff_t *ppos) {
169
170         struct iwl_priv *priv = file->private_data;
171         char *buf;
172         int pos = 0;
173         int cnt;
174         ssize_t ret;
175         const size_t bufsz = 100 +
176                 sizeof(char) * 50 * (MANAGEMENT_MAX + CONTROL_MAX);
177         buf = kzalloc(bufsz, GFP_KERNEL);
178         if (!buf)
179                 return -ENOMEM;
180
181         pos += scnprintf(buf + pos, bufsz - pos, "Management:\n");
182         for (cnt = 0; cnt < MANAGEMENT_MAX; cnt++) {
183                 pos += scnprintf(buf + pos, bufsz - pos,
184                                  "\t%25s\t\t: %u\n",
185                                  iwl_legacy_get_mgmt_string(cnt),
186                                  priv->rx_stats.mgmt[cnt]);
187         }
188         pos += scnprintf(buf + pos, bufsz - pos, "Control:\n");
189         for (cnt = 0; cnt < CONTROL_MAX; cnt++) {
190                 pos += scnprintf(buf + pos, bufsz - pos,
191                                  "\t%25s\t\t: %u\n",
192                                  iwl_legacy_get_ctrl_string(cnt),
193                                  priv->rx_stats.ctrl[cnt]);
194         }
195         pos += scnprintf(buf + pos, bufsz - pos, "Data:\n");
196         pos += scnprintf(buf + pos, bufsz - pos, "\tcnt: %u\n",
197                          priv->rx_stats.data_cnt);
198         pos += scnprintf(buf + pos, bufsz - pos, "\tbytes: %llu\n",
199                          priv->rx_stats.data_bytes);
200
201         ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
202         kfree(buf);
203         return ret;
204 }
205
206 #define BYTE1_MASK 0x000000ff;
207 #define BYTE2_MASK 0x0000ffff;
208 #define BYTE3_MASK 0x00ffffff;
209 static ssize_t iwl_legacy_dbgfs_sram_read(struct file *file,
210                                         char __user *user_buf,
211                                         size_t count, loff_t *ppos)
212 {
213         u32 val;
214         char *buf;
215         ssize_t ret;
216         int i;
217         int pos = 0;
218         struct iwl_priv *priv = file->private_data;
219         size_t bufsz;
220
221         /* default is to dump the entire data segment */
222         if (!priv->dbgfs_sram_offset && !priv->dbgfs_sram_len) {
223                 priv->dbgfs_sram_offset = 0x800000;
224                 if (priv->ucode_type == UCODE_INIT)
225                         priv->dbgfs_sram_len = priv->ucode_init_data.len;
226                 else
227                         priv->dbgfs_sram_len = priv->ucode_data.len;
228         }
229         bufsz =  30 + priv->dbgfs_sram_len * sizeof(char) * 10;
230         buf = kmalloc(bufsz, GFP_KERNEL);
231         if (!buf)
232                 return -ENOMEM;
233         pos += scnprintf(buf + pos, bufsz - pos, "sram_len: 0x%x\n",
234                         priv->dbgfs_sram_len);
235         pos += scnprintf(buf + pos, bufsz - pos, "sram_offset: 0x%x\n",
236                         priv->dbgfs_sram_offset);
237         for (i = priv->dbgfs_sram_len; i > 0; i -= 4) {
238                 val = iwl_legacy_read_targ_mem(priv, priv->dbgfs_sram_offset + \
239                                         priv->dbgfs_sram_len - i);
240                 if (i < 4) {
241                         switch (i) {
242                         case 1:
243                                 val &= BYTE1_MASK;
244                                 break;
245                         case 2:
246                                 val &= BYTE2_MASK;
247                                 break;
248                         case 3:
249                                 val &= BYTE3_MASK;
250                                 break;
251                         }
252                 }
253                 if (!(i % 16))
254                         pos += scnprintf(buf + pos, bufsz - pos, "\n");
255                 pos += scnprintf(buf + pos, bufsz - pos, "0x%08x ", val);
256         }
257         pos += scnprintf(buf + pos, bufsz - pos, "\n");
258
259         ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
260         kfree(buf);
261         return ret;
262 }
263
264 static ssize_t iwl_legacy_dbgfs_sram_write(struct file *file,
265                                         const char __user *user_buf,
266                                         size_t count, loff_t *ppos)
267 {
268         struct iwl_priv *priv = file->private_data;
269         char buf[64];
270         int buf_size;
271         u32 offset, len;
272
273         memset(buf, 0, sizeof(buf));
274         buf_size = min(count, sizeof(buf) -  1);
275         if (copy_from_user(buf, user_buf, buf_size))
276                 return -EFAULT;
277
278         if (sscanf(buf, "%x,%x", &offset, &len) == 2) {
279                 priv->dbgfs_sram_offset = offset;
280                 priv->dbgfs_sram_len = len;
281         } else {
282                 priv->dbgfs_sram_offset = 0;
283                 priv->dbgfs_sram_len = 0;
284         }
285
286         return count;
287 }
288
289 static ssize_t
290 iwl_legacy_dbgfs_stations_read(struct file *file, char __user *user_buf,
291                                         size_t count, loff_t *ppos)
292 {
293         struct iwl_priv *priv = file->private_data;
294         struct iwl_station_entry *station;
295         int max_sta = priv->hw_params.max_stations;
296         char *buf;
297         int i, j, pos = 0;
298         ssize_t ret;
299         /* Add 30 for initial string */
300         const size_t bufsz = 30 + sizeof(char) * 500 * (priv->num_stations);
301
302         buf = kmalloc(bufsz, GFP_KERNEL);
303         if (!buf)
304                 return -ENOMEM;
305
306         pos += scnprintf(buf + pos, bufsz - pos, "num of stations: %d\n\n",
307                         priv->num_stations);
308
309         for (i = 0; i < max_sta; i++) {
310                 station = &priv->stations[i];
311                 if (!station->used)
312                         continue;
313                 pos += scnprintf(buf + pos, bufsz - pos,
314                                  "station %d - addr: %pM, flags: %#x\n",
315                                  i, station->sta.sta.addr,
316                                  station->sta.station_flags_msk);
317                 pos += scnprintf(buf + pos, bufsz - pos,
318                                 "TID\tseq_num\ttxq_id\tframes\ttfds\t");
319                 pos += scnprintf(buf + pos, bufsz - pos,
320                                 "start_idx\tbitmap\t\t\trate_n_flags\n");
321
322                 for (j = 0; j < MAX_TID_COUNT; j++) {
323                         pos += scnprintf(buf + pos, bufsz - pos,
324                                 "%d:\t%#x\t%#x\t%u\t%u\t%u\t\t%#.16llx\t%#x",
325                                 j, station->tid[j].seq_number,
326                                 station->tid[j].agg.txq_id,
327                                 station->tid[j].agg.frame_count,
328                                 station->tid[j].tfds_in_queue,
329                                 station->tid[j].agg.start_idx,
330                                 station->tid[j].agg.bitmap,
331                                 station->tid[j].agg.rate_n_flags);
332
333                         if (station->tid[j].agg.wait_for_ba)
334                                 pos += scnprintf(buf + pos, bufsz - pos,
335                                                  " - waitforba");
336                         pos += scnprintf(buf + pos, bufsz - pos, "\n");
337                 }
338
339                 pos += scnprintf(buf + pos, bufsz - pos, "\n");
340         }
341
342         ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
343         kfree(buf);
344         return ret;
345 }
346
347 static ssize_t iwl_legacy_dbgfs_nvm_read(struct file *file,
348                                        char __user *user_buf,
349                                        size_t count,
350                                        loff_t *ppos)
351 {
352         ssize_t ret;
353         struct iwl_priv *priv = file->private_data;
354         int pos = 0, ofs = 0, buf_size = 0;
355         const u8 *ptr;
356         char *buf;
357         u16 eeprom_ver;
358         size_t eeprom_len = priv->cfg->base_params->eeprom_size;
359         buf_size = 4 * eeprom_len + 256;
360
361         if (eeprom_len % 16) {
362                 IWL_ERR(priv, "NVM size is not multiple of 16.\n");
363                 return -ENODATA;
364         }
365
366         ptr = priv->eeprom;
367         if (!ptr) {
368                 IWL_ERR(priv, "Invalid EEPROM memory\n");
369                 return -ENOMEM;
370         }
371
372         /* 4 characters for byte 0xYY */
373         buf = kzalloc(buf_size, GFP_KERNEL);
374         if (!buf) {
375                 IWL_ERR(priv, "Can not allocate Buffer\n");
376                 return -ENOMEM;
377         }
378         eeprom_ver = iwl_legacy_eeprom_query16(priv, EEPROM_VERSION);
379         pos += scnprintf(buf + pos, buf_size - pos, "EEPROM "
380                         "version: 0x%x\n", eeprom_ver);
381         for (ofs = 0 ; ofs < eeprom_len ; ofs += 16) {
382                 pos += scnprintf(buf + pos, buf_size - pos, "0x%.4x ", ofs);
383                 hex_dump_to_buffer(ptr + ofs, 16 , 16, 2, buf + pos,
384                                    buf_size - pos, 0);
385                 pos += strlen(buf + pos);
386                 if (buf_size - pos > 0)
387                         buf[pos++] = '\n';
388         }
389
390         ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
391         kfree(buf);
392         return ret;
393 }
394
395 static ssize_t
396 iwl_legacy_dbgfs_channels_read(struct file *file, char __user *user_buf,
397                                        size_t count, loff_t *ppos)
398 {
399         struct iwl_priv *priv = file->private_data;
400         struct ieee80211_channel *channels = NULL;
401         const struct ieee80211_supported_band *supp_band = NULL;
402         int pos = 0, i, bufsz = PAGE_SIZE;
403         char *buf;
404         ssize_t ret;
405
406         if (!test_bit(STATUS_GEO_CONFIGURED, &priv->status))
407                 return -EAGAIN;
408
409         buf = kzalloc(bufsz, GFP_KERNEL);
410         if (!buf) {
411                 IWL_ERR(priv, "Can not allocate Buffer\n");
412                 return -ENOMEM;
413         }
414
415         supp_band = iwl_get_hw_mode(priv, IEEE80211_BAND_2GHZ);
416         if (supp_band) {
417                 channels = supp_band->channels;
418
419                 pos += scnprintf(buf + pos, bufsz - pos,
420                                 "Displaying %d channels in 2.4GHz band 802.11bg):\n",
421                                 supp_band->n_channels);
422
423                 for (i = 0; i < supp_band->n_channels; i++)
424                         pos += scnprintf(buf + pos, bufsz - pos,
425                                 "%d: %ddBm: BSS%s%s, %s.\n",
426                                 channels[i].hw_value,
427                                 channels[i].max_power,
428                                 channels[i].flags & IEEE80211_CHAN_RADAR ?
429                                 " (IEEE 802.11h required)" : "",
430                                 ((channels[i].flags & IEEE80211_CHAN_NO_IBSS)
431                                 || (channels[i].flags &
432                                 IEEE80211_CHAN_RADAR)) ? "" :
433                                 ", IBSS",
434                                 channels[i].flags &
435                                 IEEE80211_CHAN_PASSIVE_SCAN ?
436                                 "passive only" : "active/passive");
437         }
438         supp_band = iwl_get_hw_mode(priv, IEEE80211_BAND_5GHZ);
439         if (supp_band) {
440                 channels = supp_band->channels;
441
442                 pos += scnprintf(buf + pos, bufsz - pos,
443                                 "Displaying %d channels in 5.2GHz band (802.11a)\n",
444                                 supp_band->n_channels);
445
446                 for (i = 0; i < supp_band->n_channels; i++)
447                         pos += scnprintf(buf + pos, bufsz - pos,
448                                 "%d: %ddBm: BSS%s%s, %s.\n",
449                                 channels[i].hw_value,
450                                 channels[i].max_power,
451                                 channels[i].flags & IEEE80211_CHAN_RADAR ?
452                                 " (IEEE 802.11h required)" : "",
453                                 ((channels[i].flags & IEEE80211_CHAN_NO_IBSS)
454                                 || (channels[i].flags &
455                                 IEEE80211_CHAN_RADAR)) ? "" :
456                                 ", IBSS",
457                                 channels[i].flags &
458                                 IEEE80211_CHAN_PASSIVE_SCAN ?
459                                 "passive only" : "active/passive");
460         }
461         ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
462         kfree(buf);
463         return ret;
464 }
465
466 static ssize_t iwl_legacy_dbgfs_status_read(struct file *file,
467                                                 char __user *user_buf,
468                                                 size_t count, loff_t *ppos) {
469
470         struct iwl_priv *priv = file->private_data;
471         char buf[512];
472         int pos = 0;
473         const size_t bufsz = sizeof(buf);
474
475         pos += scnprintf(buf + pos, bufsz - pos, "STATUS_HCMD_ACTIVE:\t %d\n",
476                 test_bit(STATUS_HCMD_ACTIVE, &priv->status));
477         pos += scnprintf(buf + pos, bufsz - pos, "STATUS_INT_ENABLED:\t %d\n",
478                 test_bit(STATUS_INT_ENABLED, &priv->status));
479         pos += scnprintf(buf + pos, bufsz - pos, "STATUS_RF_KILL_HW:\t %d\n",
480                 test_bit(STATUS_RF_KILL_HW, &priv->status));
481         pos += scnprintf(buf + pos, bufsz - pos, "STATUS_CT_KILL:\t\t %d\n",
482                 test_bit(STATUS_CT_KILL, &priv->status));
483         pos += scnprintf(buf + pos, bufsz - pos, "STATUS_INIT:\t\t %d\n",
484                 test_bit(STATUS_INIT, &priv->status));
485         pos += scnprintf(buf + pos, bufsz - pos, "STATUS_ALIVE:\t\t %d\n",
486                 test_bit(STATUS_ALIVE, &priv->status));
487         pos += scnprintf(buf + pos, bufsz - pos, "STATUS_READY:\t\t %d\n",
488                 test_bit(STATUS_READY, &priv->status));
489         pos += scnprintf(buf + pos, bufsz - pos, "STATUS_TEMPERATURE:\t %d\n",
490                 test_bit(STATUS_TEMPERATURE, &priv->status));
491         pos += scnprintf(buf + pos, bufsz - pos, "STATUS_GEO_CONFIGURED:\t %d\n",
492                 test_bit(STATUS_GEO_CONFIGURED, &priv->status));
493         pos += scnprintf(buf + pos, bufsz - pos, "STATUS_EXIT_PENDING:\t %d\n",
494                 test_bit(STATUS_EXIT_PENDING, &priv->status));
495         pos += scnprintf(buf + pos, bufsz - pos, "STATUS_STATISTICS:\t %d\n",
496                 test_bit(STATUS_STATISTICS, &priv->status));
497         pos += scnprintf(buf + pos, bufsz - pos, "STATUS_SCANNING:\t %d\n",
498                 test_bit(STATUS_SCANNING, &priv->status));
499         pos += scnprintf(buf + pos, bufsz - pos, "STATUS_SCAN_ABORTING:\t %d\n",
500                 test_bit(STATUS_SCAN_ABORTING, &priv->status));
501         pos += scnprintf(buf + pos, bufsz - pos, "STATUS_SCAN_HW:\t\t %d\n",
502                 test_bit(STATUS_SCAN_HW, &priv->status));
503         pos += scnprintf(buf + pos, bufsz - pos, "STATUS_POWER_PMI:\t %d\n",
504                 test_bit(STATUS_POWER_PMI, &priv->status));
505         pos += scnprintf(buf + pos, bufsz - pos, "STATUS_FW_ERROR:\t %d\n",
506                 test_bit(STATUS_FW_ERROR, &priv->status));
507         return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
508 }
509
510 static ssize_t iwl_legacy_dbgfs_interrupt_read(struct file *file,
511                                         char __user *user_buf,
512                                         size_t count, loff_t *ppos) {
513
514         struct iwl_priv *priv = file->private_data;
515         int pos = 0;
516         int cnt = 0;
517         char *buf;
518         int bufsz = 24 * 64; /* 24 items * 64 char per item */
519         ssize_t ret;
520
521         buf = kzalloc(bufsz, GFP_KERNEL);
522         if (!buf) {
523                 IWL_ERR(priv, "Can not allocate Buffer\n");
524                 return -ENOMEM;
525         }
526
527         pos += scnprintf(buf + pos, bufsz - pos,
528                         "Interrupt Statistics Report:\n");
529
530         pos += scnprintf(buf + pos, bufsz - pos, "HW Error:\t\t\t %u\n",
531                 priv->isr_stats.hw);
532         pos += scnprintf(buf + pos, bufsz - pos, "SW Error:\t\t\t %u\n",
533                 priv->isr_stats.sw);
534         if (priv->isr_stats.sw || priv->isr_stats.hw) {
535                 pos += scnprintf(buf + pos, bufsz - pos,
536                         "\tLast Restarting Code:  0x%X\n",
537                         priv->isr_stats.err_code);
538         }
539 #ifdef CONFIG_IWLWIFI_LEGACY_DEBUG
540         pos += scnprintf(buf + pos, bufsz - pos, "Frame transmitted:\t\t %u\n",
541                 priv->isr_stats.sch);
542         pos += scnprintf(buf + pos, bufsz - pos, "Alive interrupt:\t\t %u\n",
543                 priv->isr_stats.alive);
544 #endif
545         pos += scnprintf(buf + pos, bufsz - pos,
546                 "HW RF KILL switch toggled:\t %u\n",
547                 priv->isr_stats.rfkill);
548
549         pos += scnprintf(buf + pos, bufsz - pos, "CT KILL:\t\t\t %u\n",
550                 priv->isr_stats.ctkill);
551
552         pos += scnprintf(buf + pos, bufsz - pos, "Wakeup Interrupt:\t\t %u\n",
553                 priv->isr_stats.wakeup);
554
555         pos += scnprintf(buf + pos, bufsz - pos,
556                 "Rx command responses:\t\t %u\n",
557                 priv->isr_stats.rx);
558         for (cnt = 0; cnt < REPLY_MAX; cnt++) {
559                 if (priv->isr_stats.rx_handlers[cnt] > 0)
560                         pos += scnprintf(buf + pos, bufsz - pos,
561                                 "\tRx handler[%36s]:\t\t %u\n",
562                                 iwl_legacy_get_cmd_string(cnt),
563                                 priv->isr_stats.rx_handlers[cnt]);
564         }
565
566         pos += scnprintf(buf + pos, bufsz - pos, "Tx/FH interrupt:\t\t %u\n",
567                 priv->isr_stats.tx);
568
569         pos += scnprintf(buf + pos, bufsz - pos, "Unexpected INTA:\t\t %u\n",
570                 priv->isr_stats.unhandled);
571
572         ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
573         kfree(buf);
574         return ret;
575 }
576
577 static ssize_t iwl_legacy_dbgfs_interrupt_write(struct file *file,
578                                          const char __user *user_buf,
579                                          size_t count, loff_t *ppos)
580 {
581         struct iwl_priv *priv = file->private_data;
582         char buf[8];
583         int buf_size;
584         u32 reset_flag;
585
586         memset(buf, 0, sizeof(buf));
587         buf_size = min(count, sizeof(buf) -  1);
588         if (copy_from_user(buf, user_buf, buf_size))
589                 return -EFAULT;
590         if (sscanf(buf, "%x", &reset_flag) != 1)
591                 return -EFAULT;
592         if (reset_flag == 0)
593                 iwl_legacy_clear_isr_stats(priv);
594
595         return count;
596 }
597
598 static ssize_t
599 iwl_legacy_dbgfs_qos_read(struct file *file, char __user *user_buf,
600                                        size_t count, loff_t *ppos)
601 {
602         struct iwl_priv *priv = file->private_data;
603         struct iwl_rxon_context *ctx;
604         int pos = 0, i;
605         char buf[256 * NUM_IWL_RXON_CTX];
606         const size_t bufsz = sizeof(buf);
607
608         for_each_context(priv, ctx) {
609                 pos += scnprintf(buf + pos, bufsz - pos, "context %d:\n",
610                                  ctx->ctxid);
611                 for (i = 0; i < AC_NUM; i++) {
612                         pos += scnprintf(buf + pos, bufsz - pos,
613                                 "\tcw_min\tcw_max\taifsn\ttxop\n");
614                         pos += scnprintf(buf + pos, bufsz - pos,
615                                 "AC[%d]\t%u\t%u\t%u\t%u\n", i,
616                                 ctx->qos_data.def_qos_parm.ac[i].cw_min,
617                                 ctx->qos_data.def_qos_parm.ac[i].cw_max,
618                                 ctx->qos_data.def_qos_parm.ac[i].aifsn,
619                                 ctx->qos_data.def_qos_parm.ac[i].edca_txop);
620                 }
621                 pos += scnprintf(buf + pos, bufsz - pos, "\n");
622         }
623         return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
624 }
625
626 static ssize_t iwl_legacy_dbgfs_disable_ht40_write(struct file *file,
627                                          const char __user *user_buf,
628                                          size_t count, loff_t *ppos)
629 {
630         struct iwl_priv *priv = file->private_data;
631         char buf[8];
632         int buf_size;
633         int ht40;
634
635         memset(buf, 0, sizeof(buf));
636         buf_size = min(count, sizeof(buf) -  1);
637         if (copy_from_user(buf, user_buf, buf_size))
638                 return -EFAULT;
639         if (sscanf(buf, "%d", &ht40) != 1)
640                 return -EFAULT;
641         if (!iwl_legacy_is_any_associated(priv))
642                 priv->disable_ht40 = ht40 ? true : false;
643         else {
644                 IWL_ERR(priv, "Sta associated with AP - "
645                         "Change to 40MHz channel support is not allowed\n");
646                 return -EINVAL;
647         }
648
649         return count;
650 }
651
652 static ssize_t iwl_legacy_dbgfs_disable_ht40_read(struct file *file,
653                                          char __user *user_buf,
654                                          size_t count, loff_t *ppos)
655 {
656         struct iwl_priv *priv = file->private_data;
657         char buf[100];
658         int pos = 0;
659         const size_t bufsz = sizeof(buf);
660
661         pos += scnprintf(buf + pos, bufsz - pos,
662                         "11n 40MHz Mode: %s\n",
663                         priv->disable_ht40 ? "Disabled" : "Enabled");
664         return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
665 }
666
667 DEBUGFS_READ_WRITE_FILE_OPS(sram);
668 DEBUGFS_READ_FILE_OPS(nvm);
669 DEBUGFS_READ_FILE_OPS(stations);
670 DEBUGFS_READ_FILE_OPS(channels);
671 DEBUGFS_READ_FILE_OPS(status);
672 DEBUGFS_READ_WRITE_FILE_OPS(interrupt);
673 DEBUGFS_READ_FILE_OPS(qos);
674 DEBUGFS_READ_WRITE_FILE_OPS(disable_ht40);
675
676 static ssize_t iwl_legacy_dbgfs_traffic_log_read(struct file *file,
677                                          char __user *user_buf,
678                                          size_t count, loff_t *ppos)
679 {
680         struct iwl_priv *priv = file->private_data;
681         int pos = 0, ofs = 0;
682         int cnt = 0, entry;
683         struct iwl_tx_queue *txq;
684         struct iwl_queue *q;
685         struct iwl_rx_queue *rxq = &priv->rxq;
686         char *buf;
687         int bufsz = ((IWL_TRAFFIC_ENTRIES * IWL_TRAFFIC_ENTRY_SIZE * 64) * 2) +
688                 (priv->cfg->base_params->num_of_queues * 32 * 8) + 400;
689         const u8 *ptr;
690         ssize_t ret;
691
692         if (!priv->txq) {
693                 IWL_ERR(priv, "txq not ready\n");
694                 return -EAGAIN;
695         }
696         buf = kzalloc(bufsz, GFP_KERNEL);
697         if (!buf) {
698                 IWL_ERR(priv, "Can not allocate buffer\n");
699                 return -ENOMEM;
700         }
701         pos += scnprintf(buf + pos, bufsz - pos, "Tx Queue\n");
702         for (cnt = 0; cnt < priv->hw_params.max_txq_num; cnt++) {
703                 txq = &priv->txq[cnt];
704                 q = &txq->q;
705                 pos += scnprintf(buf + pos, bufsz - pos,
706                                 "q[%d]: read_ptr: %u, write_ptr: %u\n",
707                                 cnt, q->read_ptr, q->write_ptr);
708         }
709         if (priv->tx_traffic && (iwlegacy_debug_level & IWL_DL_TX)) {
710                 ptr = priv->tx_traffic;
711                 pos += scnprintf(buf + pos, bufsz - pos,
712                                 "Tx Traffic idx: %u\n", priv->tx_traffic_idx);
713                 for (cnt = 0, ofs = 0; cnt < IWL_TRAFFIC_ENTRIES; cnt++) {
714                         for (entry = 0; entry < IWL_TRAFFIC_ENTRY_SIZE / 16;
715                              entry++,  ofs += 16) {
716                                 pos += scnprintf(buf + pos, bufsz - pos,
717                                                 "0x%.4x ", ofs);
718                                 hex_dump_to_buffer(ptr + ofs, 16, 16, 2,
719                                                    buf + pos, bufsz - pos, 0);
720                                 pos += strlen(buf + pos);
721                                 if (bufsz - pos > 0)
722                                         buf[pos++] = '\n';
723                         }
724                 }
725         }
726
727         pos += scnprintf(buf + pos, bufsz - pos, "Rx Queue\n");
728         pos += scnprintf(buf + pos, bufsz - pos,
729                         "read: %u, write: %u\n",
730                          rxq->read, rxq->write);
731
732         if (priv->rx_traffic && (iwlegacy_debug_level & IWL_DL_RX)) {
733                 ptr = priv->rx_traffic;
734                 pos += scnprintf(buf + pos, bufsz - pos,
735                                 "Rx Traffic idx: %u\n", priv->rx_traffic_idx);
736                 for (cnt = 0, ofs = 0; cnt < IWL_TRAFFIC_ENTRIES; cnt++) {
737                         for (entry = 0; entry < IWL_TRAFFIC_ENTRY_SIZE / 16;
738                              entry++,  ofs += 16) {
739                                 pos += scnprintf(buf + pos, bufsz - pos,
740                                                 "0x%.4x ", ofs);
741                                 hex_dump_to_buffer(ptr + ofs, 16, 16, 2,
742                                                    buf + pos, bufsz - pos, 0);
743                                 pos += strlen(buf + pos);
744                                 if (bufsz - pos > 0)
745                                         buf[pos++] = '\n';
746                         }
747                 }
748         }
749
750         ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
751         kfree(buf);
752         return ret;
753 }
754
755 static ssize_t iwl_legacy_dbgfs_traffic_log_write(struct file *file,
756                                          const char __user *user_buf,
757                                          size_t count, loff_t *ppos)
758 {
759         struct iwl_priv *priv = file->private_data;
760         char buf[8];
761         int buf_size;
762         int traffic_log;
763
764         memset(buf, 0, sizeof(buf));
765         buf_size = min(count, sizeof(buf) -  1);
766         if (copy_from_user(buf, user_buf, buf_size))
767                 return -EFAULT;
768         if (sscanf(buf, "%d", &traffic_log) != 1)
769                 return -EFAULT;
770         if (traffic_log == 0)
771                 iwl_legacy_reset_traffic_log(priv);
772
773         return count;
774 }
775
776 static ssize_t iwl_legacy_dbgfs_tx_queue_read(struct file *file,
777                                                 char __user *user_buf,
778                                                 size_t count, loff_t *ppos) {
779
780         struct iwl_priv *priv = file->private_data;
781         struct iwl_tx_queue *txq;
782         struct iwl_queue *q;
783         char *buf;
784         int pos = 0;
785         int cnt;
786         int ret;
787         const size_t bufsz = sizeof(char) * 64 *
788                                 priv->cfg->base_params->num_of_queues;
789
790         if (!priv->txq) {
791                 IWL_ERR(priv, "txq not ready\n");
792                 return -EAGAIN;
793         }
794         buf = kzalloc(bufsz, GFP_KERNEL);
795         if (!buf)
796                 return -ENOMEM;
797
798         for (cnt = 0; cnt < priv->hw_params.max_txq_num; cnt++) {
799                 txq = &priv->txq[cnt];
800                 q = &txq->q;
801                 pos += scnprintf(buf + pos, bufsz - pos,
802                                 "hwq %.2d: read=%u write=%u stop=%d"
803                                 " swq_id=%#.2x (ac %d/hwq %d)\n",
804                                 cnt, q->read_ptr, q->write_ptr,
805                                 !!test_bit(cnt, priv->queue_stopped),
806                                 txq->swq_id, txq->swq_id & 3,
807                                 (txq->swq_id >> 2) & 0x1f);
808                 if (cnt >= 4)
809                         continue;
810                 /* for the ACs, display the stop count too */
811                 pos += scnprintf(buf + pos, bufsz - pos,
812                                 "        stop-count: %d\n",
813                                 atomic_read(&priv->queue_stop_count[cnt]));
814         }
815         ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
816         kfree(buf);
817         return ret;
818 }
819
820 static ssize_t iwl_legacy_dbgfs_rx_queue_read(struct file *file,
821                                                 char __user *user_buf,
822                                                 size_t count, loff_t *ppos) {
823
824         struct iwl_priv *priv = file->private_data;
825         struct iwl_rx_queue *rxq = &priv->rxq;
826         char buf[256];
827         int pos = 0;
828         const size_t bufsz = sizeof(buf);
829
830         pos += scnprintf(buf + pos, bufsz - pos, "read: %u\n",
831                                                 rxq->read);
832         pos += scnprintf(buf + pos, bufsz - pos, "write: %u\n",
833                                                 rxq->write);
834         pos += scnprintf(buf + pos, bufsz - pos, "free_count: %u\n",
835                                                 rxq->free_count);
836         if (rxq->rb_stts) {
837                 pos += scnprintf(buf + pos, bufsz - pos, "closed_rb_num: %u\n",
838                          le16_to_cpu(rxq->rb_stts->closed_rb_num) &  0x0FFF);
839         } else {
840                 pos += scnprintf(buf + pos, bufsz - pos,
841                                         "closed_rb_num: Not Allocated\n");
842         }
843         return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
844 }
845
846 static ssize_t iwl_legacy_dbgfs_ucode_rx_stats_read(struct file *file,
847                                         char __user *user_buf,
848                                         size_t count, loff_t *ppos)
849 {
850         struct iwl_priv *priv = file->private_data;
851         return priv->cfg->ops->lib->debugfs_ops.rx_stats_read(file,
852                         user_buf, count, ppos);
853 }
854
855 static ssize_t iwl_legacy_dbgfs_ucode_tx_stats_read(struct file *file,
856                                         char __user *user_buf,
857                                         size_t count, loff_t *ppos)
858 {
859         struct iwl_priv *priv = file->private_data;
860         return priv->cfg->ops->lib->debugfs_ops.tx_stats_read(file,
861                         user_buf, count, ppos);
862 }
863
864 static ssize_t iwl_legacy_dbgfs_ucode_general_stats_read(struct file *file,
865                                         char __user *user_buf,
866                                         size_t count, loff_t *ppos)
867 {
868         struct iwl_priv *priv = file->private_data;
869         return priv->cfg->ops->lib->debugfs_ops.general_stats_read(file,
870                         user_buf, count, ppos);
871 }
872
873 static ssize_t iwl_legacy_dbgfs_sensitivity_read(struct file *file,
874                                         char __user *user_buf,
875                                         size_t count, loff_t *ppos) {
876
877         struct iwl_priv *priv = file->private_data;
878         int pos = 0;
879         int cnt = 0;
880         char *buf;
881         int bufsz = sizeof(struct iwl_sensitivity_data) * 4 + 100;
882         ssize_t ret;
883         struct iwl_sensitivity_data *data;
884
885         data = &priv->sensitivity_data;
886         buf = kzalloc(bufsz, GFP_KERNEL);
887         if (!buf) {
888                 IWL_ERR(priv, "Can not allocate Buffer\n");
889                 return -ENOMEM;
890         }
891
892         pos += scnprintf(buf + pos, bufsz - pos, "auto_corr_ofdm:\t\t\t %u\n",
893                         data->auto_corr_ofdm);
894         pos += scnprintf(buf + pos, bufsz - pos,
895                         "auto_corr_ofdm_mrc:\t\t %u\n",
896                         data->auto_corr_ofdm_mrc);
897         pos += scnprintf(buf + pos, bufsz - pos, "auto_corr_ofdm_x1:\t\t %u\n",
898                         data->auto_corr_ofdm_x1);
899         pos += scnprintf(buf + pos, bufsz - pos,
900                         "auto_corr_ofdm_mrc_x1:\t\t %u\n",
901                         data->auto_corr_ofdm_mrc_x1);
902         pos += scnprintf(buf + pos, bufsz - pos, "auto_corr_cck:\t\t\t %u\n",
903                         data->auto_corr_cck);
904         pos += scnprintf(buf + pos, bufsz - pos, "auto_corr_cck_mrc:\t\t %u\n",
905                         data->auto_corr_cck_mrc);
906         pos += scnprintf(buf + pos, bufsz - pos,
907                         "last_bad_plcp_cnt_ofdm:\t\t %u\n",
908                         data->last_bad_plcp_cnt_ofdm);
909         pos += scnprintf(buf + pos, bufsz - pos, "last_fa_cnt_ofdm:\t\t %u\n",
910                         data->last_fa_cnt_ofdm);
911         pos += scnprintf(buf + pos, bufsz - pos,
912                         "last_bad_plcp_cnt_cck:\t\t %u\n",
913                         data->last_bad_plcp_cnt_cck);
914         pos += scnprintf(buf + pos, bufsz - pos, "last_fa_cnt_cck:\t\t %u\n",
915                         data->last_fa_cnt_cck);
916         pos += scnprintf(buf + pos, bufsz - pos, "nrg_curr_state:\t\t\t %u\n",
917                         data->nrg_curr_state);
918         pos += scnprintf(buf + pos, bufsz - pos, "nrg_prev_state:\t\t\t %u\n",
919                         data->nrg_prev_state);
920         pos += scnprintf(buf + pos, bufsz - pos, "nrg_value:\t\t\t");
921         for (cnt = 0; cnt < 10; cnt++) {
922                 pos += scnprintf(buf + pos, bufsz - pos, " %u",
923                                 data->nrg_value[cnt]);
924         }
925         pos += scnprintf(buf + pos, bufsz - pos, "\n");
926         pos += scnprintf(buf + pos, bufsz - pos, "nrg_silence_rssi:\t\t");
927         for (cnt = 0; cnt < NRG_NUM_PREV_STAT_L; cnt++) {
928                 pos += scnprintf(buf + pos, bufsz - pos, " %u",
929                                 data->nrg_silence_rssi[cnt]);
930         }
931         pos += scnprintf(buf + pos, bufsz - pos, "\n");
932         pos += scnprintf(buf + pos, bufsz - pos, "nrg_silence_ref:\t\t %u\n",
933                         data->nrg_silence_ref);
934         pos += scnprintf(buf + pos, bufsz - pos, "nrg_energy_idx:\t\t\t %u\n",
935                         data->nrg_energy_idx);
936         pos += scnprintf(buf + pos, bufsz - pos, "nrg_silence_idx:\t\t %u\n",
937                         data->nrg_silence_idx);
938         pos += scnprintf(buf + pos, bufsz - pos, "nrg_th_cck:\t\t\t %u\n",
939                         data->nrg_th_cck);
940         pos += scnprintf(buf + pos, bufsz - pos,
941                         "nrg_auto_corr_silence_diff:\t %u\n",
942                         data->nrg_auto_corr_silence_diff);
943         pos += scnprintf(buf + pos, bufsz - pos, "num_in_cck_no_fa:\t\t %u\n",
944                         data->num_in_cck_no_fa);
945         pos += scnprintf(buf + pos, bufsz - pos, "nrg_th_ofdm:\t\t\t %u\n",
946                         data->nrg_th_ofdm);
947
948         ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
949         kfree(buf);
950         return ret;
951 }
952
953
954 static ssize_t iwl_legacy_dbgfs_chain_noise_read(struct file *file,
955                                         char __user *user_buf,
956                                         size_t count, loff_t *ppos) {
957
958         struct iwl_priv *priv = file->private_data;
959         int pos = 0;
960         int cnt = 0;
961         char *buf;
962         int bufsz = sizeof(struct iwl_chain_noise_data) * 4 + 100;
963         ssize_t ret;
964         struct iwl_chain_noise_data *data;
965
966         data = &priv->chain_noise_data;
967         buf = kzalloc(bufsz, GFP_KERNEL);
968         if (!buf) {
969                 IWL_ERR(priv, "Can not allocate Buffer\n");
970                 return -ENOMEM;
971         }
972
973         pos += scnprintf(buf + pos, bufsz - pos, "active_chains:\t\t\t %u\n",
974                         data->active_chains);
975         pos += scnprintf(buf + pos, bufsz - pos, "chain_noise_a:\t\t\t %u\n",
976                         data->chain_noise_a);
977         pos += scnprintf(buf + pos, bufsz - pos, "chain_noise_b:\t\t\t %u\n",
978                         data->chain_noise_b);
979         pos += scnprintf(buf + pos, bufsz - pos, "chain_noise_c:\t\t\t %u\n",
980                         data->chain_noise_c);
981         pos += scnprintf(buf + pos, bufsz - pos, "chain_signal_a:\t\t\t %u\n",
982                         data->chain_signal_a);
983         pos += scnprintf(buf + pos, bufsz - pos, "chain_signal_b:\t\t\t %u\n",
984                         data->chain_signal_b);
985         pos += scnprintf(buf + pos, bufsz - pos, "chain_signal_c:\t\t\t %u\n",
986                         data->chain_signal_c);
987         pos += scnprintf(buf + pos, bufsz - pos, "beacon_count:\t\t\t %u\n",
988                         data->beacon_count);
989
990         pos += scnprintf(buf + pos, bufsz - pos, "disconn_array:\t\t\t");
991         for (cnt = 0; cnt < NUM_RX_CHAINS; cnt++) {
992                 pos += scnprintf(buf + pos, bufsz - pos, " %u",
993                                 data->disconn_array[cnt]);
994         }
995         pos += scnprintf(buf + pos, bufsz - pos, "\n");
996         pos += scnprintf(buf + pos, bufsz - pos, "delta_gain_code:\t\t");
997         for (cnt = 0; cnt < NUM_RX_CHAINS; cnt++) {
998                 pos += scnprintf(buf + pos, bufsz - pos, " %u",
999                                 data->delta_gain_code[cnt]);
1000         }
1001         pos += scnprintf(buf + pos, bufsz - pos, "\n");
1002         pos += scnprintf(buf + pos, bufsz - pos, "radio_write:\t\t\t %u\n",
1003                         data->radio_write);
1004         pos += scnprintf(buf + pos, bufsz - pos, "state:\t\t\t\t %u\n",
1005                         data->state);
1006
1007         ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
1008         kfree(buf);
1009         return ret;
1010 }
1011
1012 static ssize_t iwl_legacy_dbgfs_power_save_status_read(struct file *file,
1013                                                     char __user *user_buf,
1014                                                     size_t count, loff_t *ppos)
1015 {
1016         struct iwl_priv *priv = file->private_data;
1017         char buf[60];
1018         int pos = 0;
1019         const size_t bufsz = sizeof(buf);
1020         u32 pwrsave_status;
1021
1022         pwrsave_status = iwl_read32(priv, CSR_GP_CNTRL) &
1023                         CSR_GP_REG_POWER_SAVE_STATUS_MSK;
1024
1025         pos += scnprintf(buf + pos, bufsz - pos, "Power Save Status: ");
1026         pos += scnprintf(buf + pos, bufsz - pos, "%s\n",
1027                 (pwrsave_status == CSR_GP_REG_NO_POWER_SAVE) ? "none" :
1028                 (pwrsave_status == CSR_GP_REG_MAC_POWER_SAVE) ? "MAC" :
1029                 (pwrsave_status == CSR_GP_REG_PHY_POWER_SAVE) ? "PHY" :
1030                 "error");
1031
1032         return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
1033 }
1034
1035 static ssize_t iwl_legacy_dbgfs_clear_ucode_statistics_write(struct file *file,
1036                                          const char __user *user_buf,
1037                                          size_t count, loff_t *ppos)
1038 {
1039         struct iwl_priv *priv = file->private_data;
1040         char buf[8];
1041         int buf_size;
1042         int clear;
1043
1044         memset(buf, 0, sizeof(buf));
1045         buf_size = min(count, sizeof(buf) -  1);
1046         if (copy_from_user(buf, user_buf, buf_size))
1047                 return -EFAULT;
1048         if (sscanf(buf, "%d", &clear) != 1)
1049                 return -EFAULT;
1050
1051         /* make request to uCode to retrieve statistics information */
1052         mutex_lock(&priv->mutex);
1053         iwl_legacy_send_statistics_request(priv, CMD_SYNC, true);
1054         mutex_unlock(&priv->mutex);
1055
1056         return count;
1057 }
1058
1059 static ssize_t iwl_legacy_dbgfs_rxon_flags_read(struct file *file,
1060                                          char __user *user_buf,
1061                                          size_t count, loff_t *ppos) {
1062
1063         struct iwl_priv *priv = file->private_data;
1064         int len = 0;
1065         char buf[20];
1066
1067         len = sprintf(buf, "0x%04X\n",
1068                 le32_to_cpu(priv->contexts[IWL_RXON_CTX_BSS].active.flags));
1069         return simple_read_from_buffer(user_buf, count, ppos, buf, len);
1070 }
1071
1072 static ssize_t iwl_legacy_dbgfs_rxon_filter_flags_read(struct file *file,
1073                                                 char __user *user_buf,
1074                                                 size_t count, loff_t *ppos) {
1075
1076         struct iwl_priv *priv = file->private_data;
1077         int len = 0;
1078         char buf[20];
1079
1080         len = sprintf(buf, "0x%04X\n",
1081         le32_to_cpu(priv->contexts[IWL_RXON_CTX_BSS].active.filter_flags));
1082         return simple_read_from_buffer(user_buf, count, ppos, buf, len);
1083 }
1084
1085 static ssize_t iwl_legacy_dbgfs_fh_reg_read(struct file *file,
1086                                          char __user *user_buf,
1087                                          size_t count, loff_t *ppos)
1088 {
1089         struct iwl_priv *priv = file->private_data;
1090         char *buf;
1091         int pos = 0;
1092         ssize_t ret = -EFAULT;
1093
1094         if (priv->cfg->ops->lib->dump_fh) {
1095                 ret = pos = priv->cfg->ops->lib->dump_fh(priv, &buf, true);
1096                 if (buf) {
1097                         ret = simple_read_from_buffer(user_buf,
1098                                                       count, ppos, buf, pos);
1099                         kfree(buf);
1100                 }
1101         }
1102
1103         return ret;
1104 }
1105
1106 static ssize_t iwl_legacy_dbgfs_missed_beacon_read(struct file *file,
1107                                         char __user *user_buf,
1108                                         size_t count, loff_t *ppos) {
1109
1110         struct iwl_priv *priv = file->private_data;
1111         int pos = 0;
1112         char buf[12];
1113         const size_t bufsz = sizeof(buf);
1114
1115         pos += scnprintf(buf + pos, bufsz - pos, "%d\n",
1116                         priv->missed_beacon_threshold);
1117
1118         return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
1119 }
1120
1121 static ssize_t iwl_legacy_dbgfs_missed_beacon_write(struct file *file,
1122                                          const char __user *user_buf,
1123                                          size_t count, loff_t *ppos)
1124 {
1125         struct iwl_priv *priv = file->private_data;
1126         char buf[8];
1127         int buf_size;
1128         int missed;
1129
1130         memset(buf, 0, sizeof(buf));
1131         buf_size = min(count, sizeof(buf) -  1);
1132         if (copy_from_user(buf, user_buf, buf_size))
1133                 return -EFAULT;
1134         if (sscanf(buf, "%d", &missed) != 1)
1135                 return -EINVAL;
1136
1137         if (missed < IWL_MISSED_BEACON_THRESHOLD_MIN ||
1138             missed > IWL_MISSED_BEACON_THRESHOLD_MAX)
1139                 priv->missed_beacon_threshold =
1140                         IWL_MISSED_BEACON_THRESHOLD_DEF;
1141         else
1142                 priv->missed_beacon_threshold = missed;
1143
1144         return count;
1145 }
1146
1147 static ssize_t iwl_legacy_dbgfs_force_reset_read(struct file *file,
1148                                         char __user *user_buf,
1149                                         size_t count, loff_t *ppos) {
1150
1151         struct iwl_priv *priv = file->private_data;
1152         int pos = 0;
1153         char buf[300];
1154         const size_t bufsz = sizeof(buf);
1155         struct iwl_force_reset *force_reset;
1156
1157         force_reset = &priv->force_reset;
1158
1159         pos += scnprintf(buf + pos, bufsz - pos,
1160                         "\tnumber of reset request: %d\n",
1161                         force_reset->reset_request_count);
1162         pos += scnprintf(buf + pos, bufsz - pos,
1163                         "\tnumber of reset request success: %d\n",
1164                         force_reset->reset_success_count);
1165         pos += scnprintf(buf + pos, bufsz - pos,
1166                         "\tnumber of reset request reject: %d\n",
1167                         force_reset->reset_reject_count);
1168         pos += scnprintf(buf + pos, bufsz - pos,
1169                         "\treset duration: %lu\n",
1170                         force_reset->reset_duration);
1171
1172         return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
1173 }
1174
1175 static ssize_t iwl_legacy_dbgfs_force_reset_write(struct file *file,
1176                                         const char __user *user_buf,
1177                                         size_t count, loff_t *ppos) {
1178
1179         int ret;
1180         struct iwl_priv *priv = file->private_data;
1181
1182         ret = iwl_legacy_force_reset(priv, true);
1183
1184         return ret ? ret : count;
1185 }
1186
1187 static ssize_t iwl_legacy_dbgfs_wd_timeout_write(struct file *file,
1188                                         const char __user *user_buf,
1189                                         size_t count, loff_t *ppos) {
1190
1191         struct iwl_priv *priv = file->private_data;
1192         char buf[8];
1193         int buf_size;
1194         int timeout;
1195
1196         memset(buf, 0, sizeof(buf));
1197         buf_size = min(count, sizeof(buf) -  1);
1198         if (copy_from_user(buf, user_buf, buf_size))
1199                 return -EFAULT;
1200         if (sscanf(buf, "%d", &timeout) != 1)
1201                 return -EINVAL;
1202         if (timeout < 0 || timeout > IWL_MAX_WD_TIMEOUT)
1203                 timeout = IWL_DEF_WD_TIMEOUT;
1204
1205         priv->cfg->base_params->wd_timeout = timeout;
1206         iwl_legacy_setup_watchdog(priv);
1207         return count;
1208 }
1209
1210 DEBUGFS_READ_FILE_OPS(rx_statistics);
1211 DEBUGFS_READ_FILE_OPS(tx_statistics);
1212 DEBUGFS_READ_WRITE_FILE_OPS(traffic_log);
1213 DEBUGFS_READ_FILE_OPS(rx_queue);
1214 DEBUGFS_READ_FILE_OPS(tx_queue);
1215 DEBUGFS_READ_FILE_OPS(ucode_rx_stats);
1216 DEBUGFS_READ_FILE_OPS(ucode_tx_stats);
1217 DEBUGFS_READ_FILE_OPS(ucode_general_stats);
1218 DEBUGFS_READ_FILE_OPS(sensitivity);
1219 DEBUGFS_READ_FILE_OPS(chain_noise);
1220 DEBUGFS_READ_FILE_OPS(power_save_status);
1221 DEBUGFS_WRITE_FILE_OPS(clear_ucode_statistics);
1222 DEBUGFS_WRITE_FILE_OPS(clear_traffic_statistics);
1223 DEBUGFS_READ_FILE_OPS(fh_reg);
1224 DEBUGFS_READ_WRITE_FILE_OPS(missed_beacon);
1225 DEBUGFS_READ_WRITE_FILE_OPS(force_reset);
1226 DEBUGFS_READ_FILE_OPS(rxon_flags);
1227 DEBUGFS_READ_FILE_OPS(rxon_filter_flags);
1228 DEBUGFS_WRITE_FILE_OPS(wd_timeout);
1229
1230 /*
1231  * Create the debugfs files and directories
1232  *
1233  */
1234 int iwl_legacy_dbgfs_register(struct iwl_priv *priv, const char *name)
1235 {
1236         struct dentry *phyd = priv->hw->wiphy->debugfsdir;
1237         struct dentry *dir_drv, *dir_data, *dir_rf, *dir_debug;
1238
1239         dir_drv = debugfs_create_dir(name, phyd);
1240         if (!dir_drv)
1241                 return -ENOMEM;
1242
1243         priv->debugfs_dir = dir_drv;
1244
1245         dir_data = debugfs_create_dir("data", dir_drv);
1246         if (!dir_data)
1247                 goto err;
1248         dir_rf = debugfs_create_dir("rf", dir_drv);
1249         if (!dir_rf)
1250                 goto err;
1251         dir_debug = debugfs_create_dir("debug", dir_drv);
1252         if (!dir_debug)
1253                 goto err;
1254
1255         DEBUGFS_ADD_FILE(nvm, dir_data, S_IRUSR);
1256         DEBUGFS_ADD_FILE(sram, dir_data, S_IWUSR | S_IRUSR);
1257         DEBUGFS_ADD_FILE(stations, dir_data, S_IRUSR);
1258         DEBUGFS_ADD_FILE(channels, dir_data, S_IRUSR);
1259         DEBUGFS_ADD_FILE(status, dir_data, S_IRUSR);
1260         DEBUGFS_ADD_FILE(interrupt, dir_data, S_IWUSR | S_IRUSR);
1261         DEBUGFS_ADD_FILE(qos, dir_data, S_IRUSR);
1262         DEBUGFS_ADD_FILE(disable_ht40, dir_data, S_IWUSR | S_IRUSR);
1263         DEBUGFS_ADD_FILE(rx_statistics, dir_debug, S_IRUSR);
1264         DEBUGFS_ADD_FILE(tx_statistics, dir_debug, S_IRUSR);
1265         DEBUGFS_ADD_FILE(traffic_log, dir_debug, S_IWUSR | S_IRUSR);
1266         DEBUGFS_ADD_FILE(rx_queue, dir_debug, S_IRUSR);
1267         DEBUGFS_ADD_FILE(tx_queue, dir_debug, S_IRUSR);
1268         DEBUGFS_ADD_FILE(power_save_status, dir_debug, S_IRUSR);
1269         DEBUGFS_ADD_FILE(clear_ucode_statistics, dir_debug, S_IWUSR);
1270         DEBUGFS_ADD_FILE(clear_traffic_statistics, dir_debug, S_IWUSR);
1271         DEBUGFS_ADD_FILE(fh_reg, dir_debug, S_IRUSR);
1272         DEBUGFS_ADD_FILE(missed_beacon, dir_debug, S_IWUSR);
1273         DEBUGFS_ADD_FILE(force_reset, dir_debug, S_IWUSR | S_IRUSR);
1274         DEBUGFS_ADD_FILE(ucode_rx_stats, dir_debug, S_IRUSR);
1275         DEBUGFS_ADD_FILE(ucode_tx_stats, dir_debug, S_IRUSR);
1276         DEBUGFS_ADD_FILE(ucode_general_stats, dir_debug, S_IRUSR);
1277
1278         if (priv->cfg->base_params->sensitivity_calib_by_driver)
1279                 DEBUGFS_ADD_FILE(sensitivity, dir_debug, S_IRUSR);
1280         if (priv->cfg->base_params->chain_noise_calib_by_driver)
1281                 DEBUGFS_ADD_FILE(chain_noise, dir_debug, S_IRUSR);
1282         DEBUGFS_ADD_FILE(rxon_flags, dir_debug, S_IWUSR);
1283         DEBUGFS_ADD_FILE(rxon_filter_flags, dir_debug, S_IWUSR);
1284         DEBUGFS_ADD_FILE(wd_timeout, dir_debug, S_IWUSR);
1285         if (priv->cfg->base_params->sensitivity_calib_by_driver)
1286                 DEBUGFS_ADD_BOOL(disable_sensitivity, dir_rf,
1287                                  &priv->disable_sens_cal);
1288         if (priv->cfg->base_params->chain_noise_calib_by_driver)
1289                 DEBUGFS_ADD_BOOL(disable_chain_noise, dir_rf,
1290                                  &priv->disable_chain_noise_cal);
1291         DEBUGFS_ADD_BOOL(disable_tx_power, dir_rf,
1292                                 &priv->disable_tx_power_cal);
1293         return 0;
1294
1295 err:
1296         IWL_ERR(priv, "Can't create the debugfs directory\n");
1297         iwl_legacy_dbgfs_unregister(priv);
1298         return -ENOMEM;
1299 }
1300 EXPORT_SYMBOL(iwl_legacy_dbgfs_register);
1301
1302 /**
1303  * Remove the debugfs files and directories
1304  *
1305  */
1306 void iwl_legacy_dbgfs_unregister(struct iwl_priv *priv)
1307 {
1308         if (!priv->debugfs_dir)
1309                 return;
1310
1311         debugfs_remove_recursive(priv->debugfs_dir);
1312         priv->debugfs_dir = NULL;
1313 }
1314 EXPORT_SYMBOL(iwl_legacy_dbgfs_unregister);