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