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