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