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