1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20#include <linux/debugfs.h>
21
22#include "main.h"
23#include "11n.h"
24
25
26static struct dentry *mwifiex_dfs_dir;
27
28static char *bss_modes[] = {
29 "UNSPECIFIED",
30 "ADHOC",
31 "STATION",
32 "AP",
33 "AP_VLAN",
34 "WDS",
35 "MONITOR",
36 "MESH_POINT",
37 "P2P_CLIENT",
38 "P2P_GO",
39 "P2P_DEVICE",
40};
41
42
43#define item_size(n) (FIELD_SIZEOF(struct mwifiex_debug_info, n))
44#define item_addr(n) (offsetof(struct mwifiex_debug_info, n))
45
46
47#define adapter_item_size(n) (FIELD_SIZEOF(struct mwifiex_adapter, n))
48#define adapter_item_addr(n) (offsetof(struct mwifiex_adapter, n))
49
50struct mwifiex_debug_data {
51 char name[32];
52 u32 size;
53 size_t addr;
54 int num;
55};
56
57static struct mwifiex_debug_data items[] = {
58 {"int_counter", item_size(int_counter),
59 item_addr(int_counter), 1},
60 {"wmm_ac_vo", item_size(packets_out[WMM_AC_VO]),
61 item_addr(packets_out[WMM_AC_VO]), 1},
62 {"wmm_ac_vi", item_size(packets_out[WMM_AC_VI]),
63 item_addr(packets_out[WMM_AC_VI]), 1},
64 {"wmm_ac_be", item_size(packets_out[WMM_AC_BE]),
65 item_addr(packets_out[WMM_AC_BE]), 1},
66 {"wmm_ac_bk", item_size(packets_out[WMM_AC_BK]),
67 item_addr(packets_out[WMM_AC_BK]), 1},
68 {"tx_buf_size", item_size(tx_buf_size),
69 item_addr(tx_buf_size), 1},
70 {"curr_tx_buf_size", item_size(curr_tx_buf_size),
71 item_addr(curr_tx_buf_size), 1},
72 {"ps_mode", item_size(ps_mode),
73 item_addr(ps_mode), 1},
74 {"ps_state", item_size(ps_state),
75 item_addr(ps_state), 1},
76 {"is_deep_sleep", item_size(is_deep_sleep),
77 item_addr(is_deep_sleep), 1},
78 {"wakeup_dev_req", item_size(pm_wakeup_card_req),
79 item_addr(pm_wakeup_card_req), 1},
80 {"wakeup_tries", item_size(pm_wakeup_fw_try),
81 item_addr(pm_wakeup_fw_try), 1},
82 {"hs_configured", item_size(is_hs_configured),
83 item_addr(is_hs_configured), 1},
84 {"hs_activated", item_size(hs_activated),
85 item_addr(hs_activated), 1},
86 {"num_tx_timeout", item_size(num_tx_timeout),
87 item_addr(num_tx_timeout), 1},
88 {"num_cmd_timeout", item_size(num_cmd_timeout),
89 item_addr(num_cmd_timeout), 1},
90 {"timeout_cmd_id", item_size(timeout_cmd_id),
91 item_addr(timeout_cmd_id), 1},
92 {"timeout_cmd_act", item_size(timeout_cmd_act),
93 item_addr(timeout_cmd_act), 1},
94 {"last_cmd_id", item_size(last_cmd_id),
95 item_addr(last_cmd_id), DBG_CMD_NUM},
96 {"last_cmd_act", item_size(last_cmd_act),
97 item_addr(last_cmd_act), DBG_CMD_NUM},
98 {"last_cmd_index", item_size(last_cmd_index),
99 item_addr(last_cmd_index), 1},
100 {"last_cmd_resp_id", item_size(last_cmd_resp_id),
101 item_addr(last_cmd_resp_id), DBG_CMD_NUM},
102 {"last_cmd_resp_index", item_size(last_cmd_resp_index),
103 item_addr(last_cmd_resp_index), 1},
104 {"last_event", item_size(last_event),
105 item_addr(last_event), DBG_CMD_NUM},
106 {"last_event_index", item_size(last_event_index),
107 item_addr(last_event_index), 1},
108 {"num_cmd_h2c_fail", item_size(num_cmd_host_to_card_failure),
109 item_addr(num_cmd_host_to_card_failure), 1},
110 {"num_cmd_sleep_cfm_fail",
111 item_size(num_cmd_sleep_cfm_host_to_card_failure),
112 item_addr(num_cmd_sleep_cfm_host_to_card_failure), 1},
113 {"num_tx_h2c_fail", item_size(num_tx_host_to_card_failure),
114 item_addr(num_tx_host_to_card_failure), 1},
115 {"num_evt_deauth", item_size(num_event_deauth),
116 item_addr(num_event_deauth), 1},
117 {"num_evt_disassoc", item_size(num_event_disassoc),
118 item_addr(num_event_disassoc), 1},
119 {"num_evt_link_lost", item_size(num_event_link_lost),
120 item_addr(num_event_link_lost), 1},
121 {"num_cmd_deauth", item_size(num_cmd_deauth),
122 item_addr(num_cmd_deauth), 1},
123 {"num_cmd_assoc_ok", item_size(num_cmd_assoc_success),
124 item_addr(num_cmd_assoc_success), 1},
125 {"num_cmd_assoc_fail", item_size(num_cmd_assoc_failure),
126 item_addr(num_cmd_assoc_failure), 1},
127 {"cmd_sent", item_size(cmd_sent),
128 item_addr(cmd_sent), 1},
129 {"data_sent", item_size(data_sent),
130 item_addr(data_sent), 1},
131 {"cmd_resp_received", item_size(cmd_resp_received),
132 item_addr(cmd_resp_received), 1},
133 {"event_received", item_size(event_received),
134 item_addr(event_received), 1},
135
136
137 {"cmd_pending", adapter_item_size(cmd_pending),
138 adapter_item_addr(cmd_pending), 1},
139 {"tx_pending", adapter_item_size(tx_pending),
140 adapter_item_addr(tx_pending), 1},
141 {"rx_pending", adapter_item_size(rx_pending),
142 adapter_item_addr(rx_pending), 1},
143};
144
145static int num_of_items = ARRAY_SIZE(items);
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178static ssize_t
179mwifiex_info_read(struct file *file, char __user *ubuf,
180 size_t count, loff_t *ppos)
181{
182 struct mwifiex_private *priv =
183 (struct mwifiex_private *) file->private_data;
184 struct net_device *netdev = priv->netdev;
185 struct netdev_hw_addr *ha;
186 struct netdev_queue *txq;
187 unsigned long page = get_zeroed_page(GFP_KERNEL);
188 char *p = (char *) page, fmt[64];
189 struct mwifiex_bss_info info;
190 ssize_t ret;
191 int i = 0;
192
193 if (!p)
194 return -ENOMEM;
195
196 memset(&info, 0, sizeof(info));
197 ret = mwifiex_get_bss_info(priv, &info);
198 if (ret)
199 goto free_and_exit;
200
201 mwifiex_drv_get_driver_version(priv->adapter, fmt, sizeof(fmt) - 1);
202
203 if (!priv->version_str[0])
204 mwifiex_get_ver_ext(priv);
205
206 p += sprintf(p, "driver_name = " "\"mwifiex\"\n");
207 p += sprintf(p, "driver_version = %s", fmt);
208 p += sprintf(p, "\nverext = %s", priv->version_str);
209 p += sprintf(p, "\ninterface_name=\"%s\"\n", netdev->name);
210
211 if (info.bss_mode >= ARRAY_SIZE(bss_modes))
212 p += sprintf(p, "bss_mode=\"%d\"\n", info.bss_mode);
213 else
214 p += sprintf(p, "bss_mode=\"%s\"\n", bss_modes[info.bss_mode]);
215
216 p += sprintf(p, "media_state=\"%s\"\n",
217 (!priv->media_connected ? "Disconnected" : "Connected"));
218 p += sprintf(p, "mac_address=\"%pM\"\n", netdev->dev_addr);
219
220 if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) {
221 p += sprintf(p, "multicast_count=\"%d\"\n",
222 netdev_mc_count(netdev));
223 p += sprintf(p, "essid=\"%s\"\n", info.ssid.ssid);
224 p += sprintf(p, "bssid=\"%pM\"\n", info.bssid);
225 p += sprintf(p, "channel=\"%d\"\n", (int) info.bss_chan);
226 p += sprintf(p, "country_code = \"%s\"\n", info.country_code);
227
228 netdev_for_each_mc_addr(ha, netdev)
229 p += sprintf(p, "multicast_address[%d]=\"%pM\"\n",
230 i++, ha->addr);
231 }
232
233 p += sprintf(p, "num_tx_bytes = %lu\n", priv->stats.tx_bytes);
234 p += sprintf(p, "num_rx_bytes = %lu\n", priv->stats.rx_bytes);
235 p += sprintf(p, "num_tx_pkts = %lu\n", priv->stats.tx_packets);
236 p += sprintf(p, "num_rx_pkts = %lu\n", priv->stats.rx_packets);
237 p += sprintf(p, "num_tx_pkts_dropped = %lu\n", priv->stats.tx_dropped);
238 p += sprintf(p, "num_rx_pkts_dropped = %lu\n", priv->stats.rx_dropped);
239 p += sprintf(p, "num_tx_pkts_err = %lu\n", priv->stats.tx_errors);
240 p += sprintf(p, "num_rx_pkts_err = %lu\n", priv->stats.rx_errors);
241 p += sprintf(p, "carrier %s\n", ((netif_carrier_ok(priv->netdev))
242 ? "on" : "off"));
243 p += sprintf(p, "tx queue");
244 for (i = 0; i < netdev->num_tx_queues; i++) {
245 txq = netdev_get_tx_queue(netdev, i);
246 p += sprintf(p, " %d:%s", i, netif_tx_queue_stopped(txq) ?
247 "stopped" : "started");
248 }
249 p += sprintf(p, "\n");
250
251 ret = simple_read_from_buffer(ubuf, count, ppos, (char *) page,
252 (unsigned long) p - page);
253
254free_and_exit:
255 free_page(page);
256 return ret;
257}
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278static ssize_t
279mwifiex_getlog_read(struct file *file, char __user *ubuf,
280 size_t count, loff_t *ppos)
281{
282 struct mwifiex_private *priv =
283 (struct mwifiex_private *) file->private_data;
284 unsigned long page = get_zeroed_page(GFP_KERNEL);
285 char *p = (char *) page;
286 ssize_t ret;
287 struct mwifiex_ds_get_stats stats;
288
289 if (!p)
290 return -ENOMEM;
291
292 memset(&stats, 0, sizeof(stats));
293 ret = mwifiex_get_stats_info(priv, &stats);
294 if (ret)
295 goto free_and_exit;
296
297 p += sprintf(p, "\n"
298 "mcasttxframe %u\n"
299 "failed %u\n"
300 "retry %u\n"
301 "multiretry %u\n"
302 "framedup %u\n"
303 "rtssuccess %u\n"
304 "rtsfailure %u\n"
305 "ackfailure %u\n"
306 "rxfrag %u\n"
307 "mcastrxframe %u\n"
308 "fcserror %u\n"
309 "txframe %u\n"
310 "wepicverrcnt-1 %u\n"
311 "wepicverrcnt-2 %u\n"
312 "wepicverrcnt-3 %u\n"
313 "wepicverrcnt-4 %u\n",
314 stats.mcast_tx_frame,
315 stats.failed,
316 stats.retry,
317 stats.multi_retry,
318 stats.frame_dup,
319 stats.rts_success,
320 stats.rts_failure,
321 stats.ack_failure,
322 stats.rx_frag,
323 stats.mcast_rx_frame,
324 stats.fcs_error,
325 stats.tx_frame,
326 stats.wep_icv_error[0],
327 stats.wep_icv_error[1],
328 stats.wep_icv_error[2],
329 stats.wep_icv_error[3]);
330
331
332 ret = simple_read_from_buffer(ubuf, count, ppos, (char *) page,
333 (unsigned long) p - page);
334
335free_and_exit:
336 free_page(page);
337 return ret;
338}
339
340static struct mwifiex_debug_info info;
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389static ssize_t
390mwifiex_debug_read(struct file *file, char __user *ubuf,
391 size_t count, loff_t *ppos)
392{
393 struct mwifiex_private *priv =
394 (struct mwifiex_private *) file->private_data;
395 struct mwifiex_debug_data *d = &items[0];
396 unsigned long page = get_zeroed_page(GFP_KERNEL);
397 char *p = (char *) page;
398 ssize_t ret;
399 size_t size, addr;
400 long val;
401 int i, j;
402
403 if (!p)
404 return -ENOMEM;
405
406 ret = mwifiex_get_debug_info(priv, &info);
407 if (ret)
408 goto free_and_exit;
409
410 for (i = 0; i < num_of_items; i++) {
411 p += sprintf(p, "%s=", d[i].name);
412
413 size = d[i].size / d[i].num;
414
415 if (i < (num_of_items - 3))
416 addr = d[i].addr + (size_t) &info;
417 else
418 addr = d[i].addr + (size_t) priv->adapter;
419
420 for (j = 0; j < d[i].num; j++) {
421 switch (size) {
422 case 1:
423 val = *((u8 *) addr);
424 break;
425 case 2:
426 val = *((u16 *) addr);
427 break;
428 case 4:
429 val = *((u32 *) addr);
430 break;
431 case 8:
432 val = *((long long *) addr);
433 break;
434 default:
435 val = -1;
436 break;
437 }
438
439 p += sprintf(p, "%#lx ", val);
440 addr += size;
441 }
442
443 p += sprintf(p, "\n");
444 }
445
446 if (info.tx_tbl_num) {
447 p += sprintf(p, "Tx BA stream table:\n");
448 for (i = 0; i < info.tx_tbl_num; i++)
449 p += sprintf(p, "tid = %d, ra = %pM\n",
450 info.tx_tbl[i].tid, info.tx_tbl[i].ra);
451 }
452
453 if (info.rx_tbl_num) {
454 p += sprintf(p, "Rx reorder table:\n");
455 for (i = 0; i < info.rx_tbl_num; i++) {
456 p += sprintf(p, "tid = %d, ta = %pM, "
457 "start_win = %d, "
458 "win_size = %d, buffer: ",
459 info.rx_tbl[i].tid,
460 info.rx_tbl[i].ta,
461 info.rx_tbl[i].start_win,
462 info.rx_tbl[i].win_size);
463
464 for (j = 0; j < info.rx_tbl[i].win_size; j++)
465 p += sprintf(p, "%c ",
466 info.rx_tbl[i].buffer[j] ?
467 '1' : '0');
468
469 p += sprintf(p, "\n");
470 }
471 }
472
473 ret = simple_read_from_buffer(ubuf, count, ppos, (char *) page,
474 (unsigned long) p - page);
475
476free_and_exit:
477 free_page(page);
478 return ret;
479}
480
481static u32 saved_reg_type, saved_reg_offset, saved_reg_value;
482
483
484
485
486
487
488
489
490static ssize_t
491mwifiex_regrdwr_write(struct file *file,
492 const char __user *ubuf, size_t count, loff_t *ppos)
493{
494 unsigned long addr = get_zeroed_page(GFP_KERNEL);
495 char *buf = (char *) addr;
496 size_t buf_size = min(count, (size_t) (PAGE_SIZE - 1));
497 int ret;
498 u32 reg_type = 0, reg_offset = 0, reg_value = UINT_MAX;
499
500 if (!buf)
501 return -ENOMEM;
502
503
504 if (copy_from_user(buf, ubuf, buf_size)) {
505 ret = -EFAULT;
506 goto done;
507 }
508
509 sscanf(buf, "%u %x %x", ®_type, ®_offset, ®_value);
510
511 if (reg_type == 0 || reg_offset == 0) {
512 ret = -EINVAL;
513 goto done;
514 } else {
515 saved_reg_type = reg_type;
516 saved_reg_offset = reg_offset;
517 saved_reg_value = reg_value;
518 ret = count;
519 }
520done:
521 free_page(addr);
522 return ret;
523}
524
525
526
527
528
529
530
531
532static ssize_t
533mwifiex_regrdwr_read(struct file *file, char __user *ubuf,
534 size_t count, loff_t *ppos)
535{
536 struct mwifiex_private *priv =
537 (struct mwifiex_private *) file->private_data;
538 unsigned long addr = get_zeroed_page(GFP_KERNEL);
539 char *buf = (char *) addr;
540 int pos = 0, ret = 0;
541 u32 reg_value;
542
543 if (!buf)
544 return -ENOMEM;
545
546 if (!saved_reg_type) {
547
548 pos += snprintf(buf, PAGE_SIZE, "0");
549 goto done;
550 }
551
552 if (saved_reg_value != UINT_MAX) {
553 ret = mwifiex_reg_write(priv, saved_reg_type, saved_reg_offset,
554 saved_reg_value);
555
556 pos += snprintf(buf, PAGE_SIZE, "%u 0x%x 0x%x\n",
557 saved_reg_type, saved_reg_offset,
558 saved_reg_value);
559
560 ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos);
561
562 goto done;
563 }
564
565 ret = mwifiex_reg_read(priv, saved_reg_type,
566 saved_reg_offset, ®_value);
567 if (ret) {
568 ret = -EINVAL;
569 goto done;
570 }
571
572 pos += snprintf(buf, PAGE_SIZE, "%u 0x%x 0x%x\n", saved_reg_type,
573 saved_reg_offset, reg_value);
574
575 ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos);
576
577done:
578 free_page(addr);
579 return ret;
580}
581
582static u32 saved_offset = -1, saved_bytes = -1;
583
584
585
586
587
588
589
590
591static ssize_t
592mwifiex_rdeeprom_write(struct file *file,
593 const char __user *ubuf, size_t count, loff_t *ppos)
594{
595 unsigned long addr = get_zeroed_page(GFP_KERNEL);
596 char *buf = (char *) addr;
597 size_t buf_size = min(count, (size_t) (PAGE_SIZE - 1));
598 int ret = 0;
599 int offset = -1, bytes = -1;
600
601 if (!buf)
602 return -ENOMEM;
603
604
605 if (copy_from_user(buf, ubuf, buf_size)) {
606 ret = -EFAULT;
607 goto done;
608 }
609
610 sscanf(buf, "%d %d", &offset, &bytes);
611
612 if (offset == -1 || bytes == -1) {
613 ret = -EINVAL;
614 goto done;
615 } else {
616 saved_offset = offset;
617 saved_bytes = bytes;
618 ret = count;
619 }
620done:
621 free_page(addr);
622 return ret;
623}
624
625
626
627
628
629
630
631
632static ssize_t
633mwifiex_rdeeprom_read(struct file *file, char __user *ubuf,
634 size_t count, loff_t *ppos)
635{
636 struct mwifiex_private *priv =
637 (struct mwifiex_private *) file->private_data;
638 unsigned long addr = get_zeroed_page(GFP_KERNEL);
639 char *buf = (char *) addr;
640 int pos = 0, ret = 0, i;
641 u8 value[MAX_EEPROM_DATA];
642
643 if (!buf)
644 return -ENOMEM;
645
646 if (saved_offset == -1) {
647
648 pos += snprintf(buf, PAGE_SIZE, "0");
649 goto done;
650 }
651
652
653 ret = mwifiex_eeprom_read(priv, (u16) saved_offset,
654 (u16) saved_bytes, value);
655 if (ret) {
656 ret = -EINVAL;
657 goto done;
658 }
659
660 pos += snprintf(buf, PAGE_SIZE, "%d %d ", saved_offset, saved_bytes);
661
662 for (i = 0; i < saved_bytes; i++)
663 pos += snprintf(buf + strlen(buf), PAGE_SIZE, "%d ", value[i]);
664
665 ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos);
666
667done:
668 free_page(addr);
669 return ret;
670}
671
672
673#define MWIFIEX_DFS_ADD_FILE(name) do { \
674 if (!debugfs_create_file(#name, 0644, priv->dfs_dev_dir, \
675 priv, &mwifiex_dfs_##name##_fops)) \
676 return; \
677} while (0);
678
679#define MWIFIEX_DFS_FILE_OPS(name) \
680static const struct file_operations mwifiex_dfs_##name##_fops = { \
681 .read = mwifiex_##name##_read, \
682 .write = mwifiex_##name##_write, \
683 .open = simple_open, \
684};
685
686#define MWIFIEX_DFS_FILE_READ_OPS(name) \
687static const struct file_operations mwifiex_dfs_##name##_fops = { \
688 .read = mwifiex_##name##_read, \
689 .open = simple_open, \
690};
691
692#define MWIFIEX_DFS_FILE_WRITE_OPS(name) \
693static const struct file_operations mwifiex_dfs_##name##_fops = { \
694 .write = mwifiex_##name##_write, \
695 .open = simple_open, \
696};
697
698
699MWIFIEX_DFS_FILE_READ_OPS(info);
700MWIFIEX_DFS_FILE_READ_OPS(debug);
701MWIFIEX_DFS_FILE_READ_OPS(getlog);
702MWIFIEX_DFS_FILE_OPS(regrdwr);
703MWIFIEX_DFS_FILE_OPS(rdeeprom);
704
705
706
707
708void
709mwifiex_dev_debugfs_init(struct mwifiex_private *priv)
710{
711 if (!mwifiex_dfs_dir || !priv)
712 return;
713
714 priv->dfs_dev_dir = debugfs_create_dir(priv->netdev->name,
715 mwifiex_dfs_dir);
716
717 if (!priv->dfs_dev_dir)
718 return;
719
720 MWIFIEX_DFS_ADD_FILE(info);
721 MWIFIEX_DFS_ADD_FILE(debug);
722 MWIFIEX_DFS_ADD_FILE(getlog);
723 MWIFIEX_DFS_ADD_FILE(regrdwr);
724 MWIFIEX_DFS_ADD_FILE(rdeeprom);
725}
726
727
728
729
730void
731mwifiex_dev_debugfs_remove(struct mwifiex_private *priv)
732{
733 if (!priv)
734 return;
735
736 debugfs_remove_recursive(priv->dfs_dev_dir);
737}
738
739
740
741
742void
743mwifiex_debugfs_init(void)
744{
745 if (!mwifiex_dfs_dir)
746 mwifiex_dfs_dir = debugfs_create_dir("mwifiex", NULL);
747}
748
749
750
751
752void
753mwifiex_debugfs_remove(void)
754{
755 if (mwifiex_dfs_dir)
756 debugfs_remove(mwifiex_dfs_dir);
757}
758