]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/net/wireless/ath/ath6kl/debug.c
ath9k: Fix ANI trigger threshold
[karo-tx-linux.git] / drivers / net / wireless / ath / ath6kl / debug.c
1 /*
2  * Copyright (c) 2004-2011 Atheros Communications Inc.
3  * Copyright (c) 2011-2012 Qualcomm Atheros, Inc.
4  *
5  * Permission to use, copy, modify, and/or distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17
18 #include "core.h"
19
20 #include <linux/skbuff.h>
21 #include <linux/fs.h>
22 #include <linux/vmalloc.h>
23 #include <linux/export.h>
24
25 #include "debug.h"
26 #include "target.h"
27
28 struct ath6kl_fwlog_slot {
29         __le32 timestamp;
30         __le32 length;
31
32         /* max ATH6KL_FWLOG_PAYLOAD_SIZE bytes */
33         u8 payload[0];
34 };
35
36 #define ATH6KL_FWLOG_MAX_ENTRIES 20
37
38 #define ATH6KL_FWLOG_VALID_MASK 0x1ffff
39
40 int ath6kl_printk(const char *level, const char *fmt, ...)
41 {
42         struct va_format vaf;
43         va_list args;
44         int rtn;
45
46         va_start(args, fmt);
47
48         vaf.fmt = fmt;
49         vaf.va = &args;
50
51         rtn = printk("%sath6kl: %pV", level, &vaf);
52
53         va_end(args);
54
55         return rtn;
56 }
57 EXPORT_SYMBOL(ath6kl_printk);
58
59 int ath6kl_info(const char *fmt, ...)
60 {
61         struct va_format vaf = {
62                 .fmt = fmt,
63         };
64         va_list args;
65         int ret;
66
67         va_start(args, fmt);
68         vaf.va = &args;
69         ret = ath6kl_printk(KERN_INFO, "%pV", &vaf);
70         trace_ath6kl_log_info(&vaf);
71         va_end(args);
72
73         return ret;
74 }
75 EXPORT_SYMBOL(ath6kl_info);
76
77 int ath6kl_err(const char *fmt, ...)
78 {
79         struct va_format vaf = {
80                 .fmt = fmt,
81         };
82         va_list args;
83         int ret;
84
85         va_start(args, fmt);
86         vaf.va = &args;
87         ret = ath6kl_printk(KERN_ERR, "%pV", &vaf);
88         trace_ath6kl_log_err(&vaf);
89         va_end(args);
90
91         return ret;
92 }
93 EXPORT_SYMBOL(ath6kl_err);
94
95 int ath6kl_warn(const char *fmt, ...)
96 {
97         struct va_format vaf = {
98                 .fmt = fmt,
99         };
100         va_list args;
101         int ret;
102
103         va_start(args, fmt);
104         vaf.va = &args;
105         ret = ath6kl_printk(KERN_WARNING, "%pV", &vaf);
106         trace_ath6kl_log_warn(&vaf);
107         va_end(args);
108
109         return ret;
110 }
111 EXPORT_SYMBOL(ath6kl_warn);
112
113 #ifdef CONFIG_ATH6KL_DEBUG
114
115 void ath6kl_dbg(enum ATH6K_DEBUG_MASK mask, const char *fmt, ...)
116 {
117         struct va_format vaf;
118         va_list args;
119
120         va_start(args, fmt);
121
122         vaf.fmt = fmt;
123         vaf.va = &args;
124
125         if (debug_mask & mask)
126                 ath6kl_printk(KERN_DEBUG, "%pV", &vaf);
127
128         trace_ath6kl_log_dbg(mask, &vaf);
129
130         va_end(args);
131 }
132 EXPORT_SYMBOL(ath6kl_dbg);
133
134 void ath6kl_dbg_dump(enum ATH6K_DEBUG_MASK mask,
135                      const char *msg, const char *prefix,
136                      const void *buf, size_t len)
137 {
138         if (debug_mask & mask) {
139                 if (msg)
140                         ath6kl_dbg(mask, "%s\n", msg);
141
142                 print_hex_dump_bytes(prefix, DUMP_PREFIX_OFFSET, buf, len);
143         }
144
145         /* tracing code doesn't like null strings :/ */
146         trace_ath6kl_log_dbg_dump(msg ? msg : "", prefix ? prefix : "",
147                                   buf, len);
148 }
149 EXPORT_SYMBOL(ath6kl_dbg_dump);
150
151 #define REG_OUTPUT_LEN_PER_LINE 25
152 #define REGTYPE_STR_LEN         100
153
154 struct ath6kl_diag_reg_info {
155         u32 reg_start;
156         u32 reg_end;
157         const char *reg_info;
158 };
159
160 static const struct ath6kl_diag_reg_info diag_reg[] = {
161         { 0x20000, 0x200fc, "General DMA and Rx registers" },
162         { 0x28000, 0x28900, "MAC PCU register & keycache" },
163         { 0x20800, 0x20a40, "QCU" },
164         { 0x21000, 0x212f0, "DCU" },
165         { 0x4000,  0x42e4, "RTC" },
166         { 0x540000, 0x540000 + (256 * 1024), "RAM" },
167         { 0x29800, 0x2B210, "Base Band" },
168         { 0x1C000, 0x1C748, "Analog" },
169 };
170
171 void ath6kl_dump_registers(struct ath6kl_device *dev,
172                            struct ath6kl_irq_proc_registers *irq_proc_reg,
173                            struct ath6kl_irq_enable_reg *irq_enable_reg)
174 {
175
176         ath6kl_dbg(ATH6KL_DBG_IRQ, ("<------- Register Table -------->\n"));
177
178         if (irq_proc_reg != NULL) {
179                 ath6kl_dbg(ATH6KL_DBG_IRQ,
180                            "Host Int status:           0x%x\n",
181                            irq_proc_reg->host_int_status);
182                 ath6kl_dbg(ATH6KL_DBG_IRQ,
183                            "CPU Int status:            0x%x\n",
184                            irq_proc_reg->cpu_int_status);
185                 ath6kl_dbg(ATH6KL_DBG_IRQ,
186                            "Error Int status:          0x%x\n",
187                            irq_proc_reg->error_int_status);
188                 ath6kl_dbg(ATH6KL_DBG_IRQ,
189                            "Counter Int status:        0x%x\n",
190                            irq_proc_reg->counter_int_status);
191                 ath6kl_dbg(ATH6KL_DBG_IRQ,
192                            "Mbox Frame:                0x%x\n",
193                            irq_proc_reg->mbox_frame);
194                 ath6kl_dbg(ATH6KL_DBG_IRQ,
195                            "Rx Lookahead Valid:        0x%x\n",
196                            irq_proc_reg->rx_lkahd_valid);
197                 ath6kl_dbg(ATH6KL_DBG_IRQ,
198                            "Rx Lookahead 0:            0x%x\n",
199                            irq_proc_reg->rx_lkahd[0]);
200                 ath6kl_dbg(ATH6KL_DBG_IRQ,
201                            "Rx Lookahead 1:            0x%x\n",
202                            irq_proc_reg->rx_lkahd[1]);
203
204                 if (dev->ar->mbox_info.gmbox_addr != 0) {
205                         /*
206                          * If the target supports GMBOX hardware, dump some
207                          * additional state.
208                          */
209                         ath6kl_dbg(ATH6KL_DBG_IRQ,
210                                    "GMBOX Host Int status 2:   0x%x\n",
211                                    irq_proc_reg->host_int_status2);
212                         ath6kl_dbg(ATH6KL_DBG_IRQ,
213                                    "GMBOX RX Avail:            0x%x\n",
214                                    irq_proc_reg->gmbox_rx_avail);
215                         ath6kl_dbg(ATH6KL_DBG_IRQ,
216                                    "GMBOX lookahead alias 0:   0x%x\n",
217                                    irq_proc_reg->rx_gmbox_lkahd_alias[0]);
218                         ath6kl_dbg(ATH6KL_DBG_IRQ,
219                                    "GMBOX lookahead alias 1:   0x%x\n",
220                                    irq_proc_reg->rx_gmbox_lkahd_alias[1]);
221                 }
222
223         }
224
225         if (irq_enable_reg != NULL) {
226                 ath6kl_dbg(ATH6KL_DBG_IRQ,
227                            "Int status Enable:         0x%x\n",
228                            irq_enable_reg->int_status_en);
229                 ath6kl_dbg(ATH6KL_DBG_IRQ, "Counter Int status Enable: 0x%x\n",
230                            irq_enable_reg->cntr_int_status_en);
231         }
232         ath6kl_dbg(ATH6KL_DBG_IRQ, "<------------------------------->\n");
233 }
234
235 static void dump_cred_dist(struct htc_endpoint_credit_dist *ep_dist)
236 {
237         ath6kl_dbg(ATH6KL_DBG_CREDIT,
238                    "--- endpoint: %d  svc_id: 0x%X ---\n",
239                    ep_dist->endpoint, ep_dist->svc_id);
240         ath6kl_dbg(ATH6KL_DBG_CREDIT, " dist_flags     : 0x%X\n",
241                    ep_dist->dist_flags);
242         ath6kl_dbg(ATH6KL_DBG_CREDIT, " cred_norm      : %d\n",
243                    ep_dist->cred_norm);
244         ath6kl_dbg(ATH6KL_DBG_CREDIT, " cred_min       : %d\n",
245                    ep_dist->cred_min);
246         ath6kl_dbg(ATH6KL_DBG_CREDIT, " credits        : %d\n",
247                    ep_dist->credits);
248         ath6kl_dbg(ATH6KL_DBG_CREDIT, " cred_assngd    : %d\n",
249                    ep_dist->cred_assngd);
250         ath6kl_dbg(ATH6KL_DBG_CREDIT, " seek_cred      : %d\n",
251                    ep_dist->seek_cred);
252         ath6kl_dbg(ATH6KL_DBG_CREDIT, " cred_sz        : %d\n",
253                    ep_dist->cred_sz);
254         ath6kl_dbg(ATH6KL_DBG_CREDIT, " cred_per_msg   : %d\n",
255                    ep_dist->cred_per_msg);
256         ath6kl_dbg(ATH6KL_DBG_CREDIT, " cred_to_dist   : %d\n",
257                    ep_dist->cred_to_dist);
258         ath6kl_dbg(ATH6KL_DBG_CREDIT, " txq_depth      : %d\n",
259                    get_queue_depth(&ep_dist->htc_ep->txq));
260         ath6kl_dbg(ATH6KL_DBG_CREDIT,
261                    "----------------------------------\n");
262 }
263
264 /* FIXME: move to htc.c */
265 void dump_cred_dist_stats(struct htc_target *target)
266 {
267         struct htc_endpoint_credit_dist *ep_list;
268
269         list_for_each_entry(ep_list, &target->cred_dist_list, list)
270                 dump_cred_dist(ep_list);
271
272         ath6kl_dbg(ATH6KL_DBG_CREDIT,
273                    "credit distribution total %d free %d\n",
274                    target->credit_info->total_avail_credits,
275                    target->credit_info->cur_free_credits);
276 }
277
278 void ath6kl_debug_war(struct ath6kl *ar, enum ath6kl_war war)
279 {
280         switch (war) {
281         case ATH6KL_WAR_INVALID_RATE:
282                 ar->debug.war_stats.invalid_rate++;
283                 break;
284         }
285 }
286
287 static ssize_t read_file_war_stats(struct file *file, char __user *user_buf,
288                                    size_t count, loff_t *ppos)
289 {
290         struct ath6kl *ar = file->private_data;
291         char *buf;
292         unsigned int len = 0, buf_len = 1500;
293         ssize_t ret_cnt;
294
295         buf = kzalloc(buf_len, GFP_KERNEL);
296         if (!buf)
297                 return -ENOMEM;
298
299         len += scnprintf(buf + len, buf_len - len, "\n");
300         len += scnprintf(buf + len, buf_len - len, "%25s\n",
301                          "Workaround stats");
302         len += scnprintf(buf + len, buf_len - len, "%25s\n\n",
303                          "=================");
304         len += scnprintf(buf + len, buf_len - len, "%20s %10u\n",
305                          "Invalid rates", ar->debug.war_stats.invalid_rate);
306
307         if (WARN_ON(len > buf_len))
308                 len = buf_len;
309
310         ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
311
312         kfree(buf);
313         return ret_cnt;
314 }
315
316 static const struct file_operations fops_war_stats = {
317         .read = read_file_war_stats,
318         .open = simple_open,
319         .owner = THIS_MODULE,
320         .llseek = default_llseek,
321 };
322
323 void ath6kl_debug_fwlog_event(struct ath6kl *ar, const void *buf, size_t len)
324 {
325         struct ath6kl_fwlog_slot *slot;
326         struct sk_buff *skb;
327         size_t slot_len;
328
329         if (WARN_ON(len > ATH6KL_FWLOG_PAYLOAD_SIZE))
330                 return;
331
332         slot_len = sizeof(*slot) + ATH6KL_FWLOG_PAYLOAD_SIZE;
333
334         skb = alloc_skb(slot_len, GFP_KERNEL);
335         if (!skb)
336                 return;
337
338         slot = (struct ath6kl_fwlog_slot *) skb_put(skb, slot_len);
339         slot->timestamp = cpu_to_le32(jiffies);
340         slot->length = cpu_to_le32(len);
341         memcpy(slot->payload, buf, len);
342
343         /* Need to pad each record to fixed length ATH6KL_FWLOG_PAYLOAD_SIZE */
344         memset(slot->payload + len, 0, ATH6KL_FWLOG_PAYLOAD_SIZE - len);
345
346         spin_lock(&ar->debug.fwlog_queue.lock);
347
348         __skb_queue_tail(&ar->debug.fwlog_queue, skb);
349         complete(&ar->debug.fwlog_completion);
350
351         /* drop oldest entries */
352         while (skb_queue_len(&ar->debug.fwlog_queue) >
353                ATH6KL_FWLOG_MAX_ENTRIES) {
354                 skb = __skb_dequeue(&ar->debug.fwlog_queue);
355                 kfree_skb(skb);
356         }
357
358         spin_unlock(&ar->debug.fwlog_queue.lock);
359
360         return;
361 }
362
363 static int ath6kl_fwlog_open(struct inode *inode, struct file *file)
364 {
365         struct ath6kl *ar = inode->i_private;
366
367         if (ar->debug.fwlog_open)
368                 return -EBUSY;
369
370         ar->debug.fwlog_open = true;
371
372         file->private_data = inode->i_private;
373         return 0;
374 }
375
376 static int ath6kl_fwlog_release(struct inode *inode, struct file *file)
377 {
378         struct ath6kl *ar = inode->i_private;
379
380         ar->debug.fwlog_open = false;
381
382         return 0;
383 }
384
385 static ssize_t ath6kl_fwlog_read(struct file *file, char __user *user_buf,
386                                  size_t count, loff_t *ppos)
387 {
388         struct ath6kl *ar = file->private_data;
389         struct sk_buff *skb;
390         ssize_t ret_cnt;
391         size_t len = 0;
392         char *buf;
393
394         buf = vmalloc(count);
395         if (!buf)
396                 return -ENOMEM;
397
398         /* read undelivered logs from firmware */
399         ath6kl_read_fwlogs(ar);
400
401         spin_lock(&ar->debug.fwlog_queue.lock);
402
403         while ((skb = __skb_dequeue(&ar->debug.fwlog_queue))) {
404                 if (skb->len > count - len) {
405                         /* not enough space, put skb back and leave */
406                         __skb_queue_head(&ar->debug.fwlog_queue, skb);
407                         break;
408                 }
409
410
411                 memcpy(buf + len, skb->data, skb->len);
412                 len += skb->len;
413
414                 kfree_skb(skb);
415         }
416
417         spin_unlock(&ar->debug.fwlog_queue.lock);
418
419         /* FIXME: what to do if len == 0? */
420
421         ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
422
423         vfree(buf);
424
425         return ret_cnt;
426 }
427
428 static const struct file_operations fops_fwlog = {
429         .open = ath6kl_fwlog_open,
430         .release = ath6kl_fwlog_release,
431         .read = ath6kl_fwlog_read,
432         .owner = THIS_MODULE,
433         .llseek = default_llseek,
434 };
435
436 static ssize_t ath6kl_fwlog_block_read(struct file *file,
437                                        char __user *user_buf,
438                                        size_t count,
439                                        loff_t *ppos)
440 {
441         struct ath6kl *ar = file->private_data;
442         struct sk_buff *skb;
443         ssize_t ret_cnt;
444         size_t len = 0, not_copied;
445         char *buf;
446         int ret;
447
448         buf = vmalloc(count);
449         if (!buf)
450                 return -ENOMEM;
451
452         spin_lock(&ar->debug.fwlog_queue.lock);
453
454         if (skb_queue_len(&ar->debug.fwlog_queue) == 0) {
455                 /* we must init under queue lock */
456                 init_completion(&ar->debug.fwlog_completion);
457
458                 spin_unlock(&ar->debug.fwlog_queue.lock);
459
460                 ret = wait_for_completion_interruptible(
461                         &ar->debug.fwlog_completion);
462                 if (ret == -ERESTARTSYS) {
463                         vfree(buf);
464                         return ret;
465                 }
466
467                 spin_lock(&ar->debug.fwlog_queue.lock);
468         }
469
470         while ((skb = __skb_dequeue(&ar->debug.fwlog_queue))) {
471                 if (skb->len > count - len) {
472                         /* not enough space, put skb back and leave */
473                         __skb_queue_head(&ar->debug.fwlog_queue, skb);
474                         break;
475                 }
476
477
478                 memcpy(buf + len, skb->data, skb->len);
479                 len += skb->len;
480
481                 kfree_skb(skb);
482         }
483
484         spin_unlock(&ar->debug.fwlog_queue.lock);
485
486         /* FIXME: what to do if len == 0? */
487
488         not_copied = copy_to_user(user_buf, buf, len);
489         if (not_copied != 0) {
490                 ret_cnt = -EFAULT;
491                 goto out;
492         }
493
494         *ppos = *ppos + len;
495
496         ret_cnt = len;
497
498 out:
499         vfree(buf);
500
501         return ret_cnt;
502 }
503
504 static const struct file_operations fops_fwlog_block = {
505         .open = ath6kl_fwlog_open,
506         .release = ath6kl_fwlog_release,
507         .read = ath6kl_fwlog_block_read,
508         .owner = THIS_MODULE,
509         .llseek = default_llseek,
510 };
511
512 static ssize_t ath6kl_fwlog_mask_read(struct file *file, char __user *user_buf,
513                                       size_t count, loff_t *ppos)
514 {
515         struct ath6kl *ar = file->private_data;
516         char buf[16];
517         int len;
518
519         len = snprintf(buf, sizeof(buf), "0x%x\n", ar->debug.fwlog_mask);
520
521         return simple_read_from_buffer(user_buf, count, ppos, buf, len);
522 }
523
524 static ssize_t ath6kl_fwlog_mask_write(struct file *file,
525                                        const char __user *user_buf,
526                                        size_t count, loff_t *ppos)
527 {
528         struct ath6kl *ar = file->private_data;
529         int ret;
530
531         ret = kstrtou32_from_user(user_buf, count, 0, &ar->debug.fwlog_mask);
532         if (ret)
533                 return ret;
534
535         ret = ath6kl_wmi_config_debug_module_cmd(ar->wmi,
536                                                  ATH6KL_FWLOG_VALID_MASK,
537                                                  ar->debug.fwlog_mask);
538         if (ret)
539                 return ret;
540
541         return count;
542 }
543
544 static const struct file_operations fops_fwlog_mask = {
545         .open = simple_open,
546         .read = ath6kl_fwlog_mask_read,
547         .write = ath6kl_fwlog_mask_write,
548         .owner = THIS_MODULE,
549         .llseek = default_llseek,
550 };
551
552 static ssize_t read_file_tgt_stats(struct file *file, char __user *user_buf,
553                                    size_t count, loff_t *ppos)
554 {
555         struct ath6kl *ar = file->private_data;
556         struct ath6kl_vif *vif;
557         struct target_stats *tgt_stats;
558         char *buf;
559         unsigned int len = 0, buf_len = 1500;
560         int i;
561         long left;
562         ssize_t ret_cnt;
563
564         vif = ath6kl_vif_first(ar);
565         if (!vif)
566                 return -EIO;
567
568         tgt_stats = &vif->target_stats;
569
570         buf = kzalloc(buf_len, GFP_KERNEL);
571         if (!buf)
572                 return -ENOMEM;
573
574         if (down_interruptible(&ar->sem)) {
575                 kfree(buf);
576                 return -EBUSY;
577         }
578
579         set_bit(STATS_UPDATE_PEND, &vif->flags);
580
581         if (ath6kl_wmi_get_stats_cmd(ar->wmi, 0)) {
582                 up(&ar->sem);
583                 kfree(buf);
584                 return -EIO;
585         }
586
587         left = wait_event_interruptible_timeout(ar->event_wq,
588                                                 !test_bit(STATS_UPDATE_PEND,
589                                                 &vif->flags), WMI_TIMEOUT);
590
591         up(&ar->sem);
592
593         if (left <= 0) {
594                 kfree(buf);
595                 return -ETIMEDOUT;
596         }
597
598         len += scnprintf(buf + len, buf_len - len, "\n");
599         len += scnprintf(buf + len, buf_len - len, "%25s\n",
600                          "Target Tx stats");
601         len += scnprintf(buf + len, buf_len - len, "%25s\n\n",
602                          "=================");
603         len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
604                          "Ucast packets", tgt_stats->tx_ucast_pkt);
605         len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
606                          "Bcast packets", tgt_stats->tx_bcast_pkt);
607         len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
608                          "Ucast byte", tgt_stats->tx_ucast_byte);
609         len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
610                          "Bcast byte", tgt_stats->tx_bcast_byte);
611         len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
612                          "Rts success cnt", tgt_stats->tx_rts_success_cnt);
613         for (i = 0; i < 4; i++)
614                 len += scnprintf(buf + len, buf_len - len,
615                                  "%18s %d %10llu\n", "PER on ac",
616                                  i, tgt_stats->tx_pkt_per_ac[i]);
617         len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
618                          "Error", tgt_stats->tx_err);
619         len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
620                          "Fail count", tgt_stats->tx_fail_cnt);
621         len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
622                          "Retry count", tgt_stats->tx_retry_cnt);
623         len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
624                          "Multi retry cnt", tgt_stats->tx_mult_retry_cnt);
625         len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
626                          "Rts fail cnt", tgt_stats->tx_rts_fail_cnt);
627         len += scnprintf(buf + len, buf_len - len, "%25s %10llu\n\n",
628                          "TKIP counter measure used",
629                          tgt_stats->tkip_cnter_measures_invoked);
630
631         len += scnprintf(buf + len, buf_len - len, "%25s\n",
632                          "Target Rx stats");
633         len += scnprintf(buf + len, buf_len - len, "%25s\n",
634                          "=================");
635
636         len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
637                          "Ucast packets", tgt_stats->rx_ucast_pkt);
638         len += scnprintf(buf + len, buf_len - len, "%20s %10d\n",
639                          "Ucast Rate", tgt_stats->rx_ucast_rate);
640         len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
641                          "Bcast packets", tgt_stats->rx_bcast_pkt);
642         len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
643                          "Ucast byte", tgt_stats->rx_ucast_byte);
644         len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
645                          "Bcast byte", tgt_stats->rx_bcast_byte);
646         len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
647                          "Fragmented pkt", tgt_stats->rx_frgment_pkt);
648         len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
649                          "Error", tgt_stats->rx_err);
650         len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
651                          "CRC Err", tgt_stats->rx_crc_err);
652         len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
653                          "Key chache miss", tgt_stats->rx_key_cache_miss);
654         len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
655                          "Decrypt Err", tgt_stats->rx_decrypt_err);
656         len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
657                          "Duplicate frame", tgt_stats->rx_dupl_frame);
658         len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
659                          "Tkip Mic failure", tgt_stats->tkip_local_mic_fail);
660         len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
661                          "TKIP format err", tgt_stats->tkip_fmt_err);
662         len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
663                          "CCMP format Err", tgt_stats->ccmp_fmt_err);
664         len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n\n",
665                          "CCMP Replay Err", tgt_stats->ccmp_replays);
666
667         len += scnprintf(buf + len, buf_len - len, "%25s\n",
668                          "Misc Target stats");
669         len += scnprintf(buf + len, buf_len - len, "%25s\n",
670                          "=================");
671         len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
672                          "Beacon Miss count", tgt_stats->cs_bmiss_cnt);
673         len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
674                          "Num Connects", tgt_stats->cs_connect_cnt);
675         len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
676                          "Num disconnects", tgt_stats->cs_discon_cnt);
677         len += scnprintf(buf + len, buf_len - len, "%20s %10d\n",
678                          "Beacon avg rssi", tgt_stats->cs_ave_beacon_rssi);
679         len += scnprintf(buf + len, buf_len - len, "%20s %10d\n",
680                          "ARP pkt received", tgt_stats->arp_received);
681         len += scnprintf(buf + len, buf_len - len, "%20s %10d\n",
682                          "ARP pkt matched", tgt_stats->arp_matched);
683         len += scnprintf(buf + len, buf_len - len, "%20s %10d\n",
684                          "ARP pkt replied", tgt_stats->arp_replied);
685
686         if (len > buf_len)
687                 len = buf_len;
688
689         ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
690
691         kfree(buf);
692         return ret_cnt;
693 }
694
695 static const struct file_operations fops_tgt_stats = {
696         .read = read_file_tgt_stats,
697         .open = simple_open,
698         .owner = THIS_MODULE,
699         .llseek = default_llseek,
700 };
701
702 #define print_credit_info(fmt_str, ep_list_field)               \
703         (len += scnprintf(buf + len, buf_len - len, fmt_str,    \
704                          ep_list->ep_list_field))
705 #define CREDIT_INFO_DISPLAY_STRING_LEN  200
706 #define CREDIT_INFO_LEN 128
707
708 static ssize_t read_file_credit_dist_stats(struct file *file,
709                                            char __user *user_buf,
710                                            size_t count, loff_t *ppos)
711 {
712         struct ath6kl *ar = file->private_data;
713         struct htc_target *target = ar->htc_target;
714         struct htc_endpoint_credit_dist *ep_list;
715         char *buf;
716         unsigned int buf_len, len = 0;
717         ssize_t ret_cnt;
718
719         buf_len = CREDIT_INFO_DISPLAY_STRING_LEN +
720                   get_queue_depth(&target->cred_dist_list) * CREDIT_INFO_LEN;
721         buf = kzalloc(buf_len, GFP_KERNEL);
722         if (!buf)
723                 return -ENOMEM;
724
725         len += scnprintf(buf + len, buf_len - len, "%25s%5d\n",
726                          "Total Avail Credits: ",
727                          target->credit_info->total_avail_credits);
728         len += scnprintf(buf + len, buf_len - len, "%25s%5d\n",
729                          "Free credits :",
730                          target->credit_info->cur_free_credits);
731
732         len += scnprintf(buf + len, buf_len - len,
733                          " Epid  Flags    Cred_norm  Cred_min  Credits  Cred_assngd"
734                          "  Seek_cred  Cred_sz  Cred_per_msg  Cred_to_dist"
735                          "  qdepth\n");
736
737         list_for_each_entry(ep_list, &target->cred_dist_list, list) {
738                 print_credit_info("  %2d", endpoint);
739                 print_credit_info("%10x", dist_flags);
740                 print_credit_info("%8d", cred_norm);
741                 print_credit_info("%9d", cred_min);
742                 print_credit_info("%9d", credits);
743                 print_credit_info("%10d", cred_assngd);
744                 print_credit_info("%13d", seek_cred);
745                 print_credit_info("%12d", cred_sz);
746                 print_credit_info("%9d", cred_per_msg);
747                 print_credit_info("%14d", cred_to_dist);
748                 len += scnprintf(buf + len, buf_len - len, "%12d\n",
749                                  get_queue_depth(&ep_list->htc_ep->txq));
750         }
751
752         if (len > buf_len)
753                 len = buf_len;
754
755         ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
756         kfree(buf);
757         return ret_cnt;
758 }
759
760 static const struct file_operations fops_credit_dist_stats = {
761         .read = read_file_credit_dist_stats,
762         .open = simple_open,
763         .owner = THIS_MODULE,
764         .llseek = default_llseek,
765 };
766
767 static unsigned int print_endpoint_stat(struct htc_target *target, char *buf,
768                                         unsigned int buf_len, unsigned int len,
769                                         int offset, const char *name)
770 {
771         int i;
772         struct htc_endpoint_stats *ep_st;
773         u32 *counter;
774
775         len += scnprintf(buf + len, buf_len - len, "%s:", name);
776         for (i = 0; i < ENDPOINT_MAX; i++) {
777                 ep_st = &target->endpoint[i].ep_st;
778                 counter = ((u32 *) ep_st) + (offset / 4);
779                 len += scnprintf(buf + len, buf_len - len, " %u", *counter);
780         }
781         len += scnprintf(buf + len, buf_len - len, "\n");
782
783         return len;
784 }
785
786 static ssize_t ath6kl_endpoint_stats_read(struct file *file,
787                                           char __user *user_buf,
788                                           size_t count, loff_t *ppos)
789 {
790         struct ath6kl *ar = file->private_data;
791         struct htc_target *target = ar->htc_target;
792         char *buf;
793         unsigned int buf_len, len = 0;
794         ssize_t ret_cnt;
795
796         buf_len = sizeof(struct htc_endpoint_stats) / sizeof(u32) *
797                 (25 + ENDPOINT_MAX * 11);
798         buf = kmalloc(buf_len, GFP_KERNEL);
799         if (!buf)
800                 return -ENOMEM;
801
802 #define EPSTAT(name)                                                    \
803         do {                                                            \
804                 len = print_endpoint_stat(target, buf, buf_len, len,    \
805                                           offsetof(struct htc_endpoint_stats, \
806                                                    name),               \
807                                           #name);                       \
808         } while (0)
809
810         EPSTAT(cred_low_indicate);
811         EPSTAT(tx_issued);
812         EPSTAT(tx_pkt_bundled);
813         EPSTAT(tx_bundles);
814         EPSTAT(tx_dropped);
815         EPSTAT(tx_cred_rpt);
816         EPSTAT(cred_rpt_from_rx);
817         EPSTAT(cred_rpt_from_other);
818         EPSTAT(cred_rpt_ep0);
819         EPSTAT(cred_from_rx);
820         EPSTAT(cred_from_other);
821         EPSTAT(cred_from_ep0);
822         EPSTAT(cred_cosumd);
823         EPSTAT(cred_retnd);
824         EPSTAT(rx_pkts);
825         EPSTAT(rx_lkahds);
826         EPSTAT(rx_bundl);
827         EPSTAT(rx_bundle_lkahd);
828         EPSTAT(rx_bundle_from_hdr);
829         EPSTAT(rx_alloc_thresh_hit);
830         EPSTAT(rxalloc_thresh_byte);
831 #undef EPSTAT
832
833         if (len > buf_len)
834                 len = buf_len;
835
836         ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
837         kfree(buf);
838         return ret_cnt;
839 }
840
841 static ssize_t ath6kl_endpoint_stats_write(struct file *file,
842                                            const char __user *user_buf,
843                                            size_t count, loff_t *ppos)
844 {
845         struct ath6kl *ar = file->private_data;
846         struct htc_target *target = ar->htc_target;
847         int ret, i;
848         u32 val;
849         struct htc_endpoint_stats *ep_st;
850
851         ret = kstrtou32_from_user(user_buf, count, 0, &val);
852         if (ret)
853                 return ret;
854         if (val == 0) {
855                 for (i = 0; i < ENDPOINT_MAX; i++) {
856                         ep_st = &target->endpoint[i].ep_st;
857                         memset(ep_st, 0, sizeof(*ep_st));
858                 }
859         }
860
861         return count;
862 }
863
864 static const struct file_operations fops_endpoint_stats = {
865         .open = simple_open,
866         .read = ath6kl_endpoint_stats_read,
867         .write = ath6kl_endpoint_stats_write,
868         .owner = THIS_MODULE,
869         .llseek = default_llseek,
870 };
871
872 static unsigned long ath6kl_get_num_reg(void)
873 {
874         int i;
875         unsigned long n_reg = 0;
876
877         for (i = 0; i < ARRAY_SIZE(diag_reg); i++)
878                 n_reg = n_reg +
879                      (diag_reg[i].reg_end - diag_reg[i].reg_start) / 4 + 1;
880
881         return n_reg;
882 }
883
884 static bool ath6kl_dbg_is_diag_reg_valid(u32 reg_addr)
885 {
886         int i;
887
888         for (i = 0; i < ARRAY_SIZE(diag_reg); i++) {
889                 if (reg_addr >= diag_reg[i].reg_start &&
890                     reg_addr <= diag_reg[i].reg_end)
891                         return true;
892         }
893
894         return false;
895 }
896
897 static ssize_t ath6kl_regread_read(struct file *file, char __user *user_buf,
898                                     size_t count, loff_t *ppos)
899 {
900         struct ath6kl *ar = file->private_data;
901         u8 buf[50];
902         unsigned int len = 0;
903
904         if (ar->debug.dbgfs_diag_reg)
905                 len += scnprintf(buf + len, sizeof(buf) - len, "0x%x\n",
906                                 ar->debug.dbgfs_diag_reg);
907         else
908                 len += scnprintf(buf + len, sizeof(buf) - len,
909                                  "All diag registers\n");
910
911         return simple_read_from_buffer(user_buf, count, ppos, buf, len);
912 }
913
914 static ssize_t ath6kl_regread_write(struct file *file,
915                                     const char __user *user_buf,
916                                     size_t count, loff_t *ppos)
917 {
918         struct ath6kl *ar = file->private_data;
919         unsigned long reg_addr;
920
921         if (kstrtoul_from_user(user_buf, count, 0, &reg_addr))
922                 return -EINVAL;
923
924         if ((reg_addr % 4) != 0)
925                 return -EINVAL;
926
927         if (reg_addr && !ath6kl_dbg_is_diag_reg_valid(reg_addr))
928                 return -EINVAL;
929
930         ar->debug.dbgfs_diag_reg = reg_addr;
931
932         return count;
933 }
934
935 static const struct file_operations fops_diag_reg_read = {
936         .read = ath6kl_regread_read,
937         .write = ath6kl_regread_write,
938         .open = simple_open,
939         .owner = THIS_MODULE,
940         .llseek = default_llseek,
941 };
942
943 static int ath6kl_regdump_open(struct inode *inode, struct file *file)
944 {
945         struct ath6kl *ar = inode->i_private;
946         u8 *buf;
947         unsigned long int reg_len;
948         unsigned int len = 0, n_reg;
949         u32 addr;
950         __le32 reg_val;
951         int i, status;
952
953         /* Dump all the registers if no register is specified */
954         if (!ar->debug.dbgfs_diag_reg)
955                 n_reg = ath6kl_get_num_reg();
956         else
957                 n_reg = 1;
958
959         reg_len = n_reg * REG_OUTPUT_LEN_PER_LINE;
960         if (n_reg > 1)
961                 reg_len += REGTYPE_STR_LEN;
962
963         buf = vmalloc(reg_len);
964         if (!buf)
965                 return -ENOMEM;
966
967         if (n_reg == 1) {
968                 addr = ar->debug.dbgfs_diag_reg;
969
970                 status = ath6kl_diag_read32(ar,
971                                 TARG_VTOP(ar->target_type, addr),
972                                 (u32 *)&reg_val);
973                 if (status)
974                         goto fail_reg_read;
975
976                 len += scnprintf(buf + len, reg_len - len,
977                                  "0x%06x 0x%08x\n", addr, le32_to_cpu(reg_val));
978                 goto done;
979         }
980
981         for (i = 0; i < ARRAY_SIZE(diag_reg); i++) {
982                 len += scnprintf(buf + len, reg_len - len,
983                                 "%s\n", diag_reg[i].reg_info);
984                 for (addr = diag_reg[i].reg_start;
985                      addr <= diag_reg[i].reg_end; addr += 4) {
986                         status = ath6kl_diag_read32(ar,
987                                         TARG_VTOP(ar->target_type, addr),
988                                         (u32 *)&reg_val);
989                         if (status)
990                                 goto fail_reg_read;
991
992                         len += scnprintf(buf + len, reg_len - len,
993                                         "0x%06x 0x%08x\n",
994                                         addr, le32_to_cpu(reg_val));
995                 }
996         }
997
998 done:
999         file->private_data = buf;
1000         return 0;
1001
1002 fail_reg_read:
1003         ath6kl_warn("Unable to read memory:%u\n", addr);
1004         vfree(buf);
1005         return -EIO;
1006 }
1007
1008 static ssize_t ath6kl_regdump_read(struct file *file, char __user *user_buf,
1009                                   size_t count, loff_t *ppos)
1010 {
1011         u8 *buf = file->private_data;
1012         return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));
1013 }
1014
1015 static int ath6kl_regdump_release(struct inode *inode, struct file *file)
1016 {
1017         vfree(file->private_data);
1018         return 0;
1019 }
1020
1021 static const struct file_operations fops_reg_dump = {
1022         .open = ath6kl_regdump_open,
1023         .read = ath6kl_regdump_read,
1024         .release = ath6kl_regdump_release,
1025         .owner = THIS_MODULE,
1026         .llseek = default_llseek,
1027 };
1028
1029 static ssize_t ath6kl_lrssi_roam_write(struct file *file,
1030                                        const char __user *user_buf,
1031                                        size_t count, loff_t *ppos)
1032 {
1033         struct ath6kl *ar = file->private_data;
1034         unsigned long lrssi_roam_threshold;
1035
1036         if (kstrtoul_from_user(user_buf, count, 0, &lrssi_roam_threshold))
1037                 return -EINVAL;
1038
1039         ar->lrssi_roam_threshold = lrssi_roam_threshold;
1040
1041         ath6kl_wmi_set_roam_lrssi_cmd(ar->wmi, ar->lrssi_roam_threshold);
1042
1043         return count;
1044 }
1045
1046 static ssize_t ath6kl_lrssi_roam_read(struct file *file,
1047                                       char __user *user_buf,
1048                                       size_t count, loff_t *ppos)
1049 {
1050         struct ath6kl *ar = file->private_data;
1051         char buf[32];
1052         unsigned int len;
1053
1054         len = snprintf(buf, sizeof(buf), "%u\n", ar->lrssi_roam_threshold);
1055
1056         return simple_read_from_buffer(user_buf, count, ppos, buf, len);
1057 }
1058
1059 static const struct file_operations fops_lrssi_roam_threshold = {
1060         .read = ath6kl_lrssi_roam_read,
1061         .write = ath6kl_lrssi_roam_write,
1062         .open = simple_open,
1063         .owner = THIS_MODULE,
1064         .llseek = default_llseek,
1065 };
1066
1067 static ssize_t ath6kl_regwrite_read(struct file *file,
1068                                     char __user *user_buf,
1069                                     size_t count, loff_t *ppos)
1070 {
1071         struct ath6kl *ar = file->private_data;
1072         u8 buf[32];
1073         unsigned int len = 0;
1074
1075         len = scnprintf(buf, sizeof(buf), "Addr: 0x%x Val: 0x%x\n",
1076                         ar->debug.diag_reg_addr_wr, ar->debug.diag_reg_val_wr);
1077
1078         return simple_read_from_buffer(user_buf, count, ppos, buf, len);
1079 }
1080
1081 static ssize_t ath6kl_regwrite_write(struct file *file,
1082                                      const char __user *user_buf,
1083                                      size_t count, loff_t *ppos)
1084 {
1085         struct ath6kl *ar = file->private_data;
1086         char buf[32];
1087         char *sptr, *token;
1088         unsigned int len = 0;
1089         u32 reg_addr, reg_val;
1090
1091         len = min(count, sizeof(buf) - 1);
1092         if (copy_from_user(buf, user_buf, len))
1093                 return -EFAULT;
1094
1095         buf[len] = '\0';
1096         sptr = buf;
1097
1098         token = strsep(&sptr, "=");
1099         if (!token)
1100                 return -EINVAL;
1101
1102         if (kstrtou32(token, 0, &reg_addr))
1103                 return -EINVAL;
1104
1105         if (!ath6kl_dbg_is_diag_reg_valid(reg_addr))
1106                 return -EINVAL;
1107
1108         if (kstrtou32(sptr, 0, &reg_val))
1109                 return -EINVAL;
1110
1111         ar->debug.diag_reg_addr_wr = reg_addr;
1112         ar->debug.diag_reg_val_wr = reg_val;
1113
1114         if (ath6kl_diag_write32(ar, ar->debug.diag_reg_addr_wr,
1115                                 cpu_to_le32(ar->debug.diag_reg_val_wr)))
1116                 return -EIO;
1117
1118         return count;
1119 }
1120
1121 static const struct file_operations fops_diag_reg_write = {
1122         .read = ath6kl_regwrite_read,
1123         .write = ath6kl_regwrite_write,
1124         .open = simple_open,
1125         .owner = THIS_MODULE,
1126         .llseek = default_llseek,
1127 };
1128
1129 int ath6kl_debug_roam_tbl_event(struct ath6kl *ar, const void *buf,
1130                                 size_t len)
1131 {
1132         const struct wmi_target_roam_tbl *tbl;
1133         u16 num_entries;
1134
1135         if (len < sizeof(*tbl))
1136                 return -EINVAL;
1137
1138         tbl = (const struct wmi_target_roam_tbl *) buf;
1139         num_entries = le16_to_cpu(tbl->num_entries);
1140         if (sizeof(*tbl) + num_entries * sizeof(struct wmi_bss_roam_info) >
1141             len)
1142                 return -EINVAL;
1143
1144         if (ar->debug.roam_tbl == NULL ||
1145             ar->debug.roam_tbl_len < (unsigned int) len) {
1146                 kfree(ar->debug.roam_tbl);
1147                 ar->debug.roam_tbl = kmalloc(len, GFP_ATOMIC);
1148                 if (ar->debug.roam_tbl == NULL)
1149                         return -ENOMEM;
1150         }
1151
1152         memcpy(ar->debug.roam_tbl, buf, len);
1153         ar->debug.roam_tbl_len = len;
1154
1155         if (test_bit(ROAM_TBL_PEND, &ar->flag)) {
1156                 clear_bit(ROAM_TBL_PEND, &ar->flag);
1157                 wake_up(&ar->event_wq);
1158         }
1159
1160         return 0;
1161 }
1162
1163 static ssize_t ath6kl_roam_table_read(struct file *file, char __user *user_buf,
1164                                       size_t count, loff_t *ppos)
1165 {
1166         struct ath6kl *ar = file->private_data;
1167         int ret;
1168         long left;
1169         struct wmi_target_roam_tbl *tbl;
1170         u16 num_entries, i;
1171         char *buf;
1172         unsigned int len, buf_len;
1173         ssize_t ret_cnt;
1174
1175         if (down_interruptible(&ar->sem))
1176                 return -EBUSY;
1177
1178         set_bit(ROAM_TBL_PEND, &ar->flag);
1179
1180         ret = ath6kl_wmi_get_roam_tbl_cmd(ar->wmi);
1181         if (ret) {
1182                 up(&ar->sem);
1183                 return ret;
1184         }
1185
1186         left = wait_event_interruptible_timeout(
1187                 ar->event_wq, !test_bit(ROAM_TBL_PEND, &ar->flag), WMI_TIMEOUT);
1188         up(&ar->sem);
1189
1190         if (left <= 0)
1191                 return -ETIMEDOUT;
1192
1193         if (ar->debug.roam_tbl == NULL)
1194                 return -ENOMEM;
1195
1196         tbl = (struct wmi_target_roam_tbl *) ar->debug.roam_tbl;
1197         num_entries = le16_to_cpu(tbl->num_entries);
1198
1199         buf_len = 100 + num_entries * 100;
1200         buf = kzalloc(buf_len, GFP_KERNEL);
1201         if (buf == NULL)
1202                 return -ENOMEM;
1203         len = 0;
1204         len += scnprintf(buf + len, buf_len - len,
1205                          "roam_mode=%u\n\n"
1206                          "# roam_util bssid rssi rssidt last_rssi util bias\n",
1207                          le16_to_cpu(tbl->roam_mode));
1208
1209         for (i = 0; i < num_entries; i++) {
1210                 struct wmi_bss_roam_info *info = &tbl->info[i];
1211                 len += scnprintf(buf + len, buf_len - len,
1212                                  "%d %pM %d %d %d %d %d\n",
1213                                  a_sle32_to_cpu(info->roam_util), info->bssid,
1214                                  info->rssi, info->rssidt, info->last_rssi,
1215                                  info->util, info->bias);
1216         }
1217
1218         if (len > buf_len)
1219                 len = buf_len;
1220
1221         ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
1222
1223         kfree(buf);
1224         return ret_cnt;
1225 }
1226
1227 static const struct file_operations fops_roam_table = {
1228         .read = ath6kl_roam_table_read,
1229         .open = simple_open,
1230         .owner = THIS_MODULE,
1231         .llseek = default_llseek,
1232 };
1233
1234 static ssize_t ath6kl_force_roam_write(struct file *file,
1235                                        const char __user *user_buf,
1236                                        size_t count, loff_t *ppos)
1237 {
1238         struct ath6kl *ar = file->private_data;
1239         int ret;
1240         char buf[20];
1241         size_t len;
1242         u8 bssid[ETH_ALEN];
1243         int i;
1244         int addr[ETH_ALEN];
1245
1246         len = min(count, sizeof(buf) - 1);
1247         if (copy_from_user(buf, user_buf, len))
1248                 return -EFAULT;
1249         buf[len] = '\0';
1250
1251         if (sscanf(buf, "%02x:%02x:%02x:%02x:%02x:%02x",
1252                    &addr[0], &addr[1], &addr[2], &addr[3], &addr[4], &addr[5])
1253             != ETH_ALEN)
1254                 return -EINVAL;
1255         for (i = 0; i < ETH_ALEN; i++)
1256                 bssid[i] = addr[i];
1257
1258         ret = ath6kl_wmi_force_roam_cmd(ar->wmi, bssid);
1259         if (ret)
1260                 return ret;
1261
1262         return count;
1263 }
1264
1265 static const struct file_operations fops_force_roam = {
1266         .write = ath6kl_force_roam_write,
1267         .open = simple_open,
1268         .owner = THIS_MODULE,
1269         .llseek = default_llseek,
1270 };
1271
1272 static ssize_t ath6kl_roam_mode_write(struct file *file,
1273                                       const char __user *user_buf,
1274                                       size_t count, loff_t *ppos)
1275 {
1276         struct ath6kl *ar = file->private_data;
1277         int ret;
1278         char buf[20];
1279         size_t len;
1280         enum wmi_roam_mode mode;
1281
1282         len = min(count, sizeof(buf) - 1);
1283         if (copy_from_user(buf, user_buf, len))
1284                 return -EFAULT;
1285         buf[len] = '\0';
1286         if (len > 0 && buf[len - 1] == '\n')
1287                 buf[len - 1] = '\0';
1288
1289         if (strcasecmp(buf, "default") == 0)
1290                 mode = WMI_DEFAULT_ROAM_MODE;
1291         else if (strcasecmp(buf, "bssbias") == 0)
1292                 mode = WMI_HOST_BIAS_ROAM_MODE;
1293         else if (strcasecmp(buf, "lock") == 0)
1294                 mode = WMI_LOCK_BSS_MODE;
1295         else
1296                 return -EINVAL;
1297
1298         ret = ath6kl_wmi_set_roam_mode_cmd(ar->wmi, mode);
1299         if (ret)
1300                 return ret;
1301
1302         return count;
1303 }
1304
1305 static const struct file_operations fops_roam_mode = {
1306         .write = ath6kl_roam_mode_write,
1307         .open = simple_open,
1308         .owner = THIS_MODULE,
1309         .llseek = default_llseek,
1310 };
1311
1312 void ath6kl_debug_set_keepalive(struct ath6kl *ar, u8 keepalive)
1313 {
1314         ar->debug.keepalive = keepalive;
1315 }
1316
1317 static ssize_t ath6kl_keepalive_read(struct file *file, char __user *user_buf,
1318                                      size_t count, loff_t *ppos)
1319 {
1320         struct ath6kl *ar = file->private_data;
1321         char buf[16];
1322         int len;
1323
1324         len = snprintf(buf, sizeof(buf), "%u\n", ar->debug.keepalive);
1325
1326         return simple_read_from_buffer(user_buf, count, ppos, buf, len);
1327 }
1328
1329 static ssize_t ath6kl_keepalive_write(struct file *file,
1330                                       const char __user *user_buf,
1331                                       size_t count, loff_t *ppos)
1332 {
1333         struct ath6kl *ar = file->private_data;
1334         int ret;
1335         u8 val;
1336
1337         ret = kstrtou8_from_user(user_buf, count, 0, &val);
1338         if (ret)
1339                 return ret;
1340
1341         ret = ath6kl_wmi_set_keepalive_cmd(ar->wmi, 0, val);
1342         if (ret)
1343                 return ret;
1344
1345         return count;
1346 }
1347
1348 static const struct file_operations fops_keepalive = {
1349         .open = simple_open,
1350         .read = ath6kl_keepalive_read,
1351         .write = ath6kl_keepalive_write,
1352         .owner = THIS_MODULE,
1353         .llseek = default_llseek,
1354 };
1355
1356 void ath6kl_debug_set_disconnect_timeout(struct ath6kl *ar, u8 timeout)
1357 {
1358         ar->debug.disc_timeout = timeout;
1359 }
1360
1361 static ssize_t ath6kl_disconnect_timeout_read(struct file *file,
1362                                               char __user *user_buf,
1363                                               size_t count, loff_t *ppos)
1364 {
1365         struct ath6kl *ar = file->private_data;
1366         char buf[16];
1367         int len;
1368
1369         len = snprintf(buf, sizeof(buf), "%u\n", ar->debug.disc_timeout);
1370
1371         return simple_read_from_buffer(user_buf, count, ppos, buf, len);
1372 }
1373
1374 static ssize_t ath6kl_disconnect_timeout_write(struct file *file,
1375                                                const char __user *user_buf,
1376                                                size_t count, loff_t *ppos)
1377 {
1378         struct ath6kl *ar = file->private_data;
1379         int ret;
1380         u8 val;
1381
1382         ret = kstrtou8_from_user(user_buf, count, 0, &val);
1383         if (ret)
1384                 return ret;
1385
1386         ret = ath6kl_wmi_disctimeout_cmd(ar->wmi, 0, val);
1387         if (ret)
1388                 return ret;
1389
1390         return count;
1391 }
1392
1393 static const struct file_operations fops_disconnect_timeout = {
1394         .open = simple_open,
1395         .read = ath6kl_disconnect_timeout_read,
1396         .write = ath6kl_disconnect_timeout_write,
1397         .owner = THIS_MODULE,
1398         .llseek = default_llseek,
1399 };
1400
1401 static ssize_t ath6kl_create_qos_write(struct file *file,
1402                                                 const char __user *user_buf,
1403                                                 size_t count, loff_t *ppos)
1404 {
1405
1406         struct ath6kl *ar = file->private_data;
1407         struct ath6kl_vif *vif;
1408         char buf[200];
1409         ssize_t len;
1410         char *sptr, *token;
1411         struct wmi_create_pstream_cmd pstream;
1412         u32 val32;
1413         u16 val16;
1414
1415         vif = ath6kl_vif_first(ar);
1416         if (!vif)
1417                 return -EIO;
1418
1419         len = min(count, sizeof(buf) - 1);
1420         if (copy_from_user(buf, user_buf, len))
1421                 return -EFAULT;
1422         buf[len] = '\0';
1423         sptr = buf;
1424
1425         token = strsep(&sptr, " ");
1426         if (!token)
1427                 return -EINVAL;
1428         if (kstrtou8(token, 0, &pstream.user_pri))
1429                 return -EINVAL;
1430
1431         token = strsep(&sptr, " ");
1432         if (!token)
1433                 return -EINVAL;
1434         if (kstrtou8(token, 0, &pstream.traffic_direc))
1435                 return -EINVAL;
1436
1437         token = strsep(&sptr, " ");
1438         if (!token)
1439                 return -EINVAL;
1440         if (kstrtou8(token, 0, &pstream.traffic_class))
1441                 return -EINVAL;
1442
1443         token = strsep(&sptr, " ");
1444         if (!token)
1445                 return -EINVAL;
1446         if (kstrtou8(token, 0, &pstream.traffic_type))
1447                 return -EINVAL;
1448
1449         token = strsep(&sptr, " ");
1450         if (!token)
1451                 return -EINVAL;
1452         if (kstrtou8(token, 0, &pstream.voice_psc_cap))
1453                 return -EINVAL;
1454
1455         token = strsep(&sptr, " ");
1456         if (!token)
1457                 return -EINVAL;
1458         if (kstrtou32(token, 0, &val32))
1459                 return -EINVAL;
1460         pstream.min_service_int = cpu_to_le32(val32);
1461
1462         token = strsep(&sptr, " ");
1463         if (!token)
1464                 return -EINVAL;
1465         if (kstrtou32(token, 0, &val32))
1466                 return -EINVAL;
1467         pstream.max_service_int = cpu_to_le32(val32);
1468
1469         token = strsep(&sptr, " ");
1470         if (!token)
1471                 return -EINVAL;
1472         if (kstrtou32(token, 0, &val32))
1473                 return -EINVAL;
1474         pstream.inactivity_int = cpu_to_le32(val32);
1475
1476         token = strsep(&sptr, " ");
1477         if (!token)
1478                 return -EINVAL;
1479         if (kstrtou32(token, 0, &val32))
1480                 return -EINVAL;
1481         pstream.suspension_int = cpu_to_le32(val32);
1482
1483         token = strsep(&sptr, " ");
1484         if (!token)
1485                 return -EINVAL;
1486         if (kstrtou32(token, 0, &val32))
1487                 return -EINVAL;
1488         pstream.service_start_time = cpu_to_le32(val32);
1489
1490         token = strsep(&sptr, " ");
1491         if (!token)
1492                 return -EINVAL;
1493         if (kstrtou8(token, 0, &pstream.tsid))
1494                 return -EINVAL;
1495
1496         token = strsep(&sptr, " ");
1497         if (!token)
1498                 return -EINVAL;
1499         if (kstrtou16(token, 0, &val16))
1500                 return -EINVAL;
1501         pstream.nominal_msdu = cpu_to_le16(val16);
1502
1503         token = strsep(&sptr, " ");
1504         if (!token)
1505                 return -EINVAL;
1506         if (kstrtou16(token, 0, &val16))
1507                 return -EINVAL;
1508         pstream.max_msdu = cpu_to_le16(val16);
1509
1510         token = strsep(&sptr, " ");
1511         if (!token)
1512                 return -EINVAL;
1513         if (kstrtou32(token, 0, &val32))
1514                 return -EINVAL;
1515         pstream.min_data_rate = cpu_to_le32(val32);
1516
1517         token = strsep(&sptr, " ");
1518         if (!token)
1519                 return -EINVAL;
1520         if (kstrtou32(token, 0, &val32))
1521                 return -EINVAL;
1522         pstream.mean_data_rate = cpu_to_le32(val32);
1523
1524         token = strsep(&sptr, " ");
1525         if (!token)
1526                 return -EINVAL;
1527         if (kstrtou32(token, 0, &val32))
1528                 return -EINVAL;
1529         pstream.peak_data_rate = cpu_to_le32(val32);
1530
1531         token = strsep(&sptr, " ");
1532         if (!token)
1533                 return -EINVAL;
1534         if (kstrtou32(token, 0, &val32))
1535                 return -EINVAL;
1536         pstream.max_burst_size = cpu_to_le32(val32);
1537
1538         token = strsep(&sptr, " ");
1539         if (!token)
1540                 return -EINVAL;
1541         if (kstrtou32(token, 0, &val32))
1542                 return -EINVAL;
1543         pstream.delay_bound = cpu_to_le32(val32);
1544
1545         token = strsep(&sptr, " ");
1546         if (!token)
1547                 return -EINVAL;
1548         if (kstrtou32(token, 0, &val32))
1549                 return -EINVAL;
1550         pstream.min_phy_rate = cpu_to_le32(val32);
1551
1552         token = strsep(&sptr, " ");
1553         if (!token)
1554                 return -EINVAL;
1555         if (kstrtou32(token, 0, &val32))
1556                 return -EINVAL;
1557         pstream.sba = cpu_to_le32(val32);
1558
1559         token = strsep(&sptr, " ");
1560         if (!token)
1561                 return -EINVAL;
1562         if (kstrtou32(token, 0, &val32))
1563                 return -EINVAL;
1564         pstream.medium_time = cpu_to_le32(val32);
1565
1566         pstream.nominal_phy = le32_to_cpu(pstream.min_phy_rate) / 1000000;
1567
1568         ath6kl_wmi_create_pstream_cmd(ar->wmi, vif->fw_vif_idx, &pstream);
1569
1570         return count;
1571 }
1572
1573 static const struct file_operations fops_create_qos = {
1574         .write = ath6kl_create_qos_write,
1575         .open = simple_open,
1576         .owner = THIS_MODULE,
1577         .llseek = default_llseek,
1578 };
1579
1580 static ssize_t ath6kl_delete_qos_write(struct file *file,
1581                                 const char __user *user_buf,
1582                                 size_t count, loff_t *ppos)
1583 {
1584
1585         struct ath6kl *ar = file->private_data;
1586         struct ath6kl_vif *vif;
1587         char buf[100];
1588         ssize_t len;
1589         char *sptr, *token;
1590         u8 traffic_class;
1591         u8 tsid;
1592
1593         vif = ath6kl_vif_first(ar);
1594         if (!vif)
1595                 return -EIO;
1596
1597         len = min(count, sizeof(buf) - 1);
1598         if (copy_from_user(buf, user_buf, len))
1599                 return -EFAULT;
1600         buf[len] = '\0';
1601         sptr = buf;
1602
1603         token = strsep(&sptr, " ");
1604         if (!token)
1605                 return -EINVAL;
1606         if (kstrtou8(token, 0, &traffic_class))
1607                 return -EINVAL;
1608
1609         token = strsep(&sptr, " ");
1610         if (!token)
1611                 return -EINVAL;
1612         if (kstrtou8(token, 0, &tsid))
1613                 return -EINVAL;
1614
1615         ath6kl_wmi_delete_pstream_cmd(ar->wmi, vif->fw_vif_idx,
1616                                       traffic_class, tsid);
1617
1618         return count;
1619 }
1620
1621 static const struct file_operations fops_delete_qos = {
1622         .write = ath6kl_delete_qos_write,
1623         .open = simple_open,
1624         .owner = THIS_MODULE,
1625         .llseek = default_llseek,
1626 };
1627
1628 static ssize_t ath6kl_bgscan_int_write(struct file *file,
1629                                 const char __user *user_buf,
1630                                 size_t count, loff_t *ppos)
1631 {
1632         struct ath6kl *ar = file->private_data;
1633         struct ath6kl_vif *vif;
1634         u16 bgscan_int;
1635         char buf[32];
1636         ssize_t len;
1637
1638         vif = ath6kl_vif_first(ar);
1639         if (!vif)
1640                 return -EIO;
1641
1642         len = min(count, sizeof(buf) - 1);
1643         if (copy_from_user(buf, user_buf, len))
1644                 return -EFAULT;
1645
1646         buf[len] = '\0';
1647         if (kstrtou16(buf, 0, &bgscan_int))
1648                 return -EINVAL;
1649
1650         if (bgscan_int == 0)
1651                 bgscan_int = 0xffff;
1652
1653         vif->bg_scan_period = bgscan_int;
1654
1655         ath6kl_wmi_scanparams_cmd(ar->wmi, 0, 0, 0, bgscan_int, 0, 0, 0, 3,
1656                                   0, 0, 0);
1657
1658         return count;
1659 }
1660
1661 static const struct file_operations fops_bgscan_int = {
1662         .write = ath6kl_bgscan_int_write,
1663         .open = simple_open,
1664         .owner = THIS_MODULE,
1665         .llseek = default_llseek,
1666 };
1667
1668 static ssize_t ath6kl_listen_int_write(struct file *file,
1669                                        const char __user *user_buf,
1670                                        size_t count, loff_t *ppos)
1671 {
1672         struct ath6kl *ar = file->private_data;
1673         struct ath6kl_vif *vif;
1674         u16 listen_interval;
1675         char buf[32];
1676         ssize_t len;
1677
1678         vif = ath6kl_vif_first(ar);
1679         if (!vif)
1680                 return -EIO;
1681
1682         len = min(count, sizeof(buf) - 1);
1683         if (copy_from_user(buf, user_buf, len))
1684                 return -EFAULT;
1685
1686         buf[len] = '\0';
1687         if (kstrtou16(buf, 0, &listen_interval))
1688                 return -EINVAL;
1689
1690         if ((listen_interval < 15) || (listen_interval > 3000))
1691                 return -EINVAL;
1692
1693         vif->listen_intvl_t = listen_interval;
1694         ath6kl_wmi_listeninterval_cmd(ar->wmi, vif->fw_vif_idx,
1695                                       vif->listen_intvl_t, 0);
1696
1697         return count;
1698 }
1699
1700 static ssize_t ath6kl_listen_int_read(struct file *file,
1701                                       char __user *user_buf,
1702                                       size_t count, loff_t *ppos)
1703 {
1704         struct ath6kl *ar = file->private_data;
1705         struct ath6kl_vif *vif;
1706         char buf[32];
1707         int len;
1708
1709         vif = ath6kl_vif_first(ar);
1710         if (!vif)
1711                 return -EIO;
1712
1713         len = scnprintf(buf, sizeof(buf), "%u\n", vif->listen_intvl_t);
1714
1715         return simple_read_from_buffer(user_buf, count, ppos, buf, len);
1716 }
1717
1718 static const struct file_operations fops_listen_int = {
1719         .read = ath6kl_listen_int_read,
1720         .write = ath6kl_listen_int_write,
1721         .open = simple_open,
1722         .owner = THIS_MODULE,
1723         .llseek = default_llseek,
1724 };
1725
1726 static ssize_t ath6kl_power_params_write(struct file *file,
1727                                                 const char __user *user_buf,
1728                                                 size_t count, loff_t *ppos)
1729 {
1730         struct ath6kl *ar = file->private_data;
1731         u8 buf[100];
1732         unsigned int len = 0;
1733         char *sptr, *token;
1734         u16 idle_period, ps_poll_num, dtim,
1735                 tx_wakeup, num_tx;
1736
1737         len = min(count, sizeof(buf) - 1);
1738         if (copy_from_user(buf, user_buf, len))
1739                 return -EFAULT;
1740         buf[len] = '\0';
1741         sptr = buf;
1742
1743         token = strsep(&sptr, " ");
1744         if (!token)
1745                 return -EINVAL;
1746         if (kstrtou16(token, 0, &idle_period))
1747                 return -EINVAL;
1748
1749         token = strsep(&sptr, " ");
1750         if (!token)
1751                 return -EINVAL;
1752         if (kstrtou16(token, 0, &ps_poll_num))
1753                 return -EINVAL;
1754
1755         token = strsep(&sptr, " ");
1756         if (!token)
1757                 return -EINVAL;
1758         if (kstrtou16(token, 0, &dtim))
1759                 return -EINVAL;
1760
1761         token = strsep(&sptr, " ");
1762         if (!token)
1763                 return -EINVAL;
1764         if (kstrtou16(token, 0, &tx_wakeup))
1765                 return -EINVAL;
1766
1767         token = strsep(&sptr, " ");
1768         if (!token)
1769                 return -EINVAL;
1770         if (kstrtou16(token, 0, &num_tx))
1771                 return -EINVAL;
1772
1773         ath6kl_wmi_pmparams_cmd(ar->wmi, 0, idle_period, ps_poll_num,
1774                                 dtim, tx_wakeup, num_tx, 0);
1775
1776         return count;
1777 }
1778
1779 static const struct file_operations fops_power_params = {
1780         .write = ath6kl_power_params_write,
1781         .open = simple_open,
1782         .owner = THIS_MODULE,
1783         .llseek = default_llseek,
1784 };
1785
1786 void ath6kl_debug_init(struct ath6kl *ar)
1787 {
1788         skb_queue_head_init(&ar->debug.fwlog_queue);
1789         init_completion(&ar->debug.fwlog_completion);
1790
1791         /*
1792          * Actually we are lying here but don't know how to read the mask
1793          * value from the firmware.
1794          */
1795         ar->debug.fwlog_mask = 0;
1796 }
1797
1798 /*
1799  * Initialisation needs to happen in two stages as fwlog events can come
1800  * before cfg80211 is initialised, and debugfs depends on cfg80211
1801  * initialisation.
1802  */
1803 int ath6kl_debug_init_fs(struct ath6kl *ar)
1804 {
1805         ar->debugfs_phy = debugfs_create_dir("ath6kl",
1806                                              ar->wiphy->debugfsdir);
1807         if (!ar->debugfs_phy)
1808                 return -ENOMEM;
1809
1810         debugfs_create_file("tgt_stats", S_IRUSR, ar->debugfs_phy, ar,
1811                             &fops_tgt_stats);
1812
1813         if (ar->hif_type == ATH6KL_HIF_TYPE_SDIO)
1814                 debugfs_create_file("credit_dist_stats", S_IRUSR,
1815                                     ar->debugfs_phy, ar,
1816                                     &fops_credit_dist_stats);
1817
1818         debugfs_create_file("endpoint_stats", S_IRUSR | S_IWUSR,
1819                             ar->debugfs_phy, ar, &fops_endpoint_stats);
1820
1821         debugfs_create_file("fwlog", S_IRUSR, ar->debugfs_phy, ar,
1822                             &fops_fwlog);
1823
1824         debugfs_create_file("fwlog_block", S_IRUSR, ar->debugfs_phy, ar,
1825                             &fops_fwlog_block);
1826
1827         debugfs_create_file("fwlog_mask", S_IRUSR | S_IWUSR, ar->debugfs_phy,
1828                             ar, &fops_fwlog_mask);
1829
1830         debugfs_create_file("reg_addr", S_IRUSR | S_IWUSR, ar->debugfs_phy, ar,
1831                             &fops_diag_reg_read);
1832
1833         debugfs_create_file("reg_dump", S_IRUSR, ar->debugfs_phy, ar,
1834                             &fops_reg_dump);
1835
1836         debugfs_create_file("lrssi_roam_threshold", S_IRUSR | S_IWUSR,
1837                             ar->debugfs_phy, ar, &fops_lrssi_roam_threshold);
1838
1839         debugfs_create_file("reg_write", S_IRUSR | S_IWUSR,
1840                             ar->debugfs_phy, ar, &fops_diag_reg_write);
1841
1842         debugfs_create_file("war_stats", S_IRUSR, ar->debugfs_phy, ar,
1843                             &fops_war_stats);
1844
1845         debugfs_create_file("roam_table", S_IRUSR, ar->debugfs_phy, ar,
1846                             &fops_roam_table);
1847
1848         debugfs_create_file("force_roam", S_IWUSR, ar->debugfs_phy, ar,
1849                             &fops_force_roam);
1850
1851         debugfs_create_file("roam_mode", S_IWUSR, ar->debugfs_phy, ar,
1852                             &fops_roam_mode);
1853
1854         debugfs_create_file("keepalive", S_IRUSR | S_IWUSR, ar->debugfs_phy, ar,
1855                             &fops_keepalive);
1856
1857         debugfs_create_file("disconnect_timeout", S_IRUSR | S_IWUSR,
1858                             ar->debugfs_phy, ar, &fops_disconnect_timeout);
1859
1860         debugfs_create_file("create_qos", S_IWUSR, ar->debugfs_phy, ar,
1861                             &fops_create_qos);
1862
1863         debugfs_create_file("delete_qos", S_IWUSR, ar->debugfs_phy, ar,
1864                             &fops_delete_qos);
1865
1866         debugfs_create_file("bgscan_interval", S_IWUSR,
1867                             ar->debugfs_phy, ar, &fops_bgscan_int);
1868
1869         debugfs_create_file("listen_interval", S_IRUSR | S_IWUSR,
1870                             ar->debugfs_phy, ar, &fops_listen_int);
1871
1872         debugfs_create_file("power_params", S_IWUSR, ar->debugfs_phy, ar,
1873                             &fops_power_params);
1874
1875         return 0;
1876 }
1877
1878 void ath6kl_debug_cleanup(struct ath6kl *ar)
1879 {
1880         skb_queue_purge(&ar->debug.fwlog_queue);
1881         complete(&ar->debug.fwlog_completion);
1882         kfree(ar->debug.roam_tbl);
1883 }
1884
1885 #endif