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