Merge branch 'wireless-next-2.6' of git://git.kernel.org/pub/scm/linux/kernel/git...
[pandora-kernel.git] / drivers / net / wireless / iwlwifi / iwl-debugfs.c
1 /******************************************************************************
2  *
3  * GPL LICENSE SUMMARY
4  *
5  * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of version 2 of the GNU General Public License as
9  * published by the Free Software Foundation.
10  *
11  * This program is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
19  * USA
20  *
21  * The full GNU General Public License is included in this distribution
22  * in the file called LICENSE.GPL.
23  *
24  * Contact Information:
25  *  Intel Linux Wireless <ilw@linux.intel.com>
26  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
27  *****************************************************************************/
28
29 #include <linux/slab.h>
30 #include <linux/kernel.h>
31 #include <linux/module.h>
32 #include <linux/debugfs.h>
33
34 #include <linux/ieee80211.h>
35 #include <net/mac80211.h>
36
37
38 #include "iwl-dev.h"
39 #include "iwl-debug.h"
40 #include "iwl-core.h"
41 #include "iwl-io.h"
42 #include "iwl-calib.h"
43
44 /* create and remove of files */
45 #define DEBUGFS_ADD_FILE(name, parent, mode) do {                       \
46         if (!debugfs_create_file(#name, mode, parent, priv,             \
47                                  &iwl_dbgfs_##name##_ops))              \
48                 goto err;                                               \
49 } while (0)
50
51 #define DEBUGFS_ADD_BOOL(name, parent, ptr) do {                        \
52         struct dentry *__tmp;                                           \
53         __tmp = debugfs_create_bool(#name, S_IWUSR | S_IRUSR,           \
54                                     parent, ptr);                       \
55         if (IS_ERR(__tmp) || !__tmp)                                    \
56                 goto err;                                               \
57 } while (0)
58
59 #define DEBUGFS_ADD_X32(name, parent, ptr) do {                         \
60         struct dentry *__tmp;                                           \
61         __tmp = debugfs_create_x32(#name, S_IWUSR | S_IRUSR,            \
62                                    parent, ptr);                        \
63         if (IS_ERR(__tmp) || !__tmp)                                    \
64                 goto err;                                               \
65 } while (0)
66
67 /* file operation */
68 #define DEBUGFS_READ_FUNC(name)                                         \
69 static ssize_t iwl_dbgfs_##name##_read(struct file *file,               \
70                                         char __user *user_buf,          \
71                                         size_t count, loff_t *ppos);
72
73 #define DEBUGFS_WRITE_FUNC(name)                                        \
74 static ssize_t iwl_dbgfs_##name##_write(struct file *file,              \
75                                         const char __user *user_buf,    \
76                                         size_t count, loff_t *ppos);
77
78
79 static int iwl_dbgfs_open_file_generic(struct inode *inode, struct file *file)
80 {
81         file->private_data = inode->i_private;
82         return 0;
83 }
84
85 #define DEBUGFS_READ_FILE_OPS(name)                                     \
86         DEBUGFS_READ_FUNC(name);                                        \
87 static const struct file_operations iwl_dbgfs_##name##_ops = {          \
88         .read = iwl_dbgfs_##name##_read,                                \
89         .open = iwl_dbgfs_open_file_generic,                            \
90 };
91
92 #define DEBUGFS_WRITE_FILE_OPS(name)                                    \
93         DEBUGFS_WRITE_FUNC(name);                                       \
94 static const struct file_operations iwl_dbgfs_##name##_ops = {          \
95         .write = iwl_dbgfs_##name##_write,                              \
96         .open = iwl_dbgfs_open_file_generic,                            \
97 };
98
99
100 #define DEBUGFS_READ_WRITE_FILE_OPS(name)                               \
101         DEBUGFS_READ_FUNC(name);                                        \
102         DEBUGFS_WRITE_FUNC(name);                                       \
103 static const struct file_operations iwl_dbgfs_##name##_ops = {          \
104         .write = iwl_dbgfs_##name##_write,                              \
105         .read = iwl_dbgfs_##name##_read,                                \
106         .open = iwl_dbgfs_open_file_generic,                            \
107 };
108
109 static ssize_t iwl_dbgfs_tx_statistics_read(struct file *file,
110                                                 char __user *user_buf,
111                                                 size_t count, loff_t *ppos) {
112
113         struct iwl_priv *priv = file->private_data;
114         char *buf;
115         int pos = 0;
116
117         int cnt;
118         ssize_t ret;
119         const size_t bufsz = 100 +
120                 sizeof(char) * 50 * (MANAGEMENT_MAX + CONTROL_MAX);
121         buf = kzalloc(bufsz, GFP_KERNEL);
122         if (!buf)
123                 return -ENOMEM;
124         pos += scnprintf(buf + pos, bufsz - pos, "Management:\n");
125         for (cnt = 0; cnt < MANAGEMENT_MAX; cnt++) {
126                 pos += scnprintf(buf + pos, bufsz - pos,
127                                  "\t%25s\t\t: %u\n",
128                                  get_mgmt_string(cnt),
129                                  priv->tx_stats.mgmt[cnt]);
130         }
131         pos += scnprintf(buf + pos, bufsz - pos, "Control\n");
132         for (cnt = 0; cnt < CONTROL_MAX; cnt++) {
133                 pos += scnprintf(buf + pos, bufsz - pos,
134                                  "\t%25s\t\t: %u\n",
135                                  get_ctrl_string(cnt),
136                                  priv->tx_stats.ctrl[cnt]);
137         }
138         pos += scnprintf(buf + pos, bufsz - pos, "Data:\n");
139         pos += scnprintf(buf + pos, bufsz - pos, "\tcnt: %u\n",
140                          priv->tx_stats.data_cnt);
141         pos += scnprintf(buf + pos, bufsz - pos, "\tbytes: %llu\n",
142                          priv->tx_stats.data_bytes);
143         ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
144         kfree(buf);
145         return ret;
146 }
147
148 static ssize_t iwl_dbgfs_clear_traffic_statistics_write(struct file *file,
149                                         const char __user *user_buf,
150                                         size_t count, loff_t *ppos)
151 {
152         struct iwl_priv *priv = file->private_data;
153         u32 clear_flag;
154         char buf[8];
155         int buf_size;
156
157         memset(buf, 0, sizeof(buf));
158         buf_size = min(count, sizeof(buf) -  1);
159         if (copy_from_user(buf, user_buf, buf_size))
160                 return -EFAULT;
161         if (sscanf(buf, "%x", &clear_flag) != 1)
162                 return -EFAULT;
163         iwl_clear_traffic_stats(priv);
164
165         return count;
166 }
167
168 static ssize_t iwl_dbgfs_rx_statistics_read(struct file *file,
169                                                 char __user *user_buf,
170                                                 size_t count, loff_t *ppos) {
171
172         struct iwl_priv *priv = file->private_data;
173         char *buf;
174         int pos = 0;
175         int cnt;
176         ssize_t ret;
177         const size_t bufsz = 100 +
178                 sizeof(char) * 50 * (MANAGEMENT_MAX + CONTROL_MAX);
179         buf = kzalloc(bufsz, GFP_KERNEL);
180         if (!buf)
181                 return -ENOMEM;
182
183         pos += scnprintf(buf + pos, bufsz - pos, "Management:\n");
184         for (cnt = 0; cnt < MANAGEMENT_MAX; cnt++) {
185                 pos += scnprintf(buf + pos, bufsz - pos,
186                                  "\t%25s\t\t: %u\n",
187                                  get_mgmt_string(cnt),
188                                  priv->rx_stats.mgmt[cnt]);
189         }
190         pos += scnprintf(buf + pos, bufsz - pos, "Control:\n");
191         for (cnt = 0; cnt < CONTROL_MAX; cnt++) {
192                 pos += scnprintf(buf + pos, bufsz - pos,
193                                  "\t%25s\t\t: %u\n",
194                                  get_ctrl_string(cnt),
195                                  priv->rx_stats.ctrl[cnt]);
196         }
197         pos += scnprintf(buf + pos, bufsz - pos, "Data:\n");
198         pos += scnprintf(buf + pos, bufsz - pos, "\tcnt: %u\n",
199                          priv->rx_stats.data_cnt);
200         pos += scnprintf(buf + pos, bufsz - pos, "\tbytes: %llu\n",
201                          priv->rx_stats.data_bytes);
202
203         ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
204         kfree(buf);
205         return ret;
206 }
207
208 #define BYTE1_MASK 0x000000ff;
209 #define BYTE2_MASK 0x0000ffff;
210 #define BYTE3_MASK 0x00ffffff;
211 static ssize_t iwl_dbgfs_sram_read(struct file *file,
212                                         char __user *user_buf,
213                                         size_t count, loff_t *ppos)
214 {
215         u32 val;
216         char *buf;
217         ssize_t ret;
218         int i;
219         int pos = 0;
220         struct iwl_priv *priv = file->private_data;
221         size_t bufsz;
222
223         /* default is to dump the entire data segment */
224         if (!priv->dbgfs_sram_offset && !priv->dbgfs_sram_len) {
225                 priv->dbgfs_sram_offset = 0x800000;
226                 if (priv->ucode_type == UCODE_INIT)
227                         priv->dbgfs_sram_len = priv->ucode_init_data.len;
228                 else
229                         priv->dbgfs_sram_len = priv->ucode_data.len;
230         }
231         bufsz =  30 + priv->dbgfs_sram_len * sizeof(char) * 10;
232         buf = kmalloc(bufsz, GFP_KERNEL);
233         if (!buf)
234                 return -ENOMEM;
235         pos += scnprintf(buf + pos, bufsz - pos, "sram_len: 0x%x\n",
236                         priv->dbgfs_sram_len);
237         pos += scnprintf(buf + pos, bufsz - pos, "sram_offset: 0x%x\n",
238                         priv->dbgfs_sram_offset);
239         for (i = priv->dbgfs_sram_len; i > 0; i -= 4) {
240                 val = iwl_read_targ_mem(priv, priv->dbgfs_sram_offset + \
241                                         priv->dbgfs_sram_len - i);
242                 if (i < 4) {
243                         switch (i) {
244                         case 1:
245                                 val &= BYTE1_MASK;
246                                 break;
247                         case 2:
248                                 val &= BYTE2_MASK;
249                                 break;
250                         case 3:
251                                 val &= BYTE3_MASK;
252                                 break;
253                         }
254                 }
255                 if (!(i % 16))
256                         pos += scnprintf(buf + pos, bufsz - pos, "\n");
257                 pos += scnprintf(buf + pos, bufsz - pos, "0x%08x ", val);
258         }
259         pos += scnprintf(buf + pos, bufsz - pos, "\n");
260
261         ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
262         kfree(buf);
263         return ret;
264 }
265
266 static ssize_t iwl_dbgfs_sram_write(struct file *file,
267                                         const char __user *user_buf,
268                                         size_t count, loff_t *ppos)
269 {
270         struct iwl_priv *priv = file->private_data;
271         char buf[64];
272         int buf_size;
273         u32 offset, len;
274
275         memset(buf, 0, sizeof(buf));
276         buf_size = min(count, sizeof(buf) -  1);
277         if (copy_from_user(buf, user_buf, buf_size))
278                 return -EFAULT;
279
280         if (sscanf(buf, "%x,%x", &offset, &len) == 2) {
281                 priv->dbgfs_sram_offset = offset;
282                 priv->dbgfs_sram_len = len;
283         } else {
284                 priv->dbgfs_sram_offset = 0;
285                 priv->dbgfs_sram_len = 0;
286         }
287
288         return count;
289 }
290
291 static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf,
292                                         size_t count, loff_t *ppos)
293 {
294         struct iwl_priv *priv = file->private_data;
295         struct iwl_station_entry *station;
296         int max_sta = priv->hw_params.max_stations;
297         char *buf;
298         int i, j, pos = 0;
299         ssize_t ret;
300         /* Add 30 for initial string */
301         const size_t bufsz = 30 + sizeof(char) * 500 * (priv->num_stations);
302
303         buf = kmalloc(bufsz, GFP_KERNEL);
304         if (!buf)
305                 return -ENOMEM;
306
307         pos += scnprintf(buf + pos, bufsz - pos, "num of stations: %d\n\n",
308                         priv->num_stations);
309
310         for (i = 0; i < max_sta; i++) {
311                 station = &priv->stations[i];
312                 if (!station->used)
313                         continue;
314                 pos += scnprintf(buf + pos, bufsz - pos,
315                                  "station %d - addr: %pM, flags: %#x\n",
316                                  i, station->sta.sta.addr,
317                                  station->sta.station_flags_msk);
318                 pos += scnprintf(buf + pos, bufsz - pos,
319                                 "TID\tseq_num\ttxq_id\tframes\ttfds\t");
320                 pos += scnprintf(buf + pos, bufsz - pos,
321                                 "start_idx\tbitmap\t\t\trate_n_flags\n");
322
323                 for (j = 0; j < MAX_TID_COUNT; j++) {
324                         pos += scnprintf(buf + pos, bufsz - pos,
325                                 "%d:\t%#x\t%#x\t%u\t%u\t%u\t\t%#.16llx\t%#x",
326                                 j, station->tid[j].seq_number,
327                                 station->tid[j].agg.txq_id,
328                                 station->tid[j].agg.frame_count,
329                                 station->tid[j].tfds_in_queue,
330                                 station->tid[j].agg.start_idx,
331                                 station->tid[j].agg.bitmap,
332                                 station->tid[j].agg.rate_n_flags);
333
334                         if (station->tid[j].agg.wait_for_ba)
335                                 pos += scnprintf(buf + pos, bufsz - pos,
336                                                  " - waitforba");
337                         pos += scnprintf(buf + pos, bufsz - pos, "\n");
338                 }
339
340                 pos += scnprintf(buf + pos, bufsz - pos, "\n");
341         }
342
343         ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
344         kfree(buf);
345         return ret;
346 }
347
348 static ssize_t iwl_dbgfs_nvm_read(struct file *file,
349                                        char __user *user_buf,
350                                        size_t count,
351                                        loff_t *ppos)
352 {
353         ssize_t ret;
354         struct iwl_priv *priv = file->private_data;
355         int pos = 0, ofs = 0, buf_size = 0;
356         const u8 *ptr;
357         char *buf;
358         u16 eeprom_ver;
359         size_t eeprom_len = priv->cfg->eeprom_size;
360         buf_size = 4 * eeprom_len + 256;
361
362         if (eeprom_len % 16) {
363                 IWL_ERR(priv, "NVM size is not multiple of 16.\n");
364                 return -ENODATA;
365         }
366
367         ptr = priv->eeprom;
368         if (!ptr) {
369                 IWL_ERR(priv, "Invalid EEPROM/OTP memory\n");
370                 return -ENOMEM;
371         }
372
373         /* 4 characters for byte 0xYY */
374         buf = kzalloc(buf_size, GFP_KERNEL);
375         if (!buf) {
376                 IWL_ERR(priv, "Can not allocate Buffer\n");
377                 return -ENOMEM;
378         }
379         eeprom_ver = iwl_eeprom_query16(priv, EEPROM_VERSION);
380         pos += scnprintf(buf + pos, buf_size - pos, "NVM Type: %s, "
381                         "version: 0x%x\n",
382                         (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP)
383                          ? "OTP" : "EEPROM", eeprom_ver);
384         for (ofs = 0 ; ofs < eeprom_len ; ofs += 16) {
385                 pos += scnprintf(buf + pos, buf_size - pos, "0x%.4x ", ofs);
386                 hex_dump_to_buffer(ptr + ofs, 16 , 16, 2, buf + pos,
387                                    buf_size - pos, 0);
388                 pos += strlen(buf + pos);
389                 if (buf_size - pos > 0)
390                         buf[pos++] = '\n';
391         }
392
393         ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
394         kfree(buf);
395         return ret;
396 }
397
398 static ssize_t iwl_dbgfs_log_event_read(struct file *file,
399                                          char __user *user_buf,
400                                          size_t count, loff_t *ppos)
401 {
402         struct iwl_priv *priv = file->private_data;
403         char *buf;
404         int pos = 0;
405         ssize_t ret = -ENOMEM;
406
407         ret = pos = priv->cfg->ops->lib->dump_nic_event_log(
408                                         priv, true, &buf, true);
409         if (buf) {
410                 ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
411                 kfree(buf);
412         }
413         return ret;
414 }
415
416 static ssize_t iwl_dbgfs_log_event_write(struct file *file,
417                                         const char __user *user_buf,
418                                         size_t count, loff_t *ppos)
419 {
420         struct iwl_priv *priv = file->private_data;
421         u32 event_log_flag;
422         char buf[8];
423         int buf_size;
424
425         memset(buf, 0, sizeof(buf));
426         buf_size = min(count, sizeof(buf) -  1);
427         if (copy_from_user(buf, user_buf, buf_size))
428                 return -EFAULT;
429         if (sscanf(buf, "%d", &event_log_flag) != 1)
430                 return -EFAULT;
431         if (event_log_flag == 1)
432                 priv->cfg->ops->lib->dump_nic_event_log(priv, true,
433                                                         NULL, false);
434
435         return count;
436 }
437
438
439
440 static ssize_t iwl_dbgfs_channels_read(struct file *file, char __user *user_buf,
441                                        size_t count, loff_t *ppos)
442 {
443         struct iwl_priv *priv = file->private_data;
444         struct ieee80211_channel *channels = NULL;
445         const struct ieee80211_supported_band *supp_band = NULL;
446         int pos = 0, i, bufsz = PAGE_SIZE;
447         char *buf;
448         ssize_t ret;
449
450         if (!test_bit(STATUS_GEO_CONFIGURED, &priv->status))
451                 return -EAGAIN;
452
453         buf = kzalloc(bufsz, GFP_KERNEL);
454         if (!buf) {
455                 IWL_ERR(priv, "Can not allocate Buffer\n");
456                 return -ENOMEM;
457         }
458
459         supp_band = iwl_get_hw_mode(priv, IEEE80211_BAND_2GHZ);
460         if (supp_band) {
461                 channels = supp_band->channels;
462
463                 pos += scnprintf(buf + pos, bufsz - pos,
464                                 "Displaying %d channels in 2.4GHz band 802.11bg):\n",
465                                 supp_band->n_channels);
466
467                 for (i = 0; i < supp_band->n_channels; i++)
468                         pos += scnprintf(buf + pos, bufsz - pos,
469                                         "%d: %ddBm: BSS%s%s, %s.\n",
470                                         ieee80211_frequency_to_channel(
471                                         channels[i].center_freq),
472                                         channels[i].max_power,
473                                         channels[i].flags & IEEE80211_CHAN_RADAR ?
474                                         " (IEEE 802.11h required)" : "",
475                                         ((channels[i].flags & IEEE80211_CHAN_NO_IBSS)
476                                         || (channels[i].flags &
477                                         IEEE80211_CHAN_RADAR)) ? "" :
478                                         ", IBSS",
479                                         channels[i].flags &
480                                         IEEE80211_CHAN_PASSIVE_SCAN ?
481                                         "passive only" : "active/passive");
482         }
483         supp_band = iwl_get_hw_mode(priv, IEEE80211_BAND_5GHZ);
484         if (supp_band) {
485                 channels = supp_band->channels;
486
487                 pos += scnprintf(buf + pos, bufsz - pos,
488                                 "Displaying %d channels in 5.2GHz band (802.11a)\n",
489                                 supp_band->n_channels);
490
491                 for (i = 0; i < supp_band->n_channels; i++)
492                         pos += scnprintf(buf + pos, bufsz - pos,
493                                         "%d: %ddBm: BSS%s%s, %s.\n",
494                                         ieee80211_frequency_to_channel(
495                                         channels[i].center_freq),
496                                         channels[i].max_power,
497                                         channels[i].flags & IEEE80211_CHAN_RADAR ?
498                                         " (IEEE 802.11h required)" : "",
499                                         ((channels[i].flags & IEEE80211_CHAN_NO_IBSS)
500                                         || (channels[i].flags &
501                                         IEEE80211_CHAN_RADAR)) ? "" :
502                                         ", IBSS",
503                                         channels[i].flags &
504                                         IEEE80211_CHAN_PASSIVE_SCAN ?
505                                         "passive only" : "active/passive");
506         }
507         ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
508         kfree(buf);
509         return ret;
510 }
511
512 static ssize_t iwl_dbgfs_status_read(struct file *file,
513                                                 char __user *user_buf,
514                                                 size_t count, loff_t *ppos) {
515
516         struct iwl_priv *priv = file->private_data;
517         char buf[512];
518         int pos = 0;
519         const size_t bufsz = sizeof(buf);
520
521         pos += scnprintf(buf + pos, bufsz - pos, "STATUS_HCMD_ACTIVE:\t %d\n",
522                 test_bit(STATUS_HCMD_ACTIVE, &priv->status));
523         pos += scnprintf(buf + pos, bufsz - pos, "STATUS_INT_ENABLED:\t %d\n",
524                 test_bit(STATUS_INT_ENABLED, &priv->status));
525         pos += scnprintf(buf + pos, bufsz - pos, "STATUS_RF_KILL_HW:\t %d\n",
526                 test_bit(STATUS_RF_KILL_HW, &priv->status));
527         pos += scnprintf(buf + pos, bufsz - pos, "STATUS_CT_KILL:\t\t %d\n",
528                 test_bit(STATUS_CT_KILL, &priv->status));
529         pos += scnprintf(buf + pos, bufsz - pos, "STATUS_INIT:\t\t %d\n",
530                 test_bit(STATUS_INIT, &priv->status));
531         pos += scnprintf(buf + pos, bufsz - pos, "STATUS_ALIVE:\t\t %d\n",
532                 test_bit(STATUS_ALIVE, &priv->status));
533         pos += scnprintf(buf + pos, bufsz - pos, "STATUS_READY:\t\t %d\n",
534                 test_bit(STATUS_READY, &priv->status));
535         pos += scnprintf(buf + pos, bufsz - pos, "STATUS_TEMPERATURE:\t %d\n",
536                 test_bit(STATUS_TEMPERATURE, &priv->status));
537         pos += scnprintf(buf + pos, bufsz - pos, "STATUS_GEO_CONFIGURED:\t %d\n",
538                 test_bit(STATUS_GEO_CONFIGURED, &priv->status));
539         pos += scnprintf(buf + pos, bufsz - pos, "STATUS_EXIT_PENDING:\t %d\n",
540                 test_bit(STATUS_EXIT_PENDING, &priv->status));
541         pos += scnprintf(buf + pos, bufsz - pos, "STATUS_STATISTICS:\t %d\n",
542                 test_bit(STATUS_STATISTICS, &priv->status));
543         pos += scnprintf(buf + pos, bufsz - pos, "STATUS_SCANNING:\t %d\n",
544                 test_bit(STATUS_SCANNING, &priv->status));
545         pos += scnprintf(buf + pos, bufsz - pos, "STATUS_SCAN_ABORTING:\t %d\n",
546                 test_bit(STATUS_SCAN_ABORTING, &priv->status));
547         pos += scnprintf(buf + pos, bufsz - pos, "STATUS_SCAN_HW:\t\t %d\n",
548                 test_bit(STATUS_SCAN_HW, &priv->status));
549         pos += scnprintf(buf + pos, bufsz - pos, "STATUS_POWER_PMI:\t %d\n",
550                 test_bit(STATUS_POWER_PMI, &priv->status));
551         pos += scnprintf(buf + pos, bufsz - pos, "STATUS_FW_ERROR:\t %d\n",
552                 test_bit(STATUS_FW_ERROR, &priv->status));
553         return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
554 }
555
556 static ssize_t iwl_dbgfs_interrupt_read(struct file *file,
557                                         char __user *user_buf,
558                                         size_t count, loff_t *ppos) {
559
560         struct iwl_priv *priv = file->private_data;
561         int pos = 0;
562         int cnt = 0;
563         char *buf;
564         int bufsz = 24 * 64; /* 24 items * 64 char per item */
565         ssize_t ret;
566
567         buf = kzalloc(bufsz, GFP_KERNEL);
568         if (!buf) {
569                 IWL_ERR(priv, "Can not allocate Buffer\n");
570                 return -ENOMEM;
571         }
572
573         pos += scnprintf(buf + pos, bufsz - pos,
574                         "Interrupt Statistics Report:\n");
575
576         pos += scnprintf(buf + pos, bufsz - pos, "HW Error:\t\t\t %u\n",
577                 priv->isr_stats.hw);
578         pos += scnprintf(buf + pos, bufsz - pos, "SW Error:\t\t\t %u\n",
579                 priv->isr_stats.sw);
580         if (priv->isr_stats.sw > 0) {
581                 pos += scnprintf(buf + pos, bufsz - pos,
582                         "\tLast Restarting Code:  0x%X\n",
583                         priv->isr_stats.sw_err);
584         }
585 #ifdef CONFIG_IWLWIFI_DEBUG
586         pos += scnprintf(buf + pos, bufsz - pos, "Frame transmitted:\t\t %u\n",
587                 priv->isr_stats.sch);
588         pos += scnprintf(buf + pos, bufsz - pos, "Alive interrupt:\t\t %u\n",
589                 priv->isr_stats.alive);
590 #endif
591         pos += scnprintf(buf + pos, bufsz - pos,
592                 "HW RF KILL switch toggled:\t %u\n",
593                 priv->isr_stats.rfkill);
594
595         pos += scnprintf(buf + pos, bufsz - pos, "CT KILL:\t\t\t %u\n",
596                 priv->isr_stats.ctkill);
597
598         pos += scnprintf(buf + pos, bufsz - pos, "Wakeup Interrupt:\t\t %u\n",
599                 priv->isr_stats.wakeup);
600
601         pos += scnprintf(buf + pos, bufsz - pos,
602                 "Rx command responses:\t\t %u\n",
603                 priv->isr_stats.rx);
604         for (cnt = 0; cnt < REPLY_MAX; cnt++) {
605                 if (priv->isr_stats.rx_handlers[cnt] > 0)
606                         pos += scnprintf(buf + pos, bufsz - pos,
607                                 "\tRx handler[%36s]:\t\t %u\n",
608                                 get_cmd_string(cnt),
609                                 priv->isr_stats.rx_handlers[cnt]);
610         }
611
612         pos += scnprintf(buf + pos, bufsz - pos, "Tx/FH interrupt:\t\t %u\n",
613                 priv->isr_stats.tx);
614
615         pos += scnprintf(buf + pos, bufsz - pos, "Unexpected INTA:\t\t %u\n",
616                 priv->isr_stats.unhandled);
617
618         ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
619         kfree(buf);
620         return ret;
621 }
622
623 static ssize_t iwl_dbgfs_interrupt_write(struct file *file,
624                                          const char __user *user_buf,
625                                          size_t count, loff_t *ppos)
626 {
627         struct iwl_priv *priv = file->private_data;
628         char buf[8];
629         int buf_size;
630         u32 reset_flag;
631
632         memset(buf, 0, sizeof(buf));
633         buf_size = min(count, sizeof(buf) -  1);
634         if (copy_from_user(buf, user_buf, buf_size))
635                 return -EFAULT;
636         if (sscanf(buf, "%x", &reset_flag) != 1)
637                 return -EFAULT;
638         if (reset_flag == 0)
639                 iwl_clear_isr_stats(priv);
640
641         return count;
642 }
643
644 static ssize_t iwl_dbgfs_qos_read(struct file *file, char __user *user_buf,
645                                        size_t count, loff_t *ppos)
646 {
647         struct iwl_priv *priv = file->private_data;
648         int pos = 0, i;
649         char buf[256];
650         const size_t bufsz = sizeof(buf);
651
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                                 priv->qos_data.def_qos_parm.ac[i].cw_min,
658                                 priv->qos_data.def_qos_parm.ac[i].cw_max,
659                                 priv->qos_data.def_qos_parm.ac[i].aifsn,
660                                 priv->qos_data.def_qos_parm.ac[i].edca_txop);
661         }
662         return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
663 }
664
665 static ssize_t iwl_dbgfs_led_read(struct file *file, char __user *user_buf,
666                                   size_t count, loff_t *ppos)
667 {
668         struct iwl_priv *priv = file->private_data;
669         int pos = 0;
670         char buf[256];
671         const size_t bufsz = sizeof(buf);
672
673         pos += scnprintf(buf + pos, bufsz - pos,
674                          "allow blinking: %s\n",
675                          (priv->allow_blinking) ? "True" : "False");
676         if (priv->allow_blinking) {
677                 pos += scnprintf(buf + pos, bufsz - pos,
678                                  "Led blinking rate: %u\n",
679                                  priv->last_blink_rate);
680                 pos += scnprintf(buf + pos, bufsz - pos,
681                                  "Last blink time: %lu\n",
682                                  priv->last_blink_time);
683         }
684
685         return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
686 }
687
688 static ssize_t iwl_dbgfs_thermal_throttling_read(struct file *file,
689                                 char __user *user_buf,
690                                 size_t count, loff_t *ppos)
691 {
692         struct iwl_priv *priv = file->private_data;
693         struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
694         struct iwl_tt_restriction *restriction;
695         char buf[100];
696         int pos = 0;
697         const size_t bufsz = sizeof(buf);
698
699         pos += scnprintf(buf + pos, bufsz - pos,
700                         "Thermal Throttling Mode: %s\n",
701                         tt->advanced_tt ? "Advance" : "Legacy");
702         pos += scnprintf(buf + pos, bufsz - pos,
703                         "Thermal Throttling State: %d\n",
704                         tt->state);
705         if (tt->advanced_tt) {
706                 restriction = tt->restriction + tt->state;
707                 pos += scnprintf(buf + pos, bufsz - pos,
708                                 "Tx mode: %d\n",
709                                 restriction->tx_stream);
710                 pos += scnprintf(buf + pos, bufsz - pos,
711                                 "Rx mode: %d\n",
712                                 restriction->rx_stream);
713                 pos += scnprintf(buf + pos, bufsz - pos,
714                                 "HT mode: %d\n",
715                                 restriction->is_ht);
716         }
717         return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
718 }
719
720 static ssize_t iwl_dbgfs_disable_ht40_write(struct file *file,
721                                          const char __user *user_buf,
722                                          size_t count, loff_t *ppos)
723 {
724         struct iwl_priv *priv = file->private_data;
725         char buf[8];
726         int buf_size;
727         int ht40;
728
729         memset(buf, 0, sizeof(buf));
730         buf_size = min(count, sizeof(buf) -  1);
731         if (copy_from_user(buf, user_buf, buf_size))
732                 return -EFAULT;
733         if (sscanf(buf, "%d", &ht40) != 1)
734                 return -EFAULT;
735         if (!iwl_is_associated(priv))
736                 priv->disable_ht40 = ht40 ? true : false;
737         else {
738                 IWL_ERR(priv, "Sta associated with AP - "
739                         "Change to 40MHz channel support is not allowed\n");
740                 return -EINVAL;
741         }
742
743         return count;
744 }
745
746 static ssize_t iwl_dbgfs_disable_ht40_read(struct file *file,
747                                          char __user *user_buf,
748                                          size_t count, loff_t *ppos)
749 {
750         struct iwl_priv *priv = file->private_data;
751         char buf[100];
752         int pos = 0;
753         const size_t bufsz = sizeof(buf);
754
755         pos += scnprintf(buf + pos, bufsz - pos,
756                         "11n 40MHz Mode: %s\n",
757                         priv->disable_ht40 ? "Disabled" : "Enabled");
758         return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
759 }
760
761 static ssize_t iwl_dbgfs_sleep_level_override_write(struct file *file,
762                                                     const char __user *user_buf,
763                                                     size_t count, loff_t *ppos)
764 {
765         struct iwl_priv *priv = file->private_data;
766         char buf[8];
767         int buf_size;
768         int value;
769
770         memset(buf, 0, sizeof(buf));
771         buf_size = min(count, sizeof(buf) -  1);
772         if (copy_from_user(buf, user_buf, buf_size))
773                 return -EFAULT;
774
775         if (sscanf(buf, "%d", &value) != 1)
776                 return -EINVAL;
777
778         /*
779          * Our users expect 0 to be "CAM", but 0 isn't actually
780          * valid here. However, let's not confuse them and present
781          * IWL_POWER_INDEX_1 as "1", not "0".
782          */
783         if (value == 0)
784                 return -EINVAL;
785         else if (value > 0)
786                 value -= 1;
787
788         if (value != -1 && (value < 0 || value >= IWL_POWER_NUM))
789                 return -EINVAL;
790
791         if (!iwl_is_ready_rf(priv))
792                 return -EAGAIN;
793
794         priv->power_data.debug_sleep_level_override = value;
795
796         mutex_lock(&priv->mutex);
797         iwl_power_update_mode(priv, true);
798         mutex_unlock(&priv->mutex);
799
800         return count;
801 }
802
803 static ssize_t iwl_dbgfs_sleep_level_override_read(struct file *file,
804                                                    char __user *user_buf,
805                                                    size_t count, loff_t *ppos)
806 {
807         struct iwl_priv *priv = file->private_data;
808         char buf[10];
809         int pos, value;
810         const size_t bufsz = sizeof(buf);
811
812         /* see the write function */
813         value = priv->power_data.debug_sleep_level_override;
814         if (value >= 0)
815                 value += 1;
816
817         pos = scnprintf(buf, bufsz, "%d\n", value);
818         return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
819 }
820
821 static ssize_t iwl_dbgfs_current_sleep_command_read(struct file *file,
822                                                     char __user *user_buf,
823                                                     size_t count, loff_t *ppos)
824 {
825         struct iwl_priv *priv = file->private_data;
826         char buf[200];
827         int pos = 0, i;
828         const size_t bufsz = sizeof(buf);
829         struct iwl_powertable_cmd *cmd = &priv->power_data.sleep_cmd;
830
831         pos += scnprintf(buf + pos, bufsz - pos,
832                          "flags: %#.2x\n", le16_to_cpu(cmd->flags));
833         pos += scnprintf(buf + pos, bufsz - pos,
834                          "RX/TX timeout: %d/%d usec\n",
835                          le32_to_cpu(cmd->rx_data_timeout),
836                          le32_to_cpu(cmd->tx_data_timeout));
837         for (i = 0; i < IWL_POWER_VEC_SIZE; i++)
838                 pos += scnprintf(buf + pos, bufsz - pos,
839                                  "sleep_interval[%d]: %d\n", i,
840                                  le32_to_cpu(cmd->sleep_interval[i]));
841
842         return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
843 }
844
845 DEBUGFS_READ_WRITE_FILE_OPS(sram);
846 DEBUGFS_READ_WRITE_FILE_OPS(log_event);
847 DEBUGFS_READ_FILE_OPS(nvm);
848 DEBUGFS_READ_FILE_OPS(stations);
849 DEBUGFS_READ_FILE_OPS(channels);
850 DEBUGFS_READ_FILE_OPS(status);
851 DEBUGFS_READ_WRITE_FILE_OPS(interrupt);
852 DEBUGFS_READ_FILE_OPS(qos);
853 DEBUGFS_READ_FILE_OPS(led);
854 DEBUGFS_READ_FILE_OPS(thermal_throttling);
855 DEBUGFS_READ_WRITE_FILE_OPS(disable_ht40);
856 DEBUGFS_READ_WRITE_FILE_OPS(sleep_level_override);
857 DEBUGFS_READ_FILE_OPS(current_sleep_command);
858
859 static ssize_t iwl_dbgfs_traffic_log_read(struct file *file,
860                                          char __user *user_buf,
861                                          size_t count, loff_t *ppos)
862 {
863         struct iwl_priv *priv = file->private_data;
864         int pos = 0, ofs = 0;
865         int cnt = 0, entry;
866         struct iwl_tx_queue *txq;
867         struct iwl_queue *q;
868         struct iwl_rx_queue *rxq = &priv->rxq;
869         char *buf;
870         int bufsz = ((IWL_TRAFFIC_ENTRIES * IWL_TRAFFIC_ENTRY_SIZE * 64) * 2) +
871                 (priv->cfg->num_of_queues * 32 * 8) + 400;
872         const u8 *ptr;
873         ssize_t ret;
874
875         if (!priv->txq) {
876                 IWL_ERR(priv, "txq not ready\n");
877                 return -EAGAIN;
878         }
879         buf = kzalloc(bufsz, GFP_KERNEL);
880         if (!buf) {
881                 IWL_ERR(priv, "Can not allocate buffer\n");
882                 return -ENOMEM;
883         }
884         pos += scnprintf(buf + pos, bufsz - pos, "Tx Queue\n");
885         for (cnt = 0; cnt < priv->hw_params.max_txq_num; cnt++) {
886                 txq = &priv->txq[cnt];
887                 q = &txq->q;
888                 pos += scnprintf(buf + pos, bufsz - pos,
889                                 "q[%d]: read_ptr: %u, write_ptr: %u\n",
890                                 cnt, q->read_ptr, q->write_ptr);
891         }
892         if (priv->tx_traffic && (iwl_debug_level & IWL_DL_TX)) {
893                 ptr = priv->tx_traffic;
894                 pos += scnprintf(buf + pos, bufsz - pos,
895                                 "Tx Traffic idx: %u\n", priv->tx_traffic_idx);
896                 for (cnt = 0, ofs = 0; cnt < IWL_TRAFFIC_ENTRIES; cnt++) {
897                         for (entry = 0; entry < IWL_TRAFFIC_ENTRY_SIZE / 16;
898                              entry++,  ofs += 16) {
899                                 pos += scnprintf(buf + pos, bufsz - pos,
900                                                 "0x%.4x ", ofs);
901                                 hex_dump_to_buffer(ptr + ofs, 16, 16, 2,
902                                                    buf + pos, bufsz - pos, 0);
903                                 pos += strlen(buf + pos);
904                                 if (bufsz - pos > 0)
905                                         buf[pos++] = '\n';
906                         }
907                 }
908         }
909
910         pos += scnprintf(buf + pos, bufsz - pos, "Rx Queue\n");
911         pos += scnprintf(buf + pos, bufsz - pos,
912                         "read: %u, write: %u\n",
913                          rxq->read, rxq->write);
914
915         if (priv->rx_traffic && (iwl_debug_level & IWL_DL_RX)) {
916                 ptr = priv->rx_traffic;
917                 pos += scnprintf(buf + pos, bufsz - pos,
918                                 "Rx Traffic idx: %u\n", priv->rx_traffic_idx);
919                 for (cnt = 0, ofs = 0; cnt < IWL_TRAFFIC_ENTRIES; cnt++) {
920                         for (entry = 0; entry < IWL_TRAFFIC_ENTRY_SIZE / 16;
921                              entry++,  ofs += 16) {
922                                 pos += scnprintf(buf + pos, bufsz - pos,
923                                                 "0x%.4x ", ofs);
924                                 hex_dump_to_buffer(ptr + ofs, 16, 16, 2,
925                                                    buf + pos, bufsz - pos, 0);
926                                 pos += strlen(buf + pos);
927                                 if (bufsz - pos > 0)
928                                         buf[pos++] = '\n';
929                         }
930                 }
931         }
932
933         ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
934         kfree(buf);
935         return ret;
936 }
937
938 static ssize_t iwl_dbgfs_traffic_log_write(struct file *file,
939                                          const char __user *user_buf,
940                                          size_t count, loff_t *ppos)
941 {
942         struct iwl_priv *priv = file->private_data;
943         char buf[8];
944         int buf_size;
945         int traffic_log;
946
947         memset(buf, 0, sizeof(buf));
948         buf_size = min(count, sizeof(buf) -  1);
949         if (copy_from_user(buf, user_buf, buf_size))
950                 return -EFAULT;
951         if (sscanf(buf, "%d", &traffic_log) != 1)
952                 return -EFAULT;
953         if (traffic_log == 0)
954                 iwl_reset_traffic_log(priv);
955
956         return count;
957 }
958
959 static ssize_t iwl_dbgfs_tx_queue_read(struct file *file,
960                                                 char __user *user_buf,
961                                                 size_t count, loff_t *ppos) {
962
963         struct iwl_priv *priv = file->private_data;
964         struct iwl_tx_queue *txq;
965         struct iwl_queue *q;
966         char *buf;
967         int pos = 0;
968         int cnt;
969         int ret;
970         const size_t bufsz = sizeof(char) * 64 * priv->cfg->num_of_queues;
971
972         if (!priv->txq) {
973                 IWL_ERR(priv, "txq not ready\n");
974                 return -EAGAIN;
975         }
976         buf = kzalloc(bufsz, GFP_KERNEL);
977         if (!buf)
978                 return -ENOMEM;
979
980         for (cnt = 0; cnt < priv->hw_params.max_txq_num; cnt++) {
981                 txq = &priv->txq[cnt];
982                 q = &txq->q;
983                 pos += scnprintf(buf + pos, bufsz - pos,
984                                 "hwq %.2d: read=%u write=%u stop=%d"
985                                 " swq_id=%#.2x (ac %d/hwq %d)\n",
986                                 cnt, q->read_ptr, q->write_ptr,
987                                 !!test_bit(cnt, priv->queue_stopped),
988                                 txq->swq_id,
989                                 txq->swq_id & 0x80 ? txq->swq_id & 3 :
990                                 txq->swq_id,
991                                 txq->swq_id & 0x80 ? (txq->swq_id >> 2) &
992                                 0x1f : txq->swq_id);
993                 if (cnt >= 4)
994                         continue;
995                 /* for the ACs, display the stop count too */
996                 pos += scnprintf(buf + pos, bufsz - pos,
997                                 "        stop-count: %d\n",
998                                 atomic_read(&priv->queue_stop_count[cnt]));
999         }
1000         ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
1001         kfree(buf);
1002         return ret;
1003 }
1004
1005 static ssize_t iwl_dbgfs_rx_queue_read(struct file *file,
1006                                                 char __user *user_buf,
1007                                                 size_t count, loff_t *ppos) {
1008
1009         struct iwl_priv *priv = file->private_data;
1010         struct iwl_rx_queue *rxq = &priv->rxq;
1011         char buf[256];
1012         int pos = 0;
1013         const size_t bufsz = sizeof(buf);
1014
1015         pos += scnprintf(buf + pos, bufsz - pos, "read: %u\n",
1016                                                 rxq->read);
1017         pos += scnprintf(buf + pos, bufsz - pos, "write: %u\n",
1018                                                 rxq->write);
1019         pos += scnprintf(buf + pos, bufsz - pos, "free_count: %u\n",
1020                                                 rxq->free_count);
1021         pos += scnprintf(buf + pos, bufsz - pos, "closed_rb_num: %u\n",
1022                          le16_to_cpu(rxq->rb_stts->closed_rb_num) &  0x0FFF);
1023         return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
1024 }
1025
1026 static ssize_t iwl_dbgfs_ucode_rx_stats_read(struct file *file,
1027                                         char __user *user_buf,
1028                                         size_t count, loff_t *ppos)
1029 {
1030         struct iwl_priv *priv = file->private_data;
1031         return priv->cfg->ops->lib->debugfs_ops.rx_stats_read(file,
1032                         user_buf, count, ppos);
1033 }
1034
1035 static ssize_t iwl_dbgfs_ucode_tx_stats_read(struct file *file,
1036                                         char __user *user_buf,
1037                                         size_t count, loff_t *ppos)
1038 {
1039         struct iwl_priv *priv = file->private_data;
1040         return priv->cfg->ops->lib->debugfs_ops.tx_stats_read(file,
1041                         user_buf, count, ppos);
1042 }
1043
1044 static ssize_t iwl_dbgfs_ucode_general_stats_read(struct file *file,
1045                                         char __user *user_buf,
1046                                         size_t count, loff_t *ppos)
1047 {
1048         struct iwl_priv *priv = file->private_data;
1049         return priv->cfg->ops->lib->debugfs_ops.general_stats_read(file,
1050                         user_buf, count, ppos);
1051 }
1052
1053 static ssize_t iwl_dbgfs_sensitivity_read(struct file *file,
1054                                         char __user *user_buf,
1055                                         size_t count, loff_t *ppos) {
1056
1057         struct iwl_priv *priv = file->private_data;
1058         int pos = 0;
1059         int cnt = 0;
1060         char *buf;
1061         int bufsz = sizeof(struct iwl_sensitivity_data) * 4 + 100;
1062         ssize_t ret;
1063         struct iwl_sensitivity_data *data;
1064
1065         data = &priv->sensitivity_data;
1066         buf = kzalloc(bufsz, GFP_KERNEL);
1067         if (!buf) {
1068                 IWL_ERR(priv, "Can not allocate Buffer\n");
1069                 return -ENOMEM;
1070         }
1071
1072         pos += scnprintf(buf + pos, bufsz - pos, "auto_corr_ofdm:\t\t\t %u\n",
1073                         data->auto_corr_ofdm);
1074         pos += scnprintf(buf + pos, bufsz - pos,
1075                         "auto_corr_ofdm_mrc:\t\t %u\n",
1076                         data->auto_corr_ofdm_mrc);
1077         pos += scnprintf(buf + pos, bufsz - pos, "auto_corr_ofdm_x1:\t\t %u\n",
1078                         data->auto_corr_ofdm_x1);
1079         pos += scnprintf(buf + pos, bufsz - pos,
1080                         "auto_corr_ofdm_mrc_x1:\t\t %u\n",
1081                         data->auto_corr_ofdm_mrc_x1);
1082         pos += scnprintf(buf + pos, bufsz - pos, "auto_corr_cck:\t\t\t %u\n",
1083                         data->auto_corr_cck);
1084         pos += scnprintf(buf + pos, bufsz - pos, "auto_corr_cck_mrc:\t\t %u\n",
1085                         data->auto_corr_cck_mrc);
1086         pos += scnprintf(buf + pos, bufsz - pos,
1087                         "last_bad_plcp_cnt_ofdm:\t\t %u\n",
1088                         data->last_bad_plcp_cnt_ofdm);
1089         pos += scnprintf(buf + pos, bufsz - pos, "last_fa_cnt_ofdm:\t\t %u\n",
1090                         data->last_fa_cnt_ofdm);
1091         pos += scnprintf(buf + pos, bufsz - pos,
1092                         "last_bad_plcp_cnt_cck:\t\t %u\n",
1093                         data->last_bad_plcp_cnt_cck);
1094         pos += scnprintf(buf + pos, bufsz - pos, "last_fa_cnt_cck:\t\t %u\n",
1095                         data->last_fa_cnt_cck);
1096         pos += scnprintf(buf + pos, bufsz - pos, "nrg_curr_state:\t\t\t %u\n",
1097                         data->nrg_curr_state);
1098         pos += scnprintf(buf + pos, bufsz - pos, "nrg_prev_state:\t\t\t %u\n",
1099                         data->nrg_prev_state);
1100         pos += scnprintf(buf + pos, bufsz - pos, "nrg_value:\t\t\t");
1101         for (cnt = 0; cnt < 10; cnt++) {
1102                 pos += scnprintf(buf + pos, bufsz - pos, " %u",
1103                                 data->nrg_value[cnt]);
1104         }
1105         pos += scnprintf(buf + pos, bufsz - pos, "\n");
1106         pos += scnprintf(buf + pos, bufsz - pos, "nrg_silence_rssi:\t\t");
1107         for (cnt = 0; cnt < NRG_NUM_PREV_STAT_L; cnt++) {
1108                 pos += scnprintf(buf + pos, bufsz - pos, " %u",
1109                                 data->nrg_silence_rssi[cnt]);
1110         }
1111         pos += scnprintf(buf + pos, bufsz - pos, "\n");
1112         pos += scnprintf(buf + pos, bufsz - pos, "nrg_silence_ref:\t\t %u\n",
1113                         data->nrg_silence_ref);
1114         pos += scnprintf(buf + pos, bufsz - pos, "nrg_energy_idx:\t\t\t %u\n",
1115                         data->nrg_energy_idx);
1116         pos += scnprintf(buf + pos, bufsz - pos, "nrg_silence_idx:\t\t %u\n",
1117                         data->nrg_silence_idx);
1118         pos += scnprintf(buf + pos, bufsz - pos, "nrg_th_cck:\t\t\t %u\n",
1119                         data->nrg_th_cck);
1120         pos += scnprintf(buf + pos, bufsz - pos,
1121                         "nrg_auto_corr_silence_diff:\t %u\n",
1122                         data->nrg_auto_corr_silence_diff);
1123         pos += scnprintf(buf + pos, bufsz - pos, "num_in_cck_no_fa:\t\t %u\n",
1124                         data->num_in_cck_no_fa);
1125         pos += scnprintf(buf + pos, bufsz - pos, "nrg_th_ofdm:\t\t\t %u\n",
1126                         data->nrg_th_ofdm);
1127
1128         ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
1129         kfree(buf);
1130         return ret;
1131 }
1132
1133
1134 static ssize_t iwl_dbgfs_chain_noise_read(struct file *file,
1135                                         char __user *user_buf,
1136                                         size_t count, loff_t *ppos) {
1137
1138         struct iwl_priv *priv = file->private_data;
1139         int pos = 0;
1140         int cnt = 0;
1141         char *buf;
1142         int bufsz = sizeof(struct iwl_chain_noise_data) * 4 + 100;
1143         ssize_t ret;
1144         struct iwl_chain_noise_data *data;
1145
1146         data = &priv->chain_noise_data;
1147         buf = kzalloc(bufsz, GFP_KERNEL);
1148         if (!buf) {
1149                 IWL_ERR(priv, "Can not allocate Buffer\n");
1150                 return -ENOMEM;
1151         }
1152
1153         pos += scnprintf(buf + pos, bufsz - pos, "active_chains:\t\t\t %u\n",
1154                         data->active_chains);
1155         pos += scnprintf(buf + pos, bufsz - pos, "chain_noise_a:\t\t\t %u\n",
1156                         data->chain_noise_a);
1157         pos += scnprintf(buf + pos, bufsz - pos, "chain_noise_b:\t\t\t %u\n",
1158                         data->chain_noise_b);
1159         pos += scnprintf(buf + pos, bufsz - pos, "chain_noise_c:\t\t\t %u\n",
1160                         data->chain_noise_c);
1161         pos += scnprintf(buf + pos, bufsz - pos, "chain_signal_a:\t\t\t %u\n",
1162                         data->chain_signal_a);
1163         pos += scnprintf(buf + pos, bufsz - pos, "chain_signal_b:\t\t\t %u\n",
1164                         data->chain_signal_b);
1165         pos += scnprintf(buf + pos, bufsz - pos, "chain_signal_c:\t\t\t %u\n",
1166                         data->chain_signal_c);
1167         pos += scnprintf(buf + pos, bufsz - pos, "beacon_count:\t\t\t %u\n",
1168                         data->beacon_count);
1169
1170         pos += scnprintf(buf + pos, bufsz - pos, "disconn_array:\t\t\t");
1171         for (cnt = 0; cnt < NUM_RX_CHAINS; cnt++) {
1172                 pos += scnprintf(buf + pos, bufsz - pos, " %u",
1173                                 data->disconn_array[cnt]);
1174         }
1175         pos += scnprintf(buf + pos, bufsz - pos, "\n");
1176         pos += scnprintf(buf + pos, bufsz - pos, "delta_gain_code:\t\t");
1177         for (cnt = 0; cnt < NUM_RX_CHAINS; cnt++) {
1178                 pos += scnprintf(buf + pos, bufsz - pos, " %u",
1179                                 data->delta_gain_code[cnt]);
1180         }
1181         pos += scnprintf(buf + pos, bufsz - pos, "\n");
1182         pos += scnprintf(buf + pos, bufsz - pos, "radio_write:\t\t\t %u\n",
1183                         data->radio_write);
1184         pos += scnprintf(buf + pos, bufsz - pos, "state:\t\t\t\t %u\n",
1185                         data->state);
1186
1187         ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
1188         kfree(buf);
1189         return ret;
1190 }
1191
1192 static ssize_t iwl_dbgfs_power_save_status_read(struct file *file,
1193                                                     char __user *user_buf,
1194                                                     size_t count, loff_t *ppos)
1195 {
1196         struct iwl_priv *priv = file->private_data;
1197         char buf[60];
1198         int pos = 0;
1199         const size_t bufsz = sizeof(buf);
1200         u32 pwrsave_status;
1201
1202         pwrsave_status = iwl_read32(priv, CSR_GP_CNTRL) &
1203                         CSR_GP_REG_POWER_SAVE_STATUS_MSK;
1204
1205         pos += scnprintf(buf + pos, bufsz - pos, "Power Save Status: ");
1206         pos += scnprintf(buf + pos, bufsz - pos, "%s\n",
1207                 (pwrsave_status == CSR_GP_REG_NO_POWER_SAVE) ? "none" :
1208                 (pwrsave_status == CSR_GP_REG_MAC_POWER_SAVE) ? "MAC" :
1209                 (pwrsave_status == CSR_GP_REG_PHY_POWER_SAVE) ? "PHY" :
1210                 "error");
1211
1212         return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
1213 }
1214
1215 static ssize_t iwl_dbgfs_clear_ucode_statistics_write(struct file *file,
1216                                          const char __user *user_buf,
1217                                          size_t count, loff_t *ppos)
1218 {
1219         struct iwl_priv *priv = file->private_data;
1220         char buf[8];
1221         int buf_size;
1222         int clear;
1223
1224         memset(buf, 0, sizeof(buf));
1225         buf_size = min(count, sizeof(buf) -  1);
1226         if (copy_from_user(buf, user_buf, buf_size))
1227                 return -EFAULT;
1228         if (sscanf(buf, "%d", &clear) != 1)
1229                 return -EFAULT;
1230
1231         /* make request to uCode to retrieve statistics information */
1232         mutex_lock(&priv->mutex);
1233         iwl_send_statistics_request(priv, CMD_SYNC, true);
1234         mutex_unlock(&priv->mutex);
1235
1236         return count;
1237 }
1238
1239 static ssize_t iwl_dbgfs_csr_write(struct file *file,
1240                                          const char __user *user_buf,
1241                                          size_t count, loff_t *ppos)
1242 {
1243         struct iwl_priv *priv = file->private_data;
1244         char buf[8];
1245         int buf_size;
1246         int csr;
1247
1248         memset(buf, 0, sizeof(buf));
1249         buf_size = min(count, sizeof(buf) -  1);
1250         if (copy_from_user(buf, user_buf, buf_size))
1251                 return -EFAULT;
1252         if (sscanf(buf, "%d", &csr) != 1)
1253                 return -EFAULT;
1254
1255         if (priv->cfg->ops->lib->dump_csr)
1256                 priv->cfg->ops->lib->dump_csr(priv);
1257
1258         return count;
1259 }
1260
1261 static ssize_t iwl_dbgfs_ucode_tracing_read(struct file *file,
1262                                         char __user *user_buf,
1263                                         size_t count, loff_t *ppos) {
1264
1265         struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
1266         int pos = 0;
1267         char buf[128];
1268         const size_t bufsz = sizeof(buf);
1269
1270         pos += scnprintf(buf + pos, bufsz - pos, "ucode trace timer is %s\n",
1271                         priv->event_log.ucode_trace ? "On" : "Off");
1272         pos += scnprintf(buf + pos, bufsz - pos, "non_wraps_count:\t\t %u\n",
1273                         priv->event_log.non_wraps_count);
1274         pos += scnprintf(buf + pos, bufsz - pos, "wraps_once_count:\t\t %u\n",
1275                         priv->event_log.wraps_once_count);
1276         pos += scnprintf(buf + pos, bufsz - pos, "wraps_more_count:\t\t %u\n",
1277                         priv->event_log.wraps_more_count);
1278
1279         return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
1280 }
1281
1282 static ssize_t iwl_dbgfs_ucode_tracing_write(struct file *file,
1283                                          const char __user *user_buf,
1284                                          size_t count, loff_t *ppos)
1285 {
1286         struct iwl_priv *priv = file->private_data;
1287         char buf[8];
1288         int buf_size;
1289         int trace;
1290
1291         memset(buf, 0, sizeof(buf));
1292         buf_size = min(count, sizeof(buf) -  1);
1293         if (copy_from_user(buf, user_buf, buf_size))
1294                 return -EFAULT;
1295         if (sscanf(buf, "%d", &trace) != 1)
1296                 return -EFAULT;
1297
1298         if (trace) {
1299                 priv->event_log.ucode_trace = true;
1300                 /* schedule the ucode timer to occur in UCODE_TRACE_PERIOD */
1301                 mod_timer(&priv->ucode_trace,
1302                         jiffies + msecs_to_jiffies(UCODE_TRACE_PERIOD));
1303         } else {
1304                 priv->event_log.ucode_trace = false;
1305                 del_timer_sync(&priv->ucode_trace);
1306         }
1307
1308         return count;
1309 }
1310
1311 static ssize_t iwl_dbgfs_rxon_flags_read(struct file *file,
1312                                          char __user *user_buf,
1313                                          size_t count, loff_t *ppos) {
1314
1315         struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
1316         int len = 0;
1317         char buf[20];
1318
1319         len = sprintf(buf, "0x%04X\n", le32_to_cpu(priv->active_rxon.flags));
1320         return simple_read_from_buffer(user_buf, count, ppos, buf, len);
1321 }
1322
1323 static ssize_t iwl_dbgfs_rxon_filter_flags_read(struct file *file,
1324                                                 char __user *user_buf,
1325                                                 size_t count, loff_t *ppos) {
1326
1327         struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
1328         int len = 0;
1329         char buf[20];
1330
1331         len = sprintf(buf, "0x%04X\n",
1332                       le32_to_cpu(priv->active_rxon.filter_flags));
1333         return simple_read_from_buffer(user_buf, count, ppos, buf, len);
1334 }
1335
1336 static ssize_t iwl_dbgfs_fh_reg_read(struct file *file,
1337                                          char __user *user_buf,
1338                                          size_t count, loff_t *ppos)
1339 {
1340         struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
1341         char *buf;
1342         int pos = 0;
1343         ssize_t ret = -EFAULT;
1344
1345         if (priv->cfg->ops->lib->dump_fh) {
1346                 ret = pos = priv->cfg->ops->lib->dump_fh(priv, &buf, true);
1347                 if (buf) {
1348                         ret = simple_read_from_buffer(user_buf,
1349                                                       count, ppos, buf, pos);
1350                         kfree(buf);
1351                 }
1352         }
1353
1354         return ret;
1355 }
1356
1357 static ssize_t iwl_dbgfs_missed_beacon_read(struct file *file,
1358                                         char __user *user_buf,
1359                                         size_t count, loff_t *ppos) {
1360
1361         struct iwl_priv *priv = file->private_data;
1362         int pos = 0;
1363         char buf[12];
1364         const size_t bufsz = sizeof(buf);
1365
1366         pos += scnprintf(buf + pos, bufsz - pos, "%d\n",
1367                         priv->missed_beacon_threshold);
1368
1369         return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
1370 }
1371
1372 static ssize_t iwl_dbgfs_missed_beacon_write(struct file *file,
1373                                          const char __user *user_buf,
1374                                          size_t count, loff_t *ppos)
1375 {
1376         struct iwl_priv *priv = file->private_data;
1377         char buf[8];
1378         int buf_size;
1379         int missed;
1380
1381         memset(buf, 0, sizeof(buf));
1382         buf_size = min(count, sizeof(buf) -  1);
1383         if (copy_from_user(buf, user_buf, buf_size))
1384                 return -EFAULT;
1385         if (sscanf(buf, "%d", &missed) != 1)
1386                 return -EINVAL;
1387
1388         if (missed < IWL_MISSED_BEACON_THRESHOLD_MIN ||
1389             missed > IWL_MISSED_BEACON_THRESHOLD_MAX)
1390                 priv->missed_beacon_threshold =
1391                         IWL_MISSED_BEACON_THRESHOLD_DEF;
1392         else
1393                 priv->missed_beacon_threshold = missed;
1394
1395         return count;
1396 }
1397
1398 static ssize_t iwl_dbgfs_plcp_delta_read(struct file *file,
1399                                         char __user *user_buf,
1400                                         size_t count, loff_t *ppos) {
1401
1402         struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
1403         int pos = 0;
1404         char buf[12];
1405         const size_t bufsz = sizeof(buf);
1406
1407         pos += scnprintf(buf + pos, bufsz - pos, "%u\n",
1408                         priv->cfg->plcp_delta_threshold);
1409
1410         return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
1411 }
1412
1413 static ssize_t iwl_dbgfs_plcp_delta_write(struct file *file,
1414                                         const char __user *user_buf,
1415                                         size_t count, loff_t *ppos) {
1416
1417         struct iwl_priv *priv = file->private_data;
1418         char buf[8];
1419         int buf_size;
1420         int plcp;
1421
1422         memset(buf, 0, sizeof(buf));
1423         buf_size = min(count, sizeof(buf) -  1);
1424         if (copy_from_user(buf, user_buf, buf_size))
1425                 return -EFAULT;
1426         if (sscanf(buf, "%d", &plcp) != 1)
1427                 return -EINVAL;
1428         if ((plcp <= IWL_MAX_PLCP_ERR_THRESHOLD_MIN) ||
1429                 (plcp > IWL_MAX_PLCP_ERR_THRESHOLD_MAX))
1430                 priv->cfg->plcp_delta_threshold =
1431                         IWL_MAX_PLCP_ERR_THRESHOLD_DEF;
1432         else
1433                 priv->cfg->plcp_delta_threshold = plcp;
1434         return count;
1435 }
1436
1437 static ssize_t iwl_dbgfs_force_reset_read(struct file *file,
1438                                         char __user *user_buf,
1439                                         size_t count, loff_t *ppos) {
1440
1441         struct iwl_priv *priv = file->private_data;
1442         int i, pos = 0;
1443         char buf[300];
1444         const size_t bufsz = sizeof(buf);
1445         struct iwl_force_reset *force_reset;
1446
1447         for (i = 0; i < IWL_MAX_FORCE_RESET; i++) {
1448                 force_reset = &priv->force_reset[i];
1449                 pos += scnprintf(buf + pos, bufsz - pos,
1450                                 "Force reset method %d\n", i);
1451                 pos += scnprintf(buf + pos, bufsz - pos,
1452                                 "\tnumber of reset request: %d\n",
1453                                 force_reset->reset_request_count);
1454                 pos += scnprintf(buf + pos, bufsz - pos,
1455                                 "\tnumber of reset request success: %d\n",
1456                                 force_reset->reset_success_count);
1457                 pos += scnprintf(buf + pos, bufsz - pos,
1458                                 "\tnumber of reset request reject: %d\n",
1459                                 force_reset->reset_reject_count);
1460                 pos += scnprintf(buf + pos, bufsz - pos,
1461                                 "\treset duration: %lu\n",
1462                                 force_reset->reset_duration);
1463         }
1464         return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
1465 }
1466
1467 static ssize_t iwl_dbgfs_force_reset_write(struct file *file,
1468                                         const char __user *user_buf,
1469                                         size_t count, loff_t *ppos) {
1470
1471         struct iwl_priv *priv = file->private_data;
1472         char buf[8];
1473         int buf_size;
1474         int reset, ret;
1475
1476         memset(buf, 0, sizeof(buf));
1477         buf_size = min(count, sizeof(buf) -  1);
1478         if (copy_from_user(buf, user_buf, buf_size))
1479                 return -EFAULT;
1480         if (sscanf(buf, "%d", &reset) != 1)
1481                 return -EINVAL;
1482         switch (reset) {
1483         case IWL_RF_RESET:
1484         case IWL_FW_RESET:
1485                 ret = iwl_force_reset(priv, reset);
1486                 break;
1487         default:
1488                 return -EINVAL;
1489         }
1490         return ret ? ret : count;
1491 }
1492
1493 DEBUGFS_READ_FILE_OPS(rx_statistics);
1494 DEBUGFS_READ_FILE_OPS(tx_statistics);
1495 DEBUGFS_READ_WRITE_FILE_OPS(traffic_log);
1496 DEBUGFS_READ_FILE_OPS(rx_queue);
1497 DEBUGFS_READ_FILE_OPS(tx_queue);
1498 DEBUGFS_READ_FILE_OPS(ucode_rx_stats);
1499 DEBUGFS_READ_FILE_OPS(ucode_tx_stats);
1500 DEBUGFS_READ_FILE_OPS(ucode_general_stats);
1501 DEBUGFS_READ_FILE_OPS(sensitivity);
1502 DEBUGFS_READ_FILE_OPS(chain_noise);
1503 DEBUGFS_READ_FILE_OPS(power_save_status);
1504 DEBUGFS_WRITE_FILE_OPS(clear_ucode_statistics);
1505 DEBUGFS_WRITE_FILE_OPS(clear_traffic_statistics);
1506 DEBUGFS_WRITE_FILE_OPS(csr);
1507 DEBUGFS_READ_WRITE_FILE_OPS(ucode_tracing);
1508 DEBUGFS_READ_FILE_OPS(fh_reg);
1509 DEBUGFS_READ_WRITE_FILE_OPS(missed_beacon);
1510 DEBUGFS_READ_WRITE_FILE_OPS(plcp_delta);
1511 DEBUGFS_READ_WRITE_FILE_OPS(force_reset);
1512 DEBUGFS_READ_FILE_OPS(rxon_flags);
1513 DEBUGFS_READ_FILE_OPS(rxon_filter_flags);
1514
1515 /*
1516  * Create the debugfs files and directories
1517  *
1518  */
1519 int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
1520 {
1521         struct dentry *phyd = priv->hw->wiphy->debugfsdir;
1522         struct dentry *dir_drv, *dir_data, *dir_rf, *dir_debug;
1523
1524         dir_drv = debugfs_create_dir(name, phyd);
1525         if (!dir_drv)
1526                 return -ENOMEM;
1527
1528         priv->debugfs_dir = dir_drv;
1529
1530         dir_data = debugfs_create_dir("data", dir_drv);
1531         if (!dir_data)
1532                 goto err;
1533         dir_rf = debugfs_create_dir("rf", dir_drv);
1534         if (!dir_rf)
1535                 goto err;
1536         dir_debug = debugfs_create_dir("debug", dir_drv);
1537         if (!dir_debug)
1538                 goto err;
1539
1540         DEBUGFS_ADD_FILE(nvm, dir_data, S_IRUSR);
1541         DEBUGFS_ADD_FILE(sram, dir_data, S_IWUSR | S_IRUSR);
1542         DEBUGFS_ADD_FILE(log_event, dir_data, S_IWUSR | S_IRUSR);
1543         DEBUGFS_ADD_FILE(stations, dir_data, S_IRUSR);
1544         DEBUGFS_ADD_FILE(channels, dir_data, S_IRUSR);
1545         DEBUGFS_ADD_FILE(status, dir_data, S_IRUSR);
1546         DEBUGFS_ADD_FILE(interrupt, dir_data, S_IWUSR | S_IRUSR);
1547         DEBUGFS_ADD_FILE(qos, dir_data, S_IRUSR);
1548         DEBUGFS_ADD_FILE(led, dir_data, S_IRUSR);
1549         if (!priv->cfg->broken_powersave) {
1550                 DEBUGFS_ADD_FILE(sleep_level_override, dir_data,
1551                                  S_IWUSR | S_IRUSR);
1552                 DEBUGFS_ADD_FILE(current_sleep_command, dir_data, S_IRUSR);
1553         }
1554         DEBUGFS_ADD_FILE(thermal_throttling, dir_data, S_IRUSR);
1555         DEBUGFS_ADD_FILE(disable_ht40, dir_data, S_IWUSR | S_IRUSR);
1556         DEBUGFS_ADD_FILE(rx_statistics, dir_debug, S_IRUSR);
1557         DEBUGFS_ADD_FILE(tx_statistics, dir_debug, S_IRUSR);
1558         DEBUGFS_ADD_FILE(traffic_log, dir_debug, S_IWUSR | S_IRUSR);
1559         DEBUGFS_ADD_FILE(rx_queue, dir_debug, S_IRUSR);
1560         DEBUGFS_ADD_FILE(tx_queue, dir_debug, S_IRUSR);
1561         DEBUGFS_ADD_FILE(power_save_status, dir_debug, S_IRUSR);
1562         DEBUGFS_ADD_FILE(clear_ucode_statistics, dir_debug, S_IWUSR);
1563         DEBUGFS_ADD_FILE(clear_traffic_statistics, dir_debug, S_IWUSR);
1564         DEBUGFS_ADD_FILE(csr, dir_debug, S_IWUSR);
1565         DEBUGFS_ADD_FILE(fh_reg, dir_debug, S_IRUSR);
1566         DEBUGFS_ADD_FILE(missed_beacon, dir_debug, S_IWUSR);
1567         DEBUGFS_ADD_FILE(plcp_delta, dir_debug, S_IWUSR | S_IRUSR);
1568         DEBUGFS_ADD_FILE(force_reset, dir_debug, S_IWUSR | S_IRUSR);
1569         DEBUGFS_ADD_FILE(ucode_rx_stats, dir_debug, S_IRUSR);
1570         DEBUGFS_ADD_FILE(ucode_tx_stats, dir_debug, S_IRUSR);
1571         DEBUGFS_ADD_FILE(ucode_general_stats, dir_debug, S_IRUSR);
1572
1573         if (priv->cfg->sensitivity_calib_by_driver)
1574                 DEBUGFS_ADD_FILE(sensitivity, dir_debug, S_IRUSR);
1575         if (priv->cfg->chain_noise_calib_by_driver)
1576                 DEBUGFS_ADD_FILE(chain_noise, dir_debug, S_IRUSR);
1577         if (priv->cfg->ucode_tracing)
1578                 DEBUGFS_ADD_FILE(ucode_tracing, dir_debug, S_IWUSR | S_IRUSR);
1579         DEBUGFS_ADD_FILE(rxon_flags, dir_debug, S_IWUSR);
1580         DEBUGFS_ADD_FILE(rxon_filter_flags, dir_debug, S_IWUSR);
1581         if (priv->cfg->sensitivity_calib_by_driver)
1582                 DEBUGFS_ADD_BOOL(disable_sensitivity, dir_rf,
1583                                  &priv->disable_sens_cal);
1584         if (priv->cfg->chain_noise_calib_by_driver)
1585                 DEBUGFS_ADD_BOOL(disable_chain_noise, dir_rf,
1586                                  &priv->disable_chain_noise_cal);
1587         if (priv->cfg->tx_power_by_driver)
1588                 DEBUGFS_ADD_BOOL(disable_tx_power, dir_rf,
1589                                 &priv->disable_tx_power_cal);
1590         return 0;
1591
1592 err:
1593         IWL_ERR(priv, "Can't create the debugfs directory\n");
1594         iwl_dbgfs_unregister(priv);
1595         return -ENOMEM;
1596 }
1597 EXPORT_SYMBOL(iwl_dbgfs_register);
1598
1599 /**
1600  * Remove the debugfs files and directories
1601  *
1602  */
1603 void iwl_dbgfs_unregister(struct iwl_priv *priv)
1604 {
1605         if (!priv->debugfs_dir)
1606                 return;
1607
1608         debugfs_remove_recursive(priv->debugfs_dir);
1609         priv->debugfs_dir = NULL;
1610 }
1611 EXPORT_SYMBOL(iwl_dbgfs_unregister);
1612
1613
1614