6ea9c4fbcd3a0077b3298fe685012f1269593ce6
[linux-2.6.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 iwl_legacy_dbgfs_log_event_read(struct file *file,
395                                          char __user *user_buf,
396                                          size_t count, loff_t *ppos)
397 {
398         struct iwl_priv *priv = file->private_data;
399         char *buf;
400         int pos = 0;
401         ssize_t ret = -ENOMEM;
402
403         ret = pos = priv->cfg->ops->lib->dump_nic_event_log(
404                                         priv, true, &buf, true);
405         if (buf) {
406                 ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
407                 kfree(buf);
408         }
409         return ret;
410 }
411
412 static ssize_t iwl_legacy_dbgfs_log_event_write(struct file *file,
413                                         const char __user *user_buf,
414                                         size_t count, loff_t *ppos)
415 {
416         struct iwl_priv *priv = file->private_data;
417         u32 event_log_flag;
418         char buf[8];
419         int buf_size;
420
421         memset(buf, 0, sizeof(buf));
422         buf_size = min(count, sizeof(buf) -  1);
423         if (copy_from_user(buf, user_buf, buf_size))
424                 return -EFAULT;
425         if (sscanf(buf, "%d", &event_log_flag) != 1)
426                 return -EFAULT;
427         if (event_log_flag == 1)
428                 priv->cfg->ops->lib->dump_nic_event_log(priv, true,
429                                                         NULL, false);
430
431         return count;
432 }
433
434
435
436 static ssize_t
437 iwl_legacy_dbgfs_channels_read(struct file *file, char __user *user_buf,
438                                        size_t count, loff_t *ppos)
439 {
440         struct iwl_priv *priv = file->private_data;
441         struct ieee80211_channel *channels = NULL;
442         const struct ieee80211_supported_band *supp_band = NULL;
443         int pos = 0, i, bufsz = PAGE_SIZE;
444         char *buf;
445         ssize_t ret;
446
447         if (!test_bit(STATUS_GEO_CONFIGURED, &priv->status))
448                 return -EAGAIN;
449
450         buf = kzalloc(bufsz, GFP_KERNEL);
451         if (!buf) {
452                 IWL_ERR(priv, "Can not allocate Buffer\n");
453                 return -ENOMEM;
454         }
455
456         supp_band = iwl_get_hw_mode(priv, IEEE80211_BAND_2GHZ);
457         if (supp_band) {
458                 channels = supp_band->channels;
459
460                 pos += scnprintf(buf + pos, bufsz - pos,
461                                 "Displaying %d channels in 2.4GHz band 802.11bg):\n",
462                                 supp_band->n_channels);
463
464                 for (i = 0; i < supp_band->n_channels; i++)
465                         pos += scnprintf(buf + pos, bufsz - pos,
466                                 "%d: %ddBm: BSS%s%s, %s.\n",
467                                 channels[i].hw_value,
468                                 channels[i].max_power,
469                                 channels[i].flags & IEEE80211_CHAN_RADAR ?
470                                 " (IEEE 802.11h required)" : "",
471                                 ((channels[i].flags & IEEE80211_CHAN_NO_IBSS)
472                                 || (channels[i].flags &
473                                 IEEE80211_CHAN_RADAR)) ? "" :
474                                 ", IBSS",
475                                 channels[i].flags &
476                                 IEEE80211_CHAN_PASSIVE_SCAN ?
477                                 "passive only" : "active/passive");
478         }
479         supp_band = iwl_get_hw_mode(priv, IEEE80211_BAND_5GHZ);
480         if (supp_band) {
481                 channels = supp_band->channels;
482
483                 pos += scnprintf(buf + pos, bufsz - pos,
484                                 "Displaying %d channels in 5.2GHz band (802.11a)\n",
485                                 supp_band->n_channels);
486
487                 for (i = 0; i < supp_band->n_channels; i++)
488                         pos += scnprintf(buf + pos, bufsz - pos,
489                                 "%d: %ddBm: BSS%s%s, %s.\n",
490                                 channels[i].hw_value,
491                                 channels[i].max_power,
492                                 channels[i].flags & IEEE80211_CHAN_RADAR ?
493                                 " (IEEE 802.11h required)" : "",
494                                 ((channels[i].flags & IEEE80211_CHAN_NO_IBSS)
495                                 || (channels[i].flags &
496                                 IEEE80211_CHAN_RADAR)) ? "" :
497                                 ", IBSS",
498                                 channels[i].flags &
499                                 IEEE80211_CHAN_PASSIVE_SCAN ?
500                                 "passive only" : "active/passive");
501         }
502         ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
503         kfree(buf);
504         return ret;
505 }
506
507 static ssize_t iwl_legacy_dbgfs_status_read(struct file *file,
508                                                 char __user *user_buf,
509                                                 size_t count, loff_t *ppos) {
510
511         struct iwl_priv *priv = file->private_data;
512         char buf[512];
513         int pos = 0;
514         const size_t bufsz = sizeof(buf);
515
516         pos += scnprintf(buf + pos, bufsz - pos, "STATUS_HCMD_ACTIVE:\t %d\n",
517                 test_bit(STATUS_HCMD_ACTIVE, &priv->status));
518         pos += scnprintf(buf + pos, bufsz - pos, "STATUS_INT_ENABLED:\t %d\n",
519                 test_bit(STATUS_INT_ENABLED, &priv->status));
520         pos += scnprintf(buf + pos, bufsz - pos, "STATUS_RF_KILL_HW:\t %d\n",
521                 test_bit(STATUS_RF_KILL_HW, &priv->status));
522         pos += scnprintf(buf + pos, bufsz - pos, "STATUS_CT_KILL:\t\t %d\n",
523                 test_bit(STATUS_CT_KILL, &priv->status));
524         pos += scnprintf(buf + pos, bufsz - pos, "STATUS_INIT:\t\t %d\n",
525                 test_bit(STATUS_INIT, &priv->status));
526         pos += scnprintf(buf + pos, bufsz - pos, "STATUS_ALIVE:\t\t %d\n",
527                 test_bit(STATUS_ALIVE, &priv->status));
528         pos += scnprintf(buf + pos, bufsz - pos, "STATUS_READY:\t\t %d\n",
529                 test_bit(STATUS_READY, &priv->status));
530         pos += scnprintf(buf + pos, bufsz - pos, "STATUS_TEMPERATURE:\t %d\n",
531                 test_bit(STATUS_TEMPERATURE, &priv->status));
532         pos += scnprintf(buf + pos, bufsz - pos, "STATUS_GEO_CONFIGURED:\t %d\n",
533                 test_bit(STATUS_GEO_CONFIGURED, &priv->status));
534         pos += scnprintf(buf + pos, bufsz - pos, "STATUS_EXIT_PENDING:\t %d\n",
535                 test_bit(STATUS_EXIT_PENDING, &priv->status));
536         pos += scnprintf(buf + pos, bufsz - pos, "STATUS_STATISTICS:\t %d\n",
537                 test_bit(STATUS_STATISTICS, &priv->status));
538         pos += scnprintf(buf + pos, bufsz - pos, "STATUS_SCANNING:\t %d\n",
539                 test_bit(STATUS_SCANNING, &priv->status));
540         pos += scnprintf(buf + pos, bufsz - pos, "STATUS_SCAN_ABORTING:\t %d\n",
541                 test_bit(STATUS_SCAN_ABORTING, &priv->status));
542         pos += scnprintf(buf + pos, bufsz - pos, "STATUS_SCAN_HW:\t\t %d\n",
543                 test_bit(STATUS_SCAN_HW, &priv->status));
544         pos += scnprintf(buf + pos, bufsz - pos, "STATUS_POWER_PMI:\t %d\n",
545                 test_bit(STATUS_POWER_PMI, &priv->status));
546         pos += scnprintf(buf + pos, bufsz - pos, "STATUS_FW_ERROR:\t %d\n",
547                 test_bit(STATUS_FW_ERROR, &priv->status));
548         return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
549 }
550
551 static ssize_t iwl_legacy_dbgfs_interrupt_read(struct file *file,
552                                         char __user *user_buf,
553                                         size_t count, loff_t *ppos) {
554
555         struct iwl_priv *priv = file->private_data;
556         int pos = 0;
557         int cnt = 0;
558         char *buf;
559         int bufsz = 24 * 64; /* 24 items * 64 char per item */
560         ssize_t ret;
561
562         buf = kzalloc(bufsz, GFP_KERNEL);
563         if (!buf) {
564                 IWL_ERR(priv, "Can not allocate Buffer\n");
565                 return -ENOMEM;
566         }
567
568         pos += scnprintf(buf + pos, bufsz - pos,
569                         "Interrupt Statistics Report:\n");
570
571         pos += scnprintf(buf + pos, bufsz - pos, "HW Error:\t\t\t %u\n",
572                 priv->isr_stats.hw);
573         pos += scnprintf(buf + pos, bufsz - pos, "SW Error:\t\t\t %u\n",
574                 priv->isr_stats.sw);
575         if (priv->isr_stats.sw || priv->isr_stats.hw) {
576                 pos += scnprintf(buf + pos, bufsz - pos,
577                         "\tLast Restarting Code:  0x%X\n",
578                         priv->isr_stats.err_code);
579         }
580 #ifdef CONFIG_IWLWIFI_LEGACY_DEBUG
581         pos += scnprintf(buf + pos, bufsz - pos, "Frame transmitted:\t\t %u\n",
582                 priv->isr_stats.sch);
583         pos += scnprintf(buf + pos, bufsz - pos, "Alive interrupt:\t\t %u\n",
584                 priv->isr_stats.alive);
585 #endif
586         pos += scnprintf(buf + pos, bufsz - pos,
587                 "HW RF KILL switch toggled:\t %u\n",
588                 priv->isr_stats.rfkill);
589
590         pos += scnprintf(buf + pos, bufsz - pos, "CT KILL:\t\t\t %u\n",
591                 priv->isr_stats.ctkill);
592
593         pos += scnprintf(buf + pos, bufsz - pos, "Wakeup Interrupt:\t\t %u\n",
594                 priv->isr_stats.wakeup);
595
596         pos += scnprintf(buf + pos, bufsz - pos,
597                 "Rx command responses:\t\t %u\n",
598                 priv->isr_stats.rx);
599         for (cnt = 0; cnt < REPLY_MAX; cnt++) {
600                 if (priv->isr_stats.rx_handlers[cnt] > 0)
601                         pos += scnprintf(buf + pos, bufsz - pos,
602                                 "\tRx handler[%36s]:\t\t %u\n",
603                                 iwl_legacy_get_cmd_string(cnt),
604                                 priv->isr_stats.rx_handlers[cnt]);
605         }
606
607         pos += scnprintf(buf + pos, bufsz - pos, "Tx/FH interrupt:\t\t %u\n",
608                 priv->isr_stats.tx);
609
610         pos += scnprintf(buf + pos, bufsz - pos, "Unexpected INTA:\t\t %u\n",
611                 priv->isr_stats.unhandled);
612
613         ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
614         kfree(buf);
615         return ret;
616 }
617
618 static ssize_t iwl_legacy_dbgfs_interrupt_write(struct file *file,
619                                          const char __user *user_buf,
620                                          size_t count, loff_t *ppos)
621 {
622         struct iwl_priv *priv = file->private_data;
623         char buf[8];
624         int buf_size;
625         u32 reset_flag;
626
627         memset(buf, 0, sizeof(buf));
628         buf_size = min(count, sizeof(buf) -  1);
629         if (copy_from_user(buf, user_buf, buf_size))
630                 return -EFAULT;
631         if (sscanf(buf, "%x", &reset_flag) != 1)
632                 return -EFAULT;
633         if (reset_flag == 0)
634                 iwl_legacy_clear_isr_stats(priv);
635
636         return count;
637 }
638
639 static ssize_t
640 iwl_legacy_dbgfs_qos_read(struct file *file, char __user *user_buf,
641                                        size_t count, loff_t *ppos)
642 {
643         struct iwl_priv *priv = file->private_data;
644         struct iwl_rxon_context *ctx;
645         int pos = 0, i;
646         char buf[256 * NUM_IWL_RXON_CTX];
647         const size_t bufsz = sizeof(buf);
648
649         for_each_context(priv, ctx) {
650                 pos += scnprintf(buf + pos, bufsz - pos, "context %d:\n",
651                                  ctx->ctxid);
652                 for (i = 0; i < AC_NUM; i++) {
653                         pos += scnprintf(buf + pos, bufsz - pos,
654                                 "\tcw_min\tcw_max\taifsn\ttxop\n");
655                         pos += scnprintf(buf + pos, bufsz - pos,
656                                 "AC[%d]\t%u\t%u\t%u\t%u\n", i,
657                                 ctx->qos_data.def_qos_parm.ac[i].cw_min,
658                                 ctx->qos_data.def_qos_parm.ac[i].cw_max,
659                                 ctx->qos_data.def_qos_parm.ac[i].aifsn,
660                                 ctx->qos_data.def_qos_parm.ac[i].edca_txop);
661                 }
662                 pos += scnprintf(buf + pos, bufsz - pos, "\n");
663         }
664         return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
665 }
666
667 static ssize_t iwl_legacy_dbgfs_disable_ht40_write(struct file *file,
668                                          const char __user *user_buf,
669                                          size_t count, loff_t *ppos)
670 {
671         struct iwl_priv *priv = file->private_data;
672         char buf[8];
673         int buf_size;
674         int ht40;
675
676         memset(buf, 0, sizeof(buf));
677         buf_size = min(count, sizeof(buf) -  1);
678         if (copy_from_user(buf, user_buf, buf_size))
679                 return -EFAULT;
680         if (sscanf(buf, "%d", &ht40) != 1)
681                 return -EFAULT;
682         if (!iwl_legacy_is_any_associated(priv))
683                 priv->disable_ht40 = ht40 ? true : false;
684         else {
685                 IWL_ERR(priv, "Sta associated with AP - "
686                         "Change to 40MHz channel support is not allowed\n");
687                 return -EINVAL;
688         }
689
690         return count;
691 }
692
693 static ssize_t iwl_legacy_dbgfs_disable_ht40_read(struct file *file,
694                                          char __user *user_buf,
695                                          size_t count, loff_t *ppos)
696 {
697         struct iwl_priv *priv = file->private_data;
698         char buf[100];
699         int pos = 0;
700         const size_t bufsz = sizeof(buf);
701
702         pos += scnprintf(buf + pos, bufsz - pos,
703                         "11n 40MHz Mode: %s\n",
704                         priv->disable_ht40 ? "Disabled" : "Enabled");
705         return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
706 }
707
708 DEBUGFS_READ_WRITE_FILE_OPS(sram);
709 DEBUGFS_READ_WRITE_FILE_OPS(log_event);
710 DEBUGFS_READ_FILE_OPS(nvm);
711 DEBUGFS_READ_FILE_OPS(stations);
712 DEBUGFS_READ_FILE_OPS(channels);
713 DEBUGFS_READ_FILE_OPS(status);
714 DEBUGFS_READ_WRITE_FILE_OPS(interrupt);
715 DEBUGFS_READ_FILE_OPS(qos);
716 DEBUGFS_READ_WRITE_FILE_OPS(disable_ht40);
717
718 static ssize_t iwl_legacy_dbgfs_traffic_log_read(struct file *file,
719                                          char __user *user_buf,
720                                          size_t count, loff_t *ppos)
721 {
722         struct iwl_priv *priv = file->private_data;
723         int pos = 0, ofs = 0;
724         int cnt = 0, entry;
725         struct iwl_tx_queue *txq;
726         struct iwl_queue *q;
727         struct iwl_rx_queue *rxq = &priv->rxq;
728         char *buf;
729         int bufsz = ((IWL_TRAFFIC_ENTRIES * IWL_TRAFFIC_ENTRY_SIZE * 64) * 2) +
730                 (priv->cfg->base_params->num_of_queues * 32 * 8) + 400;
731         const u8 *ptr;
732         ssize_t ret;
733
734         if (!priv->txq) {
735                 IWL_ERR(priv, "txq not ready\n");
736                 return -EAGAIN;
737         }
738         buf = kzalloc(bufsz, GFP_KERNEL);
739         if (!buf) {
740                 IWL_ERR(priv, "Can not allocate buffer\n");
741                 return -ENOMEM;
742         }
743         pos += scnprintf(buf + pos, bufsz - pos, "Tx Queue\n");
744         for (cnt = 0; cnt < priv->hw_params.max_txq_num; cnt++) {
745                 txq = &priv->txq[cnt];
746                 q = &txq->q;
747                 pos += scnprintf(buf + pos, bufsz - pos,
748                                 "q[%d]: read_ptr: %u, write_ptr: %u\n",
749                                 cnt, q->read_ptr, q->write_ptr);
750         }
751         if (priv->tx_traffic && (iwl_debug_level & IWL_DL_TX)) {
752                 ptr = priv->tx_traffic;
753                 pos += scnprintf(buf + pos, bufsz - pos,
754                                 "Tx Traffic idx: %u\n", priv->tx_traffic_idx);
755                 for (cnt = 0, ofs = 0; cnt < IWL_TRAFFIC_ENTRIES; cnt++) {
756                         for (entry = 0; entry < IWL_TRAFFIC_ENTRY_SIZE / 16;
757                              entry++,  ofs += 16) {
758                                 pos += scnprintf(buf + pos, bufsz - pos,
759                                                 "0x%.4x ", ofs);
760                                 hex_dump_to_buffer(ptr + ofs, 16, 16, 2,
761                                                    buf + pos, bufsz - pos, 0);
762                                 pos += strlen(buf + pos);
763                                 if (bufsz - pos > 0)
764                                         buf[pos++] = '\n';
765                         }
766                 }
767         }
768
769         pos += scnprintf(buf + pos, bufsz - pos, "Rx Queue\n");
770         pos += scnprintf(buf + pos, bufsz - pos,
771                         "read: %u, write: %u\n",
772                          rxq->read, rxq->write);
773
774         if (priv->rx_traffic && (iwl_debug_level & IWL_DL_RX)) {
775                 ptr = priv->rx_traffic;
776                 pos += scnprintf(buf + pos, bufsz - pos,
777                                 "Rx Traffic idx: %u\n", priv->rx_traffic_idx);
778                 for (cnt = 0, ofs = 0; cnt < IWL_TRAFFIC_ENTRIES; cnt++) {
779                         for (entry = 0; entry < IWL_TRAFFIC_ENTRY_SIZE / 16;
780                              entry++,  ofs += 16) {
781                                 pos += scnprintf(buf + pos, bufsz - pos,
782                                                 "0x%.4x ", ofs);
783                                 hex_dump_to_buffer(ptr + ofs, 16, 16, 2,
784                                                    buf + pos, bufsz - pos, 0);
785                                 pos += strlen(buf + pos);
786                                 if (bufsz - pos > 0)
787                                         buf[pos++] = '\n';
788                         }
789                 }
790         }
791
792         ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
793         kfree(buf);
794         return ret;
795 }
796
797 static ssize_t iwl_legacy_dbgfs_traffic_log_write(struct file *file,
798                                          const char __user *user_buf,
799                                          size_t count, loff_t *ppos)
800 {
801         struct iwl_priv *priv = file->private_data;
802         char buf[8];
803         int buf_size;
804         int traffic_log;
805
806         memset(buf, 0, sizeof(buf));
807         buf_size = min(count, sizeof(buf) -  1);
808         if (copy_from_user(buf, user_buf, buf_size))
809                 return -EFAULT;
810         if (sscanf(buf, "%d", &traffic_log) != 1)
811                 return -EFAULT;
812         if (traffic_log == 0)
813                 iwl_legacy_reset_traffic_log(priv);
814
815         return count;
816 }
817
818 static ssize_t iwl_legacy_dbgfs_tx_queue_read(struct file *file,
819                                                 char __user *user_buf,
820                                                 size_t count, loff_t *ppos) {
821
822         struct iwl_priv *priv = file->private_data;
823         struct iwl_tx_queue *txq;
824         struct iwl_queue *q;
825         char *buf;
826         int pos = 0;
827         int cnt;
828         int ret;
829         const size_t bufsz = sizeof(char) * 64 *
830                                 priv->cfg->base_params->num_of_queues;
831
832         if (!priv->txq) {
833                 IWL_ERR(priv, "txq not ready\n");
834                 return -EAGAIN;
835         }
836         buf = kzalloc(bufsz, GFP_KERNEL);
837         if (!buf)
838                 return -ENOMEM;
839
840         for (cnt = 0; cnt < priv->hw_params.max_txq_num; cnt++) {
841                 txq = &priv->txq[cnt];
842                 q = &txq->q;
843                 pos += scnprintf(buf + pos, bufsz - pos,
844                                 "hwq %.2d: read=%u write=%u stop=%d"
845                                 " swq_id=%#.2x (ac %d/hwq %d)\n",
846                                 cnt, q->read_ptr, q->write_ptr,
847                                 !!test_bit(cnt, priv->queue_stopped),
848                                 txq->swq_id, txq->swq_id & 3,
849                                 (txq->swq_id >> 2) & 0x1f);
850                 if (cnt >= 4)
851                         continue;
852                 /* for the ACs, display the stop count too */
853                 pos += scnprintf(buf + pos, bufsz - pos,
854                                 "        stop-count: %d\n",
855                                 atomic_read(&priv->queue_stop_count[cnt]));
856         }
857         ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
858         kfree(buf);
859         return ret;
860 }
861
862 static ssize_t iwl_legacy_dbgfs_rx_queue_read(struct file *file,
863                                                 char __user *user_buf,
864                                                 size_t count, loff_t *ppos) {
865
866         struct iwl_priv *priv = file->private_data;
867         struct iwl_rx_queue *rxq = &priv->rxq;
868         char buf[256];
869         int pos = 0;
870         const size_t bufsz = sizeof(buf);
871
872         pos += scnprintf(buf + pos, bufsz - pos, "read: %u\n",
873                                                 rxq->read);
874         pos += scnprintf(buf + pos, bufsz - pos, "write: %u\n",
875                                                 rxq->write);
876         pos += scnprintf(buf + pos, bufsz - pos, "free_count: %u\n",
877                                                 rxq->free_count);
878         if (rxq->rb_stts) {
879                 pos += scnprintf(buf + pos, bufsz - pos, "closed_rb_num: %u\n",
880                          le16_to_cpu(rxq->rb_stts->closed_rb_num) &  0x0FFF);
881         } else {
882                 pos += scnprintf(buf + pos, bufsz - pos,
883                                         "closed_rb_num: Not Allocated\n");
884         }
885         return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
886 }
887
888 static ssize_t iwl_legacy_dbgfs_ucode_rx_stats_read(struct file *file,
889                                         char __user *user_buf,
890                                         size_t count, loff_t *ppos)
891 {
892         struct iwl_priv *priv = file->private_data;
893         return priv->cfg->ops->lib->debugfs_ops.rx_stats_read(file,
894                         user_buf, count, ppos);
895 }
896
897 static ssize_t iwl_legacy_dbgfs_ucode_tx_stats_read(struct file *file,
898                                         char __user *user_buf,
899                                         size_t count, loff_t *ppos)
900 {
901         struct iwl_priv *priv = file->private_data;
902         return priv->cfg->ops->lib->debugfs_ops.tx_stats_read(file,
903                         user_buf, count, ppos);
904 }
905
906 static ssize_t iwl_legacy_dbgfs_ucode_general_stats_read(struct file *file,
907                                         char __user *user_buf,
908                                         size_t count, loff_t *ppos)
909 {
910         struct iwl_priv *priv = file->private_data;
911         return priv->cfg->ops->lib->debugfs_ops.general_stats_read(file,
912                         user_buf, count, ppos);
913 }
914
915 static ssize_t iwl_legacy_dbgfs_sensitivity_read(struct file *file,
916                                         char __user *user_buf,
917                                         size_t count, loff_t *ppos) {
918
919         struct iwl_priv *priv = file->private_data;
920         int pos = 0;
921         int cnt = 0;
922         char *buf;
923         int bufsz = sizeof(struct iwl_sensitivity_data) * 4 + 100;
924         ssize_t ret;
925         struct iwl_sensitivity_data *data;
926
927         data = &priv->sensitivity_data;
928         buf = kzalloc(bufsz, GFP_KERNEL);
929         if (!buf) {
930                 IWL_ERR(priv, "Can not allocate Buffer\n");
931                 return -ENOMEM;
932         }
933
934         pos += scnprintf(buf + pos, bufsz - pos, "auto_corr_ofdm:\t\t\t %u\n",
935                         data->auto_corr_ofdm);
936         pos += scnprintf(buf + pos, bufsz - pos,
937                         "auto_corr_ofdm_mrc:\t\t %u\n",
938                         data->auto_corr_ofdm_mrc);
939         pos += scnprintf(buf + pos, bufsz - pos, "auto_corr_ofdm_x1:\t\t %u\n",
940                         data->auto_corr_ofdm_x1);
941         pos += scnprintf(buf + pos, bufsz - pos,
942                         "auto_corr_ofdm_mrc_x1:\t\t %u\n",
943                         data->auto_corr_ofdm_mrc_x1);
944         pos += scnprintf(buf + pos, bufsz - pos, "auto_corr_cck:\t\t\t %u\n",
945                         data->auto_corr_cck);
946         pos += scnprintf(buf + pos, bufsz - pos, "auto_corr_cck_mrc:\t\t %u\n",
947                         data->auto_corr_cck_mrc);
948         pos += scnprintf(buf + pos, bufsz - pos,
949                         "last_bad_plcp_cnt_ofdm:\t\t %u\n",
950                         data->last_bad_plcp_cnt_ofdm);
951         pos += scnprintf(buf + pos, bufsz - pos, "last_fa_cnt_ofdm:\t\t %u\n",
952                         data->last_fa_cnt_ofdm);
953         pos += scnprintf(buf + pos, bufsz - pos,
954                         "last_bad_plcp_cnt_cck:\t\t %u\n",
955                         data->last_bad_plcp_cnt_cck);
956         pos += scnprintf(buf + pos, bufsz - pos, "last_fa_cnt_cck:\t\t %u\n",
957                         data->last_fa_cnt_cck);
958         pos += scnprintf(buf + pos, bufsz - pos, "nrg_curr_state:\t\t\t %u\n",
959                         data->nrg_curr_state);
960         pos += scnprintf(buf + pos, bufsz - pos, "nrg_prev_state:\t\t\t %u\n",
961                         data->nrg_prev_state);
962         pos += scnprintf(buf + pos, bufsz - pos, "nrg_value:\t\t\t");
963         for (cnt = 0; cnt < 10; cnt++) {
964                 pos += scnprintf(buf + pos, bufsz - pos, " %u",
965                                 data->nrg_value[cnt]);
966         }
967         pos += scnprintf(buf + pos, bufsz - pos, "\n");
968         pos += scnprintf(buf + pos, bufsz - pos, "nrg_silence_rssi:\t\t");
969         for (cnt = 0; cnt < NRG_NUM_PREV_STAT_L; cnt++) {
970                 pos += scnprintf(buf + pos, bufsz - pos, " %u",
971                                 data->nrg_silence_rssi[cnt]);
972         }
973         pos += scnprintf(buf + pos, bufsz - pos, "\n");
974         pos += scnprintf(buf + pos, bufsz - pos, "nrg_silence_ref:\t\t %u\n",
975                         data->nrg_silence_ref);
976         pos += scnprintf(buf + pos, bufsz - pos, "nrg_energy_idx:\t\t\t %u\n",
977                         data->nrg_energy_idx);
978         pos += scnprintf(buf + pos, bufsz - pos, "nrg_silence_idx:\t\t %u\n",
979                         data->nrg_silence_idx);
980         pos += scnprintf(buf + pos, bufsz - pos, "nrg_th_cck:\t\t\t %u\n",
981                         data->nrg_th_cck);
982         pos += scnprintf(buf + pos, bufsz - pos,
983                         "nrg_auto_corr_silence_diff:\t %u\n",
984                         data->nrg_auto_corr_silence_diff);
985         pos += scnprintf(buf + pos, bufsz - pos, "num_in_cck_no_fa:\t\t %u\n",
986                         data->num_in_cck_no_fa);
987         pos += scnprintf(buf + pos, bufsz - pos, "nrg_th_ofdm:\t\t\t %u\n",
988                         data->nrg_th_ofdm);
989
990         ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
991         kfree(buf);
992         return ret;
993 }
994
995
996 static ssize_t iwl_legacy_dbgfs_chain_noise_read(struct file *file,
997                                         char __user *user_buf,
998                                         size_t count, loff_t *ppos) {
999
1000         struct iwl_priv *priv = file->private_data;
1001         int pos = 0;
1002         int cnt = 0;
1003         char *buf;
1004         int bufsz = sizeof(struct iwl_chain_noise_data) * 4 + 100;
1005         ssize_t ret;
1006         struct iwl_chain_noise_data *data;
1007
1008         data = &priv->chain_noise_data;
1009         buf = kzalloc(bufsz, GFP_KERNEL);
1010         if (!buf) {
1011                 IWL_ERR(priv, "Can not allocate Buffer\n");
1012                 return -ENOMEM;
1013         }
1014
1015         pos += scnprintf(buf + pos, bufsz - pos, "active_chains:\t\t\t %u\n",
1016                         data->active_chains);
1017         pos += scnprintf(buf + pos, bufsz - pos, "chain_noise_a:\t\t\t %u\n",
1018                         data->chain_noise_a);
1019         pos += scnprintf(buf + pos, bufsz - pos, "chain_noise_b:\t\t\t %u\n",
1020                         data->chain_noise_b);
1021         pos += scnprintf(buf + pos, bufsz - pos, "chain_noise_c:\t\t\t %u\n",
1022                         data->chain_noise_c);
1023         pos += scnprintf(buf + pos, bufsz - pos, "chain_signal_a:\t\t\t %u\n",
1024                         data->chain_signal_a);
1025         pos += scnprintf(buf + pos, bufsz - pos, "chain_signal_b:\t\t\t %u\n",
1026                         data->chain_signal_b);
1027         pos += scnprintf(buf + pos, bufsz - pos, "chain_signal_c:\t\t\t %u\n",
1028                         data->chain_signal_c);
1029         pos += scnprintf(buf + pos, bufsz - pos, "beacon_count:\t\t\t %u\n",
1030                         data->beacon_count);
1031
1032         pos += scnprintf(buf + pos, bufsz - pos, "disconn_array:\t\t\t");
1033         for (cnt = 0; cnt < NUM_RX_CHAINS; cnt++) {
1034                 pos += scnprintf(buf + pos, bufsz - pos, " %u",
1035                                 data->disconn_array[cnt]);
1036         }
1037         pos += scnprintf(buf + pos, bufsz - pos, "\n");
1038         pos += scnprintf(buf + pos, bufsz - pos, "delta_gain_code:\t\t");
1039         for (cnt = 0; cnt < NUM_RX_CHAINS; cnt++) {
1040                 pos += scnprintf(buf + pos, bufsz - pos, " %u",
1041                                 data->delta_gain_code[cnt]);
1042         }
1043         pos += scnprintf(buf + pos, bufsz - pos, "\n");
1044         pos += scnprintf(buf + pos, bufsz - pos, "radio_write:\t\t\t %u\n",
1045                         data->radio_write);
1046         pos += scnprintf(buf + pos, bufsz - pos, "state:\t\t\t\t %u\n",
1047                         data->state);
1048
1049         ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
1050         kfree(buf);
1051         return ret;
1052 }
1053
1054 static ssize_t iwl_legacy_dbgfs_power_save_status_read(struct file *file,
1055                                                     char __user *user_buf,
1056                                                     size_t count, loff_t *ppos)
1057 {
1058         struct iwl_priv *priv = file->private_data;
1059         char buf[60];
1060         int pos = 0;
1061         const size_t bufsz = sizeof(buf);
1062         u32 pwrsave_status;
1063
1064         pwrsave_status = iwl_read32(priv, CSR_GP_CNTRL) &
1065                         CSR_GP_REG_POWER_SAVE_STATUS_MSK;
1066
1067         pos += scnprintf(buf + pos, bufsz - pos, "Power Save Status: ");
1068         pos += scnprintf(buf + pos, bufsz - pos, "%s\n",
1069                 (pwrsave_status == CSR_GP_REG_NO_POWER_SAVE) ? "none" :
1070                 (pwrsave_status == CSR_GP_REG_MAC_POWER_SAVE) ? "MAC" :
1071                 (pwrsave_status == CSR_GP_REG_PHY_POWER_SAVE) ? "PHY" :
1072                 "error");
1073
1074         return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
1075 }
1076
1077 static ssize_t iwl_legacy_dbgfs_clear_ucode_statistics_write(struct file *file,
1078                                          const char __user *user_buf,
1079                                          size_t count, loff_t *ppos)
1080 {
1081         struct iwl_priv *priv = file->private_data;
1082         char buf[8];
1083         int buf_size;
1084         int clear;
1085
1086         memset(buf, 0, sizeof(buf));
1087         buf_size = min(count, sizeof(buf) -  1);
1088         if (copy_from_user(buf, user_buf, buf_size))
1089                 return -EFAULT;
1090         if (sscanf(buf, "%d", &clear) != 1)
1091                 return -EFAULT;
1092
1093         /* make request to uCode to retrieve statistics information */
1094         mutex_lock(&priv->mutex);
1095         iwl_legacy_send_statistics_request(priv, CMD_SYNC, true);
1096         mutex_unlock(&priv->mutex);
1097
1098         return count;
1099 }
1100
1101 static ssize_t iwl_legacy_dbgfs_ucode_tracing_read(struct file *file,
1102                                         char __user *user_buf,
1103                                         size_t count, loff_t *ppos) {
1104
1105         struct iwl_priv *priv = file->private_data;
1106         int pos = 0;
1107         char buf[128];
1108         const size_t bufsz = sizeof(buf);
1109
1110         pos += scnprintf(buf + pos, bufsz - pos, "ucode trace timer is %s\n",
1111                         priv->event_log.ucode_trace ? "On" : "Off");
1112         pos += scnprintf(buf + pos, bufsz - pos, "non_wraps_count:\t\t %u\n",
1113                         priv->event_log.non_wraps_count);
1114         pos += scnprintf(buf + pos, bufsz - pos, "wraps_once_count:\t\t %u\n",
1115                         priv->event_log.wraps_once_count);
1116         pos += scnprintf(buf + pos, bufsz - pos, "wraps_more_count:\t\t %u\n",
1117                         priv->event_log.wraps_more_count);
1118
1119         return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
1120 }
1121
1122 static ssize_t iwl_legacy_dbgfs_ucode_tracing_write(struct file *file,
1123                                          const char __user *user_buf,
1124                                          size_t count, loff_t *ppos)
1125 {
1126         struct iwl_priv *priv = file->private_data;
1127         char buf[8];
1128         int buf_size;
1129         int trace;
1130
1131         memset(buf, 0, sizeof(buf));
1132         buf_size = min(count, sizeof(buf) -  1);
1133         if (copy_from_user(buf, user_buf, buf_size))
1134                 return -EFAULT;
1135         if (sscanf(buf, "%d", &trace) != 1)
1136                 return -EFAULT;
1137
1138         if (trace) {
1139                 priv->event_log.ucode_trace = true;
1140                 /* schedule the ucode timer to occur in UCODE_TRACE_PERIOD */
1141                 mod_timer(&priv->ucode_trace,
1142                         jiffies + msecs_to_jiffies(UCODE_TRACE_PERIOD));
1143         } else {
1144                 priv->event_log.ucode_trace = false;
1145                 del_timer_sync(&priv->ucode_trace);
1146         }
1147
1148         return count;
1149 }
1150
1151 static ssize_t iwl_legacy_dbgfs_rxon_flags_read(struct file *file,
1152                                          char __user *user_buf,
1153                                          size_t count, loff_t *ppos) {
1154
1155         struct iwl_priv *priv = file->private_data;
1156         int len = 0;
1157         char buf[20];
1158
1159         len = sprintf(buf, "0x%04X\n",
1160                 le32_to_cpu(priv->contexts[IWL_RXON_CTX_BSS].active.flags));
1161         return simple_read_from_buffer(user_buf, count, ppos, buf, len);
1162 }
1163
1164 static ssize_t iwl_legacy_dbgfs_rxon_filter_flags_read(struct file *file,
1165                                                 char __user *user_buf,
1166                                                 size_t count, loff_t *ppos) {
1167
1168         struct iwl_priv *priv = file->private_data;
1169         int len = 0;
1170         char buf[20];
1171
1172         len = sprintf(buf, "0x%04X\n",
1173         le32_to_cpu(priv->contexts[IWL_RXON_CTX_BSS].active.filter_flags));
1174         return simple_read_from_buffer(user_buf, count, ppos, buf, len);
1175 }
1176
1177 static ssize_t iwl_legacy_dbgfs_fh_reg_read(struct file *file,
1178                                          char __user *user_buf,
1179                                          size_t count, loff_t *ppos)
1180 {
1181         struct iwl_priv *priv = file->private_data;
1182         char *buf;
1183         int pos = 0;
1184         ssize_t ret = -EFAULT;
1185
1186         if (priv->cfg->ops->lib->dump_fh) {
1187                 ret = pos = priv->cfg->ops->lib->dump_fh(priv, &buf, true);
1188                 if (buf) {
1189                         ret = simple_read_from_buffer(user_buf,
1190                                                       count, ppos, buf, pos);
1191                         kfree(buf);
1192                 }
1193         }
1194
1195         return ret;
1196 }
1197
1198 static ssize_t iwl_legacy_dbgfs_missed_beacon_read(struct file *file,
1199                                         char __user *user_buf,
1200                                         size_t count, loff_t *ppos) {
1201
1202         struct iwl_priv *priv = file->private_data;
1203         int pos = 0;
1204         char buf[12];
1205         const size_t bufsz = sizeof(buf);
1206
1207         pos += scnprintf(buf + pos, bufsz - pos, "%d\n",
1208                         priv->missed_beacon_threshold);
1209
1210         return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
1211 }
1212
1213 static ssize_t iwl_legacy_dbgfs_missed_beacon_write(struct file *file,
1214                                          const char __user *user_buf,
1215                                          size_t count, loff_t *ppos)
1216 {
1217         struct iwl_priv *priv = file->private_data;
1218         char buf[8];
1219         int buf_size;
1220         int missed;
1221
1222         memset(buf, 0, sizeof(buf));
1223         buf_size = min(count, sizeof(buf) -  1);
1224         if (copy_from_user(buf, user_buf, buf_size))
1225                 return -EFAULT;
1226         if (sscanf(buf, "%d", &missed) != 1)
1227                 return -EINVAL;
1228
1229         if (missed < IWL_MISSED_BEACON_THRESHOLD_MIN ||
1230             missed > IWL_MISSED_BEACON_THRESHOLD_MAX)
1231                 priv->missed_beacon_threshold =
1232                         IWL_MISSED_BEACON_THRESHOLD_DEF;
1233         else
1234                 priv->missed_beacon_threshold = missed;
1235
1236         return count;
1237 }
1238
1239 static ssize_t iwl_legacy_dbgfs_plcp_delta_read(struct file *file,
1240                                         char __user *user_buf,
1241                                         size_t count, loff_t *ppos) {
1242
1243         struct iwl_priv *priv = file->private_data;
1244         int pos = 0;
1245         char buf[12];
1246         const size_t bufsz = sizeof(buf);
1247
1248         pos += scnprintf(buf + pos, bufsz - pos, "%u\n",
1249                         priv->cfg->base_params->plcp_delta_threshold);
1250
1251         return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
1252 }
1253
1254 static ssize_t iwl_legacy_dbgfs_plcp_delta_write(struct file *file,
1255                                         const char __user *user_buf,
1256                                         size_t count, loff_t *ppos) {
1257
1258         struct iwl_priv *priv = file->private_data;
1259         char buf[8];
1260         int buf_size;
1261         int plcp;
1262
1263         memset(buf, 0, sizeof(buf));
1264         buf_size = min(count, sizeof(buf) -  1);
1265         if (copy_from_user(buf, user_buf, buf_size))
1266                 return -EFAULT;
1267         if (sscanf(buf, "%d", &plcp) != 1)
1268                 return -EINVAL;
1269         if ((plcp < IWL_MAX_PLCP_ERR_THRESHOLD_MIN) ||
1270                 (plcp > IWL_MAX_PLCP_ERR_THRESHOLD_MAX))
1271                 priv->cfg->base_params->plcp_delta_threshold =
1272                         IWL_MAX_PLCP_ERR_THRESHOLD_DISABLE;
1273         else
1274                 priv->cfg->base_params->plcp_delta_threshold = plcp;
1275         return count;
1276 }
1277
1278 static ssize_t iwl_legacy_dbgfs_force_reset_read(struct file *file,
1279                                         char __user *user_buf,
1280                                         size_t count, loff_t *ppos) {
1281
1282         struct iwl_priv *priv = file->private_data;
1283         int i, pos = 0;
1284         char buf[300];
1285         const size_t bufsz = sizeof(buf);
1286         struct iwl_force_reset *force_reset;
1287
1288         for (i = 0; i < IWL_MAX_FORCE_RESET; i++) {
1289                 force_reset = &priv->force_reset[i];
1290                 pos += scnprintf(buf + pos, bufsz - pos,
1291                                 "Force reset method %d\n", i);
1292                 pos += scnprintf(buf + pos, bufsz - pos,
1293                                 "\tnumber of reset request: %d\n",
1294                                 force_reset->reset_request_count);
1295                 pos += scnprintf(buf + pos, bufsz - pos,
1296                                 "\tnumber of reset request success: %d\n",
1297                                 force_reset->reset_success_count);
1298                 pos += scnprintf(buf + pos, bufsz - pos,
1299                                 "\tnumber of reset request reject: %d\n",
1300                                 force_reset->reset_reject_count);
1301                 pos += scnprintf(buf + pos, bufsz - pos,
1302                                 "\treset duration: %lu\n",
1303                                 force_reset->reset_duration);
1304         }
1305         return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
1306 }
1307
1308 static ssize_t iwl_legacy_dbgfs_force_reset_write(struct file *file,
1309                                         const char __user *user_buf,
1310                                         size_t count, loff_t *ppos) {
1311
1312         struct iwl_priv *priv = file->private_data;
1313         char buf[8];
1314         int buf_size;
1315         int reset, ret;
1316
1317         memset(buf, 0, sizeof(buf));
1318         buf_size = min(count, sizeof(buf) -  1);
1319         if (copy_from_user(buf, user_buf, buf_size))
1320                 return -EFAULT;
1321         if (sscanf(buf, "%d", &reset) != 1)
1322                 return -EINVAL;
1323         switch (reset) {
1324         case IWL_RF_RESET:
1325         case IWL_FW_RESET:
1326                 ret = iwl_legacy_force_reset(priv, reset, true);
1327                 break;
1328         default:
1329                 return -EINVAL;
1330         }
1331         return ret ? ret : count;
1332 }
1333
1334 static ssize_t iwl_legacy_dbgfs_wd_timeout_write(struct file *file,
1335                                         const char __user *user_buf,
1336                                         size_t count, loff_t *ppos) {
1337
1338         struct iwl_priv *priv = file->private_data;
1339         char buf[8];
1340         int buf_size;
1341         int timeout;
1342
1343         memset(buf, 0, sizeof(buf));
1344         buf_size = min(count, sizeof(buf) -  1);
1345         if (copy_from_user(buf, user_buf, buf_size))
1346                 return -EFAULT;
1347         if (sscanf(buf, "%d", &timeout) != 1)
1348                 return -EINVAL;
1349         if (timeout < 0 || timeout > IWL_MAX_WD_TIMEOUT)
1350                 timeout = IWL_DEF_WD_TIMEOUT;
1351
1352         priv->cfg->base_params->wd_timeout = timeout;
1353         iwl_legacy_setup_watchdog(priv);
1354         return count;
1355 }
1356
1357 DEBUGFS_READ_FILE_OPS(rx_statistics);
1358 DEBUGFS_READ_FILE_OPS(tx_statistics);
1359 DEBUGFS_READ_WRITE_FILE_OPS(traffic_log);
1360 DEBUGFS_READ_FILE_OPS(rx_queue);
1361 DEBUGFS_READ_FILE_OPS(tx_queue);
1362 DEBUGFS_READ_FILE_OPS(ucode_rx_stats);
1363 DEBUGFS_READ_FILE_OPS(ucode_tx_stats);
1364 DEBUGFS_READ_FILE_OPS(ucode_general_stats);
1365 DEBUGFS_READ_FILE_OPS(sensitivity);
1366 DEBUGFS_READ_FILE_OPS(chain_noise);
1367 DEBUGFS_READ_FILE_OPS(power_save_status);
1368 DEBUGFS_WRITE_FILE_OPS(clear_ucode_statistics);
1369 DEBUGFS_WRITE_FILE_OPS(clear_traffic_statistics);
1370 DEBUGFS_READ_WRITE_FILE_OPS(ucode_tracing);
1371 DEBUGFS_READ_FILE_OPS(fh_reg);
1372 DEBUGFS_READ_WRITE_FILE_OPS(missed_beacon);
1373 DEBUGFS_READ_WRITE_FILE_OPS(plcp_delta);
1374 DEBUGFS_READ_WRITE_FILE_OPS(force_reset);
1375 DEBUGFS_READ_FILE_OPS(rxon_flags);
1376 DEBUGFS_READ_FILE_OPS(rxon_filter_flags);
1377 DEBUGFS_WRITE_FILE_OPS(wd_timeout);
1378
1379 /*
1380  * Create the debugfs files and directories
1381  *
1382  */
1383 int iwl_legacy_dbgfs_register(struct iwl_priv *priv, const char *name)
1384 {
1385         struct dentry *phyd = priv->hw->wiphy->debugfsdir;
1386         struct dentry *dir_drv, *dir_data, *dir_rf, *dir_debug;
1387
1388         dir_drv = debugfs_create_dir(name, phyd);
1389         if (!dir_drv)
1390                 return -ENOMEM;
1391
1392         priv->debugfs_dir = dir_drv;
1393
1394         dir_data = debugfs_create_dir("data", dir_drv);
1395         if (!dir_data)
1396                 goto err;
1397         dir_rf = debugfs_create_dir("rf", dir_drv);
1398         if (!dir_rf)
1399                 goto err;
1400         dir_debug = debugfs_create_dir("debug", dir_drv);
1401         if (!dir_debug)
1402                 goto err;
1403
1404         DEBUGFS_ADD_FILE(nvm, dir_data, S_IRUSR);
1405         DEBUGFS_ADD_FILE(sram, dir_data, S_IWUSR | S_IRUSR);
1406         DEBUGFS_ADD_FILE(log_event, dir_data, S_IWUSR | S_IRUSR);
1407         DEBUGFS_ADD_FILE(stations, dir_data, S_IRUSR);
1408         DEBUGFS_ADD_FILE(channels, dir_data, S_IRUSR);
1409         DEBUGFS_ADD_FILE(status, dir_data, S_IRUSR);
1410         DEBUGFS_ADD_FILE(interrupt, dir_data, S_IWUSR | S_IRUSR);
1411         DEBUGFS_ADD_FILE(qos, dir_data, S_IRUSR);
1412         DEBUGFS_ADD_FILE(disable_ht40, dir_data, S_IWUSR | S_IRUSR);
1413         DEBUGFS_ADD_FILE(rx_statistics, dir_debug, S_IRUSR);
1414         DEBUGFS_ADD_FILE(tx_statistics, dir_debug, S_IRUSR);
1415         DEBUGFS_ADD_FILE(traffic_log, dir_debug, S_IWUSR | S_IRUSR);
1416         DEBUGFS_ADD_FILE(rx_queue, dir_debug, S_IRUSR);
1417         DEBUGFS_ADD_FILE(tx_queue, dir_debug, S_IRUSR);
1418         DEBUGFS_ADD_FILE(power_save_status, dir_debug, S_IRUSR);
1419         DEBUGFS_ADD_FILE(clear_ucode_statistics, dir_debug, S_IWUSR);
1420         DEBUGFS_ADD_FILE(clear_traffic_statistics, dir_debug, S_IWUSR);
1421         DEBUGFS_ADD_FILE(fh_reg, dir_debug, S_IRUSR);
1422         DEBUGFS_ADD_FILE(missed_beacon, dir_debug, S_IWUSR);
1423         DEBUGFS_ADD_FILE(plcp_delta, dir_debug, S_IWUSR | S_IRUSR);
1424         DEBUGFS_ADD_FILE(force_reset, dir_debug, S_IWUSR | S_IRUSR);
1425         DEBUGFS_ADD_FILE(ucode_rx_stats, dir_debug, S_IRUSR);
1426         DEBUGFS_ADD_FILE(ucode_tx_stats, dir_debug, S_IRUSR);
1427         DEBUGFS_ADD_FILE(ucode_general_stats, dir_debug, S_IRUSR);
1428
1429         if (priv->cfg->base_params->sensitivity_calib_by_driver)
1430                 DEBUGFS_ADD_FILE(sensitivity, dir_debug, S_IRUSR);
1431         if (priv->cfg->base_params->chain_noise_calib_by_driver)
1432                 DEBUGFS_ADD_FILE(chain_noise, dir_debug, S_IRUSR);
1433         if (priv->cfg->base_params->ucode_tracing)
1434                 DEBUGFS_ADD_FILE(ucode_tracing, dir_debug, S_IWUSR | S_IRUSR);
1435         DEBUGFS_ADD_FILE(rxon_flags, dir_debug, S_IWUSR);
1436         DEBUGFS_ADD_FILE(rxon_filter_flags, dir_debug, S_IWUSR);
1437         DEBUGFS_ADD_FILE(wd_timeout, dir_debug, S_IWUSR);
1438         if (priv->cfg->base_params->sensitivity_calib_by_driver)
1439                 DEBUGFS_ADD_BOOL(disable_sensitivity, dir_rf,
1440                                  &priv->disable_sens_cal);
1441         if (priv->cfg->base_params->chain_noise_calib_by_driver)
1442                 DEBUGFS_ADD_BOOL(disable_chain_noise, dir_rf,
1443                                  &priv->disable_chain_noise_cal);
1444         DEBUGFS_ADD_BOOL(disable_tx_power, dir_rf,
1445                                 &priv->disable_tx_power_cal);
1446         return 0;
1447
1448 err:
1449         IWL_ERR(priv, "Can't create the debugfs directory\n");
1450         iwl_legacy_dbgfs_unregister(priv);
1451         return -ENOMEM;
1452 }
1453 EXPORT_SYMBOL(iwl_legacy_dbgfs_register);
1454
1455 /**
1456  * Remove the debugfs files and directories
1457  *
1458  */
1459 void iwl_legacy_dbgfs_unregister(struct iwl_priv *priv)
1460 {
1461         if (!priv->debugfs_dir)
1462                 return;
1463
1464         debugfs_remove_recursive(priv->debugfs_dir);
1465         priv->debugfs_dir = NULL;
1466 }
1467 EXPORT_SYMBOL(iwl_legacy_dbgfs_unregister);