Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright (c) 2004-2011 Atheros Communications Inc.
0003  * Copyright (c) 2011-2012 Qualcomm Atheros, Inc.
0004  *
0005  * Permission to use, copy, modify, and/or distribute this software for any
0006  * purpose with or without fee is hereby granted, provided that the above
0007  * copyright notice and this permission notice appear in all copies.
0008  *
0009  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
0010  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
0011  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
0012  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
0013  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
0014  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
0015  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
0016  */
0017 
0018 #include "core.h"
0019 
0020 #include <linux/skbuff.h>
0021 #include <linux/fs.h>
0022 #include <linux/vmalloc.h>
0023 #include <linux/export.h>
0024 
0025 #include "debug.h"
0026 #include "target.h"
0027 
0028 struct ath6kl_fwlog_slot {
0029     __le32 timestamp;
0030     __le32 length;
0031 
0032     /* max ATH6KL_FWLOG_PAYLOAD_SIZE bytes */
0033     u8 payload[];
0034 };
0035 
0036 #define ATH6KL_FWLOG_MAX_ENTRIES 20
0037 
0038 #define ATH6KL_FWLOG_VALID_MASK 0x1ffff
0039 
0040 void ath6kl_printk(const char *level, const char *fmt, ...)
0041 {
0042     struct va_format vaf;
0043     va_list args;
0044 
0045     va_start(args, fmt);
0046 
0047     vaf.fmt = fmt;
0048     vaf.va = &args;
0049 
0050     printk("%sath6kl: %pV", level, &vaf);
0051 
0052     va_end(args);
0053 }
0054 EXPORT_SYMBOL(ath6kl_printk);
0055 
0056 void ath6kl_info(const char *fmt, ...)
0057 {
0058     struct va_format vaf = {
0059         .fmt = fmt,
0060     };
0061     va_list args;
0062 
0063     va_start(args, fmt);
0064     vaf.va = &args;
0065     ath6kl_printk(KERN_INFO, "%pV", &vaf);
0066     trace_ath6kl_log_info(&vaf);
0067     va_end(args);
0068 }
0069 EXPORT_SYMBOL(ath6kl_info);
0070 
0071 void ath6kl_err(const char *fmt, ...)
0072 {
0073     struct va_format vaf = {
0074         .fmt = fmt,
0075     };
0076     va_list args;
0077 
0078     va_start(args, fmt);
0079     vaf.va = &args;
0080     ath6kl_printk(KERN_ERR, "%pV", &vaf);
0081     trace_ath6kl_log_err(&vaf);
0082     va_end(args);
0083 }
0084 EXPORT_SYMBOL(ath6kl_err);
0085 
0086 void ath6kl_warn(const char *fmt, ...)
0087 {
0088     struct va_format vaf = {
0089         .fmt = fmt,
0090     };
0091     va_list args;
0092 
0093     va_start(args, fmt);
0094     vaf.va = &args;
0095     ath6kl_printk(KERN_WARNING, "%pV", &vaf);
0096     trace_ath6kl_log_warn(&vaf);
0097     va_end(args);
0098 }
0099 EXPORT_SYMBOL(ath6kl_warn);
0100 
0101 int ath6kl_read_tgt_stats(struct ath6kl *ar, struct ath6kl_vif *vif)
0102 {
0103     long left;
0104 
0105     if (down_interruptible(&ar->sem))
0106         return -EBUSY;
0107 
0108     set_bit(STATS_UPDATE_PEND, &vif->flags);
0109 
0110     if (ath6kl_wmi_get_stats_cmd(ar->wmi, 0)) {
0111         up(&ar->sem);
0112         return -EIO;
0113     }
0114 
0115     left = wait_event_interruptible_timeout(ar->event_wq,
0116                         !test_bit(STATS_UPDATE_PEND,
0117                         &vif->flags), WMI_TIMEOUT);
0118 
0119     up(&ar->sem);
0120 
0121     if (left <= 0)
0122         return -ETIMEDOUT;
0123 
0124     return 0;
0125 }
0126 EXPORT_SYMBOL(ath6kl_read_tgt_stats);
0127 
0128 #ifdef CONFIG_ATH6KL_DEBUG
0129 
0130 void ath6kl_dbg(enum ATH6K_DEBUG_MASK mask, const char *fmt, ...)
0131 {
0132     struct va_format vaf;
0133     va_list args;
0134 
0135     va_start(args, fmt);
0136 
0137     vaf.fmt = fmt;
0138     vaf.va = &args;
0139 
0140     if (debug_mask & mask)
0141         ath6kl_printk(KERN_DEBUG, "%pV", &vaf);
0142 
0143     trace_ath6kl_log_dbg(mask, &vaf);
0144 
0145     va_end(args);
0146 }
0147 EXPORT_SYMBOL(ath6kl_dbg);
0148 
0149 void ath6kl_dbg_dump(enum ATH6K_DEBUG_MASK mask,
0150              const char *msg, const char *prefix,
0151              const void *buf, size_t len)
0152 {
0153     if (debug_mask & mask) {
0154         if (msg)
0155             ath6kl_dbg(mask, "%s\n", msg);
0156 
0157         print_hex_dump_bytes(prefix, DUMP_PREFIX_OFFSET, buf, len);
0158     }
0159 
0160     /* tracing code doesn't like null strings :/ */
0161     trace_ath6kl_log_dbg_dump(msg ? msg : "", prefix ? prefix : "",
0162                   buf, len);
0163 }
0164 EXPORT_SYMBOL(ath6kl_dbg_dump);
0165 
0166 #define REG_OUTPUT_LEN_PER_LINE 25
0167 #define REGTYPE_STR_LEN     100
0168 
0169 struct ath6kl_diag_reg_info {
0170     u32 reg_start;
0171     u32 reg_end;
0172     const char *reg_info;
0173 };
0174 
0175 static const struct ath6kl_diag_reg_info diag_reg[] = {
0176     { 0x20000, 0x200fc, "General DMA and Rx registers" },
0177     { 0x28000, 0x28900, "MAC PCU register & keycache" },
0178     { 0x20800, 0x20a40, "QCU" },
0179     { 0x21000, 0x212f0, "DCU" },
0180     { 0x4000,  0x42e4, "RTC" },
0181     { 0x540000, 0x540000 + (256 * 1024), "RAM" },
0182     { 0x29800, 0x2B210, "Base Band" },
0183     { 0x1C000, 0x1C748, "Analog" },
0184 };
0185 
0186 void ath6kl_dump_registers(struct ath6kl_device *dev,
0187                struct ath6kl_irq_proc_registers *irq_proc_reg,
0188                struct ath6kl_irq_enable_reg *irq_enable_reg)
0189 {
0190     ath6kl_dbg(ATH6KL_DBG_IRQ, ("<------- Register Table -------->\n"));
0191 
0192     if (irq_proc_reg != NULL) {
0193         ath6kl_dbg(ATH6KL_DBG_IRQ,
0194                "Host Int status:           0x%x\n",
0195                irq_proc_reg->host_int_status);
0196         ath6kl_dbg(ATH6KL_DBG_IRQ,
0197                "CPU Int status:            0x%x\n",
0198                irq_proc_reg->cpu_int_status);
0199         ath6kl_dbg(ATH6KL_DBG_IRQ,
0200                "Error Int status:          0x%x\n",
0201                irq_proc_reg->error_int_status);
0202         ath6kl_dbg(ATH6KL_DBG_IRQ,
0203                "Counter Int status:        0x%x\n",
0204                irq_proc_reg->counter_int_status);
0205         ath6kl_dbg(ATH6KL_DBG_IRQ,
0206                "Mbox Frame:                0x%x\n",
0207                irq_proc_reg->mbox_frame);
0208         ath6kl_dbg(ATH6KL_DBG_IRQ,
0209                "Rx Lookahead Valid:        0x%x\n",
0210                irq_proc_reg->rx_lkahd_valid);
0211         ath6kl_dbg(ATH6KL_DBG_IRQ,
0212                "Rx Lookahead 0:            0x%x\n",
0213                irq_proc_reg->rx_lkahd[0]);
0214         ath6kl_dbg(ATH6KL_DBG_IRQ,
0215                "Rx Lookahead 1:            0x%x\n",
0216                irq_proc_reg->rx_lkahd[1]);
0217 
0218         if (dev->ar->mbox_info.gmbox_addr != 0) {
0219             /*
0220              * If the target supports GMBOX hardware, dump some
0221              * additional state.
0222              */
0223             ath6kl_dbg(ATH6KL_DBG_IRQ,
0224                    "GMBOX Host Int status 2:   0x%x\n",
0225                    irq_proc_reg->host_int_status2);
0226             ath6kl_dbg(ATH6KL_DBG_IRQ,
0227                    "GMBOX RX Avail:            0x%x\n",
0228                    irq_proc_reg->gmbox_rx_avail);
0229             ath6kl_dbg(ATH6KL_DBG_IRQ,
0230                    "GMBOX lookahead alias 0:   0x%x\n",
0231                    irq_proc_reg->rx_gmbox_lkahd_alias[0]);
0232             ath6kl_dbg(ATH6KL_DBG_IRQ,
0233                    "GMBOX lookahead alias 1:   0x%x\n",
0234                    irq_proc_reg->rx_gmbox_lkahd_alias[1]);
0235         }
0236     }
0237 
0238     if (irq_enable_reg != NULL) {
0239         ath6kl_dbg(ATH6KL_DBG_IRQ,
0240                "Int status Enable:         0x%x\n",
0241                irq_enable_reg->int_status_en);
0242         ath6kl_dbg(ATH6KL_DBG_IRQ, "Counter Int status Enable: 0x%x\n",
0243                irq_enable_reg->cntr_int_status_en);
0244     }
0245     ath6kl_dbg(ATH6KL_DBG_IRQ, "<------------------------------->\n");
0246 }
0247 
0248 static void dump_cred_dist(struct htc_endpoint_credit_dist *ep_dist)
0249 {
0250     ath6kl_dbg(ATH6KL_DBG_CREDIT,
0251            "--- endpoint: %d  svc_id: 0x%X ---\n",
0252            ep_dist->endpoint, ep_dist->svc_id);
0253     ath6kl_dbg(ATH6KL_DBG_CREDIT, " dist_flags     : 0x%X\n",
0254            ep_dist->dist_flags);
0255     ath6kl_dbg(ATH6KL_DBG_CREDIT, " cred_norm      : %d\n",
0256            ep_dist->cred_norm);
0257     ath6kl_dbg(ATH6KL_DBG_CREDIT, " cred_min       : %d\n",
0258            ep_dist->cred_min);
0259     ath6kl_dbg(ATH6KL_DBG_CREDIT, " credits        : %d\n",
0260            ep_dist->credits);
0261     ath6kl_dbg(ATH6KL_DBG_CREDIT, " cred_assngd    : %d\n",
0262            ep_dist->cred_assngd);
0263     ath6kl_dbg(ATH6KL_DBG_CREDIT, " seek_cred      : %d\n",
0264            ep_dist->seek_cred);
0265     ath6kl_dbg(ATH6KL_DBG_CREDIT, " cred_sz        : %d\n",
0266            ep_dist->cred_sz);
0267     ath6kl_dbg(ATH6KL_DBG_CREDIT, " cred_per_msg   : %d\n",
0268            ep_dist->cred_per_msg);
0269     ath6kl_dbg(ATH6KL_DBG_CREDIT, " cred_to_dist   : %d\n",
0270            ep_dist->cred_to_dist);
0271     ath6kl_dbg(ATH6KL_DBG_CREDIT, " txq_depth      : %d\n",
0272            get_queue_depth(&ep_dist->htc_ep->txq));
0273     ath6kl_dbg(ATH6KL_DBG_CREDIT,
0274            "----------------------------------\n");
0275 }
0276 
0277 /* FIXME: move to htc.c */
0278 void dump_cred_dist_stats(struct htc_target *target)
0279 {
0280     struct htc_endpoint_credit_dist *ep_list;
0281 
0282     list_for_each_entry(ep_list, &target->cred_dist_list, list)
0283         dump_cred_dist(ep_list);
0284 
0285     ath6kl_dbg(ATH6KL_DBG_CREDIT,
0286            "credit distribution total %d free %d\n",
0287            target->credit_info->total_avail_credits,
0288            target->credit_info->cur_free_credits);
0289 }
0290 
0291 void ath6kl_debug_war(struct ath6kl *ar, enum ath6kl_war war)
0292 {
0293     switch (war) {
0294     case ATH6KL_WAR_INVALID_RATE:
0295         ar->debug.war_stats.invalid_rate++;
0296         break;
0297     }
0298 }
0299 
0300 static ssize_t read_file_war_stats(struct file *file, char __user *user_buf,
0301                    size_t count, loff_t *ppos)
0302 {
0303     struct ath6kl *ar = file->private_data;
0304     char *buf;
0305     unsigned int len = 0, buf_len = 1500;
0306     ssize_t ret_cnt;
0307 
0308     buf = kzalloc(buf_len, GFP_KERNEL);
0309     if (!buf)
0310         return -ENOMEM;
0311 
0312     len += scnprintf(buf + len, buf_len - len, "\n");
0313     len += scnprintf(buf + len, buf_len - len, "%25s\n",
0314              "Workaround stats");
0315     len += scnprintf(buf + len, buf_len - len, "%25s\n\n",
0316              "=================");
0317     len += scnprintf(buf + len, buf_len - len, "%20s %10u\n",
0318              "Invalid rates", ar->debug.war_stats.invalid_rate);
0319 
0320     if (WARN_ON(len > buf_len))
0321         len = buf_len;
0322 
0323     ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
0324 
0325     kfree(buf);
0326     return ret_cnt;
0327 }
0328 
0329 static const struct file_operations fops_war_stats = {
0330     .read = read_file_war_stats,
0331     .open = simple_open,
0332     .owner = THIS_MODULE,
0333     .llseek = default_llseek,
0334 };
0335 
0336 void ath6kl_debug_fwlog_event(struct ath6kl *ar, const void *buf, size_t len)
0337 {
0338     struct ath6kl_fwlog_slot *slot;
0339     struct sk_buff *skb;
0340     size_t slot_len;
0341 
0342     if (WARN_ON(len > ATH6KL_FWLOG_PAYLOAD_SIZE))
0343         return;
0344 
0345     slot_len = sizeof(*slot) + ATH6KL_FWLOG_PAYLOAD_SIZE;
0346 
0347     skb = alloc_skb(slot_len, GFP_KERNEL);
0348     if (!skb)
0349         return;
0350 
0351     slot = skb_put(skb, slot_len);
0352     slot->timestamp = cpu_to_le32(jiffies);
0353     slot->length = cpu_to_le32(len);
0354     memcpy(slot->payload, buf, len);
0355 
0356     /* Need to pad each record to fixed length ATH6KL_FWLOG_PAYLOAD_SIZE */
0357     memset(slot->payload + len, 0, ATH6KL_FWLOG_PAYLOAD_SIZE - len);
0358 
0359     spin_lock(&ar->debug.fwlog_queue.lock);
0360 
0361     __skb_queue_tail(&ar->debug.fwlog_queue, skb);
0362     complete(&ar->debug.fwlog_completion);
0363 
0364     /* drop oldest entries */
0365     while (skb_queue_len(&ar->debug.fwlog_queue) >
0366            ATH6KL_FWLOG_MAX_ENTRIES) {
0367         skb = __skb_dequeue(&ar->debug.fwlog_queue);
0368         kfree_skb(skb);
0369     }
0370 
0371     spin_unlock(&ar->debug.fwlog_queue.lock);
0372 
0373     return;
0374 }
0375 
0376 static int ath6kl_fwlog_open(struct inode *inode, struct file *file)
0377 {
0378     struct ath6kl *ar = inode->i_private;
0379 
0380     if (ar->debug.fwlog_open)
0381         return -EBUSY;
0382 
0383     ar->debug.fwlog_open = true;
0384 
0385     file->private_data = inode->i_private;
0386     return 0;
0387 }
0388 
0389 static int ath6kl_fwlog_release(struct inode *inode, struct file *file)
0390 {
0391     struct ath6kl *ar = inode->i_private;
0392 
0393     ar->debug.fwlog_open = false;
0394 
0395     return 0;
0396 }
0397 
0398 static ssize_t ath6kl_fwlog_read(struct file *file, char __user *user_buf,
0399                  size_t count, loff_t *ppos)
0400 {
0401     struct ath6kl *ar = file->private_data;
0402     struct sk_buff *skb;
0403     ssize_t ret_cnt;
0404     size_t len = 0;
0405     char *buf;
0406 
0407     buf = vmalloc(count);
0408     if (!buf)
0409         return -ENOMEM;
0410 
0411     /* read undelivered logs from firmware */
0412     ath6kl_read_fwlogs(ar);
0413 
0414     spin_lock(&ar->debug.fwlog_queue.lock);
0415 
0416     while ((skb = __skb_dequeue(&ar->debug.fwlog_queue))) {
0417         if (skb->len > count - len) {
0418             /* not enough space, put skb back and leave */
0419             __skb_queue_head(&ar->debug.fwlog_queue, skb);
0420             break;
0421         }
0422 
0423 
0424         memcpy(buf + len, skb->data, skb->len);
0425         len += skb->len;
0426 
0427         kfree_skb(skb);
0428     }
0429 
0430     spin_unlock(&ar->debug.fwlog_queue.lock);
0431 
0432     /* FIXME: what to do if len == 0? */
0433 
0434     ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
0435 
0436     vfree(buf);
0437 
0438     return ret_cnt;
0439 }
0440 
0441 static const struct file_operations fops_fwlog = {
0442     .open = ath6kl_fwlog_open,
0443     .release = ath6kl_fwlog_release,
0444     .read = ath6kl_fwlog_read,
0445     .owner = THIS_MODULE,
0446     .llseek = default_llseek,
0447 };
0448 
0449 static ssize_t ath6kl_fwlog_block_read(struct file *file,
0450                        char __user *user_buf,
0451                        size_t count,
0452                        loff_t *ppos)
0453 {
0454     struct ath6kl *ar = file->private_data;
0455     struct sk_buff *skb;
0456     ssize_t ret_cnt;
0457     size_t len = 0, not_copied;
0458     char *buf;
0459     int ret;
0460 
0461     buf = vmalloc(count);
0462     if (!buf)
0463         return -ENOMEM;
0464 
0465     spin_lock(&ar->debug.fwlog_queue.lock);
0466 
0467     if (skb_queue_len(&ar->debug.fwlog_queue) == 0) {
0468         /* we must init under queue lock */
0469         init_completion(&ar->debug.fwlog_completion);
0470 
0471         spin_unlock(&ar->debug.fwlog_queue.lock);
0472 
0473         ret = wait_for_completion_interruptible(
0474             &ar->debug.fwlog_completion);
0475         if (ret == -ERESTARTSYS) {
0476             vfree(buf);
0477             return ret;
0478         }
0479 
0480         spin_lock(&ar->debug.fwlog_queue.lock);
0481     }
0482 
0483     while ((skb = __skb_dequeue(&ar->debug.fwlog_queue))) {
0484         if (skb->len > count - len) {
0485             /* not enough space, put skb back and leave */
0486             __skb_queue_head(&ar->debug.fwlog_queue, skb);
0487             break;
0488         }
0489 
0490 
0491         memcpy(buf + len, skb->data, skb->len);
0492         len += skb->len;
0493 
0494         kfree_skb(skb);
0495     }
0496 
0497     spin_unlock(&ar->debug.fwlog_queue.lock);
0498 
0499     /* FIXME: what to do if len == 0? */
0500 
0501     not_copied = copy_to_user(user_buf, buf, len);
0502     if (not_copied != 0) {
0503         ret_cnt = -EFAULT;
0504         goto out;
0505     }
0506 
0507     *ppos = *ppos + len;
0508 
0509     ret_cnt = len;
0510 
0511 out:
0512     vfree(buf);
0513 
0514     return ret_cnt;
0515 }
0516 
0517 static const struct file_operations fops_fwlog_block = {
0518     .open = ath6kl_fwlog_open,
0519     .release = ath6kl_fwlog_release,
0520     .read = ath6kl_fwlog_block_read,
0521     .owner = THIS_MODULE,
0522     .llseek = default_llseek,
0523 };
0524 
0525 static ssize_t ath6kl_fwlog_mask_read(struct file *file, char __user *user_buf,
0526                       size_t count, loff_t *ppos)
0527 {
0528     struct ath6kl *ar = file->private_data;
0529     char buf[16];
0530     int len;
0531 
0532     len = snprintf(buf, sizeof(buf), "0x%x\n", ar->debug.fwlog_mask);
0533 
0534     return simple_read_from_buffer(user_buf, count, ppos, buf, len);
0535 }
0536 
0537 static ssize_t ath6kl_fwlog_mask_write(struct file *file,
0538                        const char __user *user_buf,
0539                        size_t count, loff_t *ppos)
0540 {
0541     struct ath6kl *ar = file->private_data;
0542     int ret;
0543 
0544     ret = kstrtou32_from_user(user_buf, count, 0, &ar->debug.fwlog_mask);
0545     if (ret)
0546         return ret;
0547 
0548     ret = ath6kl_wmi_config_debug_module_cmd(ar->wmi,
0549                          ATH6KL_FWLOG_VALID_MASK,
0550                          ar->debug.fwlog_mask);
0551     if (ret)
0552         return ret;
0553 
0554     return count;
0555 }
0556 
0557 static const struct file_operations fops_fwlog_mask = {
0558     .open = simple_open,
0559     .read = ath6kl_fwlog_mask_read,
0560     .write = ath6kl_fwlog_mask_write,
0561     .owner = THIS_MODULE,
0562     .llseek = default_llseek,
0563 };
0564 
0565 static ssize_t read_file_tgt_stats(struct file *file, char __user *user_buf,
0566                    size_t count, loff_t *ppos)
0567 {
0568     struct ath6kl *ar = file->private_data;
0569     struct ath6kl_vif *vif;
0570     struct target_stats *tgt_stats;
0571     char *buf;
0572     unsigned int len = 0, buf_len = 1500;
0573     int i;
0574     ssize_t ret_cnt;
0575     int rv;
0576 
0577     vif = ath6kl_vif_first(ar);
0578     if (!vif)
0579         return -EIO;
0580 
0581     buf = kzalloc(buf_len, GFP_KERNEL);
0582     if (!buf)
0583         return -ENOMEM;
0584 
0585     rv = ath6kl_read_tgt_stats(ar, vif);
0586     if (rv < 0) {
0587         kfree(buf);
0588         return rv;
0589     }
0590 
0591     tgt_stats = &vif->target_stats;
0592 
0593     len += scnprintf(buf + len, buf_len - len, "\n");
0594     len += scnprintf(buf + len, buf_len - len, "%25s\n",
0595              "Target Tx stats");
0596     len += scnprintf(buf + len, buf_len - len, "%25s\n\n",
0597              "=================");
0598     len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
0599              "Ucast packets", tgt_stats->tx_ucast_pkt);
0600     len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
0601              "Bcast packets", tgt_stats->tx_bcast_pkt);
0602     len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
0603              "Ucast byte", tgt_stats->tx_ucast_byte);
0604     len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
0605              "Bcast byte", tgt_stats->tx_bcast_byte);
0606     len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
0607              "Rts success cnt", tgt_stats->tx_rts_success_cnt);
0608     for (i = 0; i < 4; i++)
0609         len += scnprintf(buf + len, buf_len - len,
0610                  "%18s %d %10llu\n", "PER on ac",
0611                  i, tgt_stats->tx_pkt_per_ac[i]);
0612     len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
0613              "Error", tgt_stats->tx_err);
0614     len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
0615              "Fail count", tgt_stats->tx_fail_cnt);
0616     len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
0617              "Retry count", tgt_stats->tx_retry_cnt);
0618     len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
0619              "Multi retry cnt", tgt_stats->tx_mult_retry_cnt);
0620     len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
0621              "Rts fail cnt", tgt_stats->tx_rts_fail_cnt);
0622     len += scnprintf(buf + len, buf_len - len, "%25s %10llu\n\n",
0623              "TKIP counter measure used",
0624              tgt_stats->tkip_cnter_measures_invoked);
0625 
0626     len += scnprintf(buf + len, buf_len - len, "%25s\n",
0627              "Target Rx stats");
0628     len += scnprintf(buf + len, buf_len - len, "%25s\n",
0629              "=================");
0630 
0631     len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
0632              "Ucast packets", tgt_stats->rx_ucast_pkt);
0633     len += scnprintf(buf + len, buf_len - len, "%20s %10d\n",
0634              "Ucast Rate", tgt_stats->rx_ucast_rate);
0635     len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
0636              "Bcast packets", tgt_stats->rx_bcast_pkt);
0637     len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
0638              "Ucast byte", tgt_stats->rx_ucast_byte);
0639     len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
0640              "Bcast byte", tgt_stats->rx_bcast_byte);
0641     len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
0642              "Fragmented pkt", tgt_stats->rx_frgment_pkt);
0643     len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
0644              "Error", tgt_stats->rx_err);
0645     len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
0646              "CRC Err", tgt_stats->rx_crc_err);
0647     len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
0648              "Key cache miss", tgt_stats->rx_key_cache_miss);
0649     len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
0650              "Decrypt Err", tgt_stats->rx_decrypt_err);
0651     len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
0652              "Duplicate frame", tgt_stats->rx_dupl_frame);
0653     len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
0654              "Tkip Mic failure", tgt_stats->tkip_local_mic_fail);
0655     len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
0656              "TKIP format err", tgt_stats->tkip_fmt_err);
0657     len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
0658              "CCMP format Err", tgt_stats->ccmp_fmt_err);
0659     len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n\n",
0660              "CCMP Replay Err", tgt_stats->ccmp_replays);
0661 
0662     len += scnprintf(buf + len, buf_len - len, "%25s\n",
0663              "Misc Target stats");
0664     len += scnprintf(buf + len, buf_len - len, "%25s\n",
0665              "=================");
0666     len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
0667              "Beacon Miss count", tgt_stats->cs_bmiss_cnt);
0668     len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
0669              "Num Connects", tgt_stats->cs_connect_cnt);
0670     len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
0671              "Num disconnects", tgt_stats->cs_discon_cnt);
0672     len += scnprintf(buf + len, buf_len - len, "%20s %10d\n",
0673              "Beacon avg rssi", tgt_stats->cs_ave_beacon_rssi);
0674     len += scnprintf(buf + len, buf_len - len, "%20s %10d\n",
0675              "ARP pkt received", tgt_stats->arp_received);
0676     len += scnprintf(buf + len, buf_len - len, "%20s %10d\n",
0677              "ARP pkt matched", tgt_stats->arp_matched);
0678     len += scnprintf(buf + len, buf_len - len, "%20s %10d\n",
0679              "ARP pkt replied", tgt_stats->arp_replied);
0680 
0681     if (len > buf_len)
0682         len = buf_len;
0683 
0684     ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
0685 
0686     kfree(buf);
0687     return ret_cnt;
0688 }
0689 
0690 static const struct file_operations fops_tgt_stats = {
0691     .read = read_file_tgt_stats,
0692     .open = simple_open,
0693     .owner = THIS_MODULE,
0694     .llseek = default_llseek,
0695 };
0696 
0697 #define print_credit_info(fmt_str, ep_list_field)       \
0698     (len += scnprintf(buf + len, buf_len - len, fmt_str,    \
0699              ep_list->ep_list_field))
0700 #define CREDIT_INFO_DISPLAY_STRING_LEN  200
0701 #define CREDIT_INFO_LEN 128
0702 
0703 static ssize_t read_file_credit_dist_stats(struct file *file,
0704                        char __user *user_buf,
0705                        size_t count, loff_t *ppos)
0706 {
0707     struct ath6kl *ar = file->private_data;
0708     struct htc_target *target = ar->htc_target;
0709     struct htc_endpoint_credit_dist *ep_list;
0710     char *buf;
0711     unsigned int buf_len, len = 0;
0712     ssize_t ret_cnt;
0713 
0714     buf_len = CREDIT_INFO_DISPLAY_STRING_LEN +
0715           get_queue_depth(&target->cred_dist_list) * CREDIT_INFO_LEN;
0716     buf = kzalloc(buf_len, GFP_KERNEL);
0717     if (!buf)
0718         return -ENOMEM;
0719 
0720     len += scnprintf(buf + len, buf_len - len, "%25s%5d\n",
0721              "Total Avail Credits: ",
0722              target->credit_info->total_avail_credits);
0723     len += scnprintf(buf + len, buf_len - len, "%25s%5d\n",
0724              "Free credits :",
0725              target->credit_info->cur_free_credits);
0726 
0727     len += scnprintf(buf + len, buf_len - len,
0728              " Epid  Flags    Cred_norm  Cred_min  Credits  Cred_assngd"
0729              "  Seek_cred  Cred_sz  Cred_per_msg  Cred_to_dist"
0730              "  qdepth\n");
0731 
0732     list_for_each_entry(ep_list, &target->cred_dist_list, list) {
0733         print_credit_info("  %2d", endpoint);
0734         print_credit_info("%10x", dist_flags);
0735         print_credit_info("%8d", cred_norm);
0736         print_credit_info("%9d", cred_min);
0737         print_credit_info("%9d", credits);
0738         print_credit_info("%10d", cred_assngd);
0739         print_credit_info("%13d", seek_cred);
0740         print_credit_info("%12d", cred_sz);
0741         print_credit_info("%9d", cred_per_msg);
0742         print_credit_info("%14d", cred_to_dist);
0743         len += scnprintf(buf + len, buf_len - len, "%12d\n",
0744                  get_queue_depth(&ep_list->htc_ep->txq));
0745     }
0746 
0747     if (len > buf_len)
0748         len = buf_len;
0749 
0750     ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
0751     kfree(buf);
0752     return ret_cnt;
0753 }
0754 
0755 static const struct file_operations fops_credit_dist_stats = {
0756     .read = read_file_credit_dist_stats,
0757     .open = simple_open,
0758     .owner = THIS_MODULE,
0759     .llseek = default_llseek,
0760 };
0761 
0762 static unsigned int print_endpoint_stat(struct htc_target *target, char *buf,
0763                     unsigned int buf_len, unsigned int len,
0764                     int offset, const char *name)
0765 {
0766     int i;
0767     struct htc_endpoint_stats *ep_st;
0768     u32 *counter;
0769 
0770     len += scnprintf(buf + len, buf_len - len, "%s:", name);
0771     for (i = 0; i < ENDPOINT_MAX; i++) {
0772         ep_st = &target->endpoint[i].ep_st;
0773         counter = ((u32 *) ep_st) + (offset / 4);
0774         len += scnprintf(buf + len, buf_len - len, " %u", *counter);
0775     }
0776     len += scnprintf(buf + len, buf_len - len, "\n");
0777 
0778     return len;
0779 }
0780 
0781 static ssize_t ath6kl_endpoint_stats_read(struct file *file,
0782                       char __user *user_buf,
0783                       size_t count, loff_t *ppos)
0784 {
0785     struct ath6kl *ar = file->private_data;
0786     struct htc_target *target = ar->htc_target;
0787     char *buf;
0788     unsigned int buf_len, len = 0;
0789     ssize_t ret_cnt;
0790 
0791     buf_len = sizeof(struct htc_endpoint_stats) / sizeof(u32) *
0792         (25 + ENDPOINT_MAX * 11);
0793     buf = kmalloc(buf_len, GFP_KERNEL);
0794     if (!buf)
0795         return -ENOMEM;
0796 
0797 #define EPSTAT(name)                            \
0798     do {                                \
0799         len = print_endpoint_stat(target, buf, buf_len, len,    \
0800                       offsetof(struct htc_endpoint_stats, \
0801                            name),       \
0802                       #name);           \
0803     } while (0)
0804 
0805     EPSTAT(cred_low_indicate);
0806     EPSTAT(tx_issued);
0807     EPSTAT(tx_pkt_bundled);
0808     EPSTAT(tx_bundles);
0809     EPSTAT(tx_dropped);
0810     EPSTAT(tx_cred_rpt);
0811     EPSTAT(cred_rpt_from_rx);
0812     EPSTAT(cred_rpt_from_other);
0813     EPSTAT(cred_rpt_ep0);
0814     EPSTAT(cred_from_rx);
0815     EPSTAT(cred_from_other);
0816     EPSTAT(cred_from_ep0);
0817     EPSTAT(cred_cosumd);
0818     EPSTAT(cred_retnd);
0819     EPSTAT(rx_pkts);
0820     EPSTAT(rx_lkahds);
0821     EPSTAT(rx_bundl);
0822     EPSTAT(rx_bundle_lkahd);
0823     EPSTAT(rx_bundle_from_hdr);
0824     EPSTAT(rx_alloc_thresh_hit);
0825     EPSTAT(rxalloc_thresh_byte);
0826 #undef EPSTAT
0827 
0828     if (len > buf_len)
0829         len = buf_len;
0830 
0831     ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
0832     kfree(buf);
0833     return ret_cnt;
0834 }
0835 
0836 static ssize_t ath6kl_endpoint_stats_write(struct file *file,
0837                        const char __user *user_buf,
0838                        size_t count, loff_t *ppos)
0839 {
0840     struct ath6kl *ar = file->private_data;
0841     struct htc_target *target = ar->htc_target;
0842     int ret, i;
0843     u32 val;
0844     struct htc_endpoint_stats *ep_st;
0845 
0846     ret = kstrtou32_from_user(user_buf, count, 0, &val);
0847     if (ret)
0848         return ret;
0849     if (val == 0) {
0850         for (i = 0; i < ENDPOINT_MAX; i++) {
0851             ep_st = &target->endpoint[i].ep_st;
0852             memset(ep_st, 0, sizeof(*ep_st));
0853         }
0854     }
0855 
0856     return count;
0857 }
0858 
0859 static const struct file_operations fops_endpoint_stats = {
0860     .open = simple_open,
0861     .read = ath6kl_endpoint_stats_read,
0862     .write = ath6kl_endpoint_stats_write,
0863     .owner = THIS_MODULE,
0864     .llseek = default_llseek,
0865 };
0866 
0867 static unsigned long ath6kl_get_num_reg(void)
0868 {
0869     int i;
0870     unsigned long n_reg = 0;
0871 
0872     for (i = 0; i < ARRAY_SIZE(diag_reg); i++)
0873         n_reg = n_reg +
0874              (diag_reg[i].reg_end - diag_reg[i].reg_start) / 4 + 1;
0875 
0876     return n_reg;
0877 }
0878 
0879 static bool ath6kl_dbg_is_diag_reg_valid(u32 reg_addr)
0880 {
0881     int i;
0882 
0883     for (i = 0; i < ARRAY_SIZE(diag_reg); i++) {
0884         if (reg_addr >= diag_reg[i].reg_start &&
0885             reg_addr <= diag_reg[i].reg_end)
0886             return true;
0887     }
0888 
0889     return false;
0890 }
0891 
0892 static ssize_t ath6kl_regread_read(struct file *file, char __user *user_buf,
0893                     size_t count, loff_t *ppos)
0894 {
0895     struct ath6kl *ar = file->private_data;
0896     u8 buf[50];
0897     unsigned int len = 0;
0898 
0899     if (ar->debug.dbgfs_diag_reg)
0900         len += scnprintf(buf + len, sizeof(buf) - len, "0x%x\n",
0901                 ar->debug.dbgfs_diag_reg);
0902     else
0903         len += scnprintf(buf + len, sizeof(buf) - len,
0904                  "All diag registers\n");
0905 
0906     return simple_read_from_buffer(user_buf, count, ppos, buf, len);
0907 }
0908 
0909 static ssize_t ath6kl_regread_write(struct file *file,
0910                     const char __user *user_buf,
0911                     size_t count, loff_t *ppos)
0912 {
0913     struct ath6kl *ar = file->private_data;
0914     unsigned long reg_addr;
0915 
0916     if (kstrtoul_from_user(user_buf, count, 0, &reg_addr))
0917         return -EINVAL;
0918 
0919     if ((reg_addr % 4) != 0)
0920         return -EINVAL;
0921 
0922     if (reg_addr && !ath6kl_dbg_is_diag_reg_valid(reg_addr))
0923         return -EINVAL;
0924 
0925     ar->debug.dbgfs_diag_reg = reg_addr;
0926 
0927     return count;
0928 }
0929 
0930 static const struct file_operations fops_diag_reg_read = {
0931     .read = ath6kl_regread_read,
0932     .write = ath6kl_regread_write,
0933     .open = simple_open,
0934     .owner = THIS_MODULE,
0935     .llseek = default_llseek,
0936 };
0937 
0938 static int ath6kl_regdump_open(struct inode *inode, struct file *file)
0939 {
0940     struct ath6kl *ar = inode->i_private;
0941     u8 *buf;
0942     unsigned long int reg_len;
0943     unsigned int len = 0, n_reg;
0944     u32 addr;
0945     __le32 reg_val;
0946     int i, status;
0947 
0948     /* Dump all the registers if no register is specified */
0949     if (!ar->debug.dbgfs_diag_reg)
0950         n_reg = ath6kl_get_num_reg();
0951     else
0952         n_reg = 1;
0953 
0954     reg_len = n_reg * REG_OUTPUT_LEN_PER_LINE;
0955     if (n_reg > 1)
0956         reg_len += REGTYPE_STR_LEN;
0957 
0958     buf = vmalloc(reg_len);
0959     if (!buf)
0960         return -ENOMEM;
0961 
0962     if (n_reg == 1) {
0963         addr = ar->debug.dbgfs_diag_reg;
0964 
0965         status = ath6kl_diag_read32(ar,
0966                 TARG_VTOP(ar->target_type, addr),
0967                 (u32 *)&reg_val);
0968         if (status)
0969             goto fail_reg_read;
0970 
0971         len += scnprintf(buf + len, reg_len - len,
0972                  "0x%06x 0x%08x\n", addr, le32_to_cpu(reg_val));
0973         goto done;
0974     }
0975 
0976     for (i = 0; i < ARRAY_SIZE(diag_reg); i++) {
0977         len += scnprintf(buf + len, reg_len - len,
0978                 "%s\n", diag_reg[i].reg_info);
0979         for (addr = diag_reg[i].reg_start;
0980              addr <= diag_reg[i].reg_end; addr += 4) {
0981             status = ath6kl_diag_read32(ar,
0982                     TARG_VTOP(ar->target_type, addr),
0983                     (u32 *)&reg_val);
0984             if (status)
0985                 goto fail_reg_read;
0986 
0987             len += scnprintf(buf + len, reg_len - len,
0988                     "0x%06x 0x%08x\n",
0989                     addr, le32_to_cpu(reg_val));
0990         }
0991     }
0992 
0993 done:
0994     file->private_data = buf;
0995     return 0;
0996 
0997 fail_reg_read:
0998     ath6kl_warn("Unable to read memory:%u\n", addr);
0999     vfree(buf);
1000     return -EIO;
1001 }
1002 
1003 static ssize_t ath6kl_regdump_read(struct file *file, char __user *user_buf,
1004                   size_t count, loff_t *ppos)
1005 {
1006     u8 *buf = file->private_data;
1007     return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));
1008 }
1009 
1010 static int ath6kl_regdump_release(struct inode *inode, struct file *file)
1011 {
1012     vfree(file->private_data);
1013     return 0;
1014 }
1015 
1016 static const struct file_operations fops_reg_dump = {
1017     .open = ath6kl_regdump_open,
1018     .read = ath6kl_regdump_read,
1019     .release = ath6kl_regdump_release,
1020     .owner = THIS_MODULE,
1021     .llseek = default_llseek,
1022 };
1023 
1024 static ssize_t ath6kl_lrssi_roam_write(struct file *file,
1025                        const char __user *user_buf,
1026                        size_t count, loff_t *ppos)
1027 {
1028     struct ath6kl *ar = file->private_data;
1029     unsigned long lrssi_roam_threshold;
1030     int ret;
1031 
1032     if (kstrtoul_from_user(user_buf, count, 0, &lrssi_roam_threshold))
1033         return -EINVAL;
1034 
1035     ar->lrssi_roam_threshold = lrssi_roam_threshold;
1036 
1037     ret = ath6kl_wmi_set_roam_lrssi_cmd(ar->wmi, ar->lrssi_roam_threshold);
1038 
1039     if (ret)
1040         return ret;
1041     return count;
1042 }
1043 
1044 static ssize_t ath6kl_lrssi_roam_read(struct file *file,
1045                       char __user *user_buf,
1046                       size_t count, loff_t *ppos)
1047 {
1048     struct ath6kl *ar = file->private_data;
1049     char buf[32];
1050     unsigned int len;
1051 
1052     len = snprintf(buf, sizeof(buf), "%u\n", ar->lrssi_roam_threshold);
1053 
1054     return simple_read_from_buffer(user_buf, count, ppos, buf, len);
1055 }
1056 
1057 static const struct file_operations fops_lrssi_roam_threshold = {
1058     .read = ath6kl_lrssi_roam_read,
1059     .write = ath6kl_lrssi_roam_write,
1060     .open = simple_open,
1061     .owner = THIS_MODULE,
1062     .llseek = default_llseek,
1063 };
1064 
1065 static ssize_t ath6kl_regwrite_read(struct file *file,
1066                     char __user *user_buf,
1067                     size_t count, loff_t *ppos)
1068 {
1069     struct ath6kl *ar = file->private_data;
1070     u8 buf[32];
1071     unsigned int len = 0;
1072 
1073     len = scnprintf(buf, sizeof(buf), "Addr: 0x%x Val: 0x%x\n",
1074             ar->debug.diag_reg_addr_wr, ar->debug.diag_reg_val_wr);
1075 
1076     return simple_read_from_buffer(user_buf, count, ppos, buf, len);
1077 }
1078 
1079 static ssize_t ath6kl_regwrite_write(struct file *file,
1080                      const char __user *user_buf,
1081                      size_t count, loff_t *ppos)
1082 {
1083     struct ath6kl *ar = file->private_data;
1084     char buf[32];
1085     char *sptr, *token;
1086     unsigned int len = 0;
1087     u32 reg_addr, reg_val;
1088 
1089     len = min(count, sizeof(buf) - 1);
1090     if (copy_from_user(buf, user_buf, len))
1091         return -EFAULT;
1092 
1093     buf[len] = '\0';
1094     sptr = buf;
1095 
1096     token = strsep(&sptr, "=");
1097     if (!token)
1098         return -EINVAL;
1099 
1100     if (kstrtou32(token, 0, &reg_addr))
1101         return -EINVAL;
1102 
1103     if (!ath6kl_dbg_is_diag_reg_valid(reg_addr))
1104         return -EINVAL;
1105 
1106     if (kstrtou32(sptr, 0, &reg_val))
1107         return -EINVAL;
1108 
1109     ar->debug.diag_reg_addr_wr = reg_addr;
1110     ar->debug.diag_reg_val_wr = reg_val;
1111 
1112     if (ath6kl_diag_write32(ar, ar->debug.diag_reg_addr_wr,
1113                 cpu_to_le32(ar->debug.diag_reg_val_wr)))
1114         return -EIO;
1115 
1116     return count;
1117 }
1118 
1119 static const struct file_operations fops_diag_reg_write = {
1120     .read = ath6kl_regwrite_read,
1121     .write = ath6kl_regwrite_write,
1122     .open = simple_open,
1123     .owner = THIS_MODULE,
1124     .llseek = default_llseek,
1125 };
1126 
1127 int ath6kl_debug_roam_tbl_event(struct ath6kl *ar, const void *buf,
1128                 size_t len)
1129 {
1130     const struct wmi_target_roam_tbl *tbl;
1131     u16 num_entries;
1132 
1133     if (len < sizeof(*tbl))
1134         return -EINVAL;
1135 
1136     tbl = (const struct wmi_target_roam_tbl *) buf;
1137     num_entries = le16_to_cpu(tbl->num_entries);
1138     if (struct_size(tbl, info, num_entries) > len)
1139         return -EINVAL;
1140 
1141     if (ar->debug.roam_tbl == NULL ||
1142         ar->debug.roam_tbl_len < (unsigned int) len) {
1143         kfree(ar->debug.roam_tbl);
1144         ar->debug.roam_tbl = kmalloc(len, GFP_ATOMIC);
1145         if (ar->debug.roam_tbl == NULL)
1146             return -ENOMEM;
1147     }
1148 
1149     memcpy(ar->debug.roam_tbl, buf, len);
1150     ar->debug.roam_tbl_len = len;
1151 
1152     if (test_bit(ROAM_TBL_PEND, &ar->flag)) {
1153         clear_bit(ROAM_TBL_PEND, &ar->flag);
1154         wake_up(&ar->event_wq);
1155     }
1156 
1157     return 0;
1158 }
1159 
1160 static ssize_t ath6kl_roam_table_read(struct file *file, char __user *user_buf,
1161                       size_t count, loff_t *ppos)
1162 {
1163     struct ath6kl *ar = file->private_data;
1164     int ret;
1165     long left;
1166     struct wmi_target_roam_tbl *tbl;
1167     u16 num_entries, i;
1168     char *buf;
1169     unsigned int len, buf_len;
1170     ssize_t ret_cnt;
1171 
1172     if (down_interruptible(&ar->sem))
1173         return -EBUSY;
1174 
1175     set_bit(ROAM_TBL_PEND, &ar->flag);
1176 
1177     ret = ath6kl_wmi_get_roam_tbl_cmd(ar->wmi);
1178     if (ret) {
1179         up(&ar->sem);
1180         return ret;
1181     }
1182 
1183     left = wait_event_interruptible_timeout(
1184         ar->event_wq, !test_bit(ROAM_TBL_PEND, &ar->flag), WMI_TIMEOUT);
1185     up(&ar->sem);
1186 
1187     if (left <= 0)
1188         return -ETIMEDOUT;
1189 
1190     if (ar->debug.roam_tbl == NULL)
1191         return -ENOMEM;
1192 
1193     tbl = (struct wmi_target_roam_tbl *) ar->debug.roam_tbl;
1194     num_entries = le16_to_cpu(tbl->num_entries);
1195 
1196     buf_len = 100 + num_entries * 100;
1197     buf = kzalloc(buf_len, GFP_KERNEL);
1198     if (buf == NULL)
1199         return -ENOMEM;
1200     len = 0;
1201     len += scnprintf(buf + len, buf_len - len,
1202              "roam_mode=%u\n\n"
1203              "# roam_util bssid rssi rssidt last_rssi util bias\n",
1204              le16_to_cpu(tbl->roam_mode));
1205 
1206     for (i = 0; i < num_entries; i++) {
1207         struct wmi_bss_roam_info *info = &tbl->info[i];
1208         len += scnprintf(buf + len, buf_len - len,
1209                  "%d %pM %d %d %d %d %d\n",
1210                  a_sle32_to_cpu(info->roam_util), info->bssid,
1211                  info->rssi, info->rssidt, info->last_rssi,
1212                  info->util, info->bias);
1213     }
1214 
1215     if (len > buf_len)
1216         len = buf_len;
1217 
1218     ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
1219 
1220     kfree(buf);
1221     return ret_cnt;
1222 }
1223 
1224 static const struct file_operations fops_roam_table = {
1225     .read = ath6kl_roam_table_read,
1226     .open = simple_open,
1227     .owner = THIS_MODULE,
1228     .llseek = default_llseek,
1229 };
1230 
1231 static ssize_t ath6kl_force_roam_write(struct file *file,
1232                        const char __user *user_buf,
1233                        size_t count, loff_t *ppos)
1234 {
1235     struct ath6kl *ar = file->private_data;
1236     int ret;
1237     char buf[20];
1238     size_t len;
1239     u8 bssid[ETH_ALEN];
1240 
1241     len = min(count, sizeof(buf) - 1);
1242     if (copy_from_user(buf, user_buf, len))
1243         return -EFAULT;
1244     buf[len] = '\0';
1245 
1246     if (!mac_pton(buf, bssid))
1247         return -EINVAL;
1248 
1249     ret = ath6kl_wmi_force_roam_cmd(ar->wmi, bssid);
1250     if (ret)
1251         return ret;
1252 
1253     return count;
1254 }
1255 
1256 static const struct file_operations fops_force_roam = {
1257     .write = ath6kl_force_roam_write,
1258     .open = simple_open,
1259     .owner = THIS_MODULE,
1260     .llseek = default_llseek,
1261 };
1262 
1263 static ssize_t ath6kl_roam_mode_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     char buf[20];
1270     size_t len;
1271     enum wmi_roam_mode mode;
1272 
1273     len = min(count, sizeof(buf) - 1);
1274     if (copy_from_user(buf, user_buf, len))
1275         return -EFAULT;
1276     buf[len] = '\0';
1277     if (len > 0 && buf[len - 1] == '\n')
1278         buf[len - 1] = '\0';
1279 
1280     if (strcasecmp(buf, "default") == 0)
1281         mode = WMI_DEFAULT_ROAM_MODE;
1282     else if (strcasecmp(buf, "bssbias") == 0)
1283         mode = WMI_HOST_BIAS_ROAM_MODE;
1284     else if (strcasecmp(buf, "lock") == 0)
1285         mode = WMI_LOCK_BSS_MODE;
1286     else
1287         return -EINVAL;
1288 
1289     ret = ath6kl_wmi_set_roam_mode_cmd(ar->wmi, mode);
1290     if (ret)
1291         return ret;
1292 
1293     return count;
1294 }
1295 
1296 static const struct file_operations fops_roam_mode = {
1297     .write = ath6kl_roam_mode_write,
1298     .open = simple_open,
1299     .owner = THIS_MODULE,
1300     .llseek = default_llseek,
1301 };
1302 
1303 void ath6kl_debug_set_keepalive(struct ath6kl *ar, u8 keepalive)
1304 {
1305     ar->debug.keepalive = keepalive;
1306 }
1307 
1308 static ssize_t ath6kl_keepalive_read(struct file *file, char __user *user_buf,
1309                      size_t count, loff_t *ppos)
1310 {
1311     struct ath6kl *ar = file->private_data;
1312     char buf[16];
1313     int len;
1314 
1315     len = snprintf(buf, sizeof(buf), "%u\n", ar->debug.keepalive);
1316 
1317     return simple_read_from_buffer(user_buf, count, ppos, buf, len);
1318 }
1319 
1320 static ssize_t ath6kl_keepalive_write(struct file *file,
1321                       const char __user *user_buf,
1322                       size_t count, loff_t *ppos)
1323 {
1324     struct ath6kl *ar = file->private_data;
1325     int ret;
1326     u8 val;
1327 
1328     ret = kstrtou8_from_user(user_buf, count, 0, &val);
1329     if (ret)
1330         return ret;
1331 
1332     ret = ath6kl_wmi_set_keepalive_cmd(ar->wmi, 0, val);
1333     if (ret)
1334         return ret;
1335 
1336     return count;
1337 }
1338 
1339 static const struct file_operations fops_keepalive = {
1340     .open = simple_open,
1341     .read = ath6kl_keepalive_read,
1342     .write = ath6kl_keepalive_write,
1343     .owner = THIS_MODULE,
1344     .llseek = default_llseek,
1345 };
1346 
1347 void ath6kl_debug_set_disconnect_timeout(struct ath6kl *ar, u8 timeout)
1348 {
1349     ar->debug.disc_timeout = timeout;
1350 }
1351 
1352 static ssize_t ath6kl_disconnect_timeout_read(struct file *file,
1353                           char __user *user_buf,
1354                           size_t count, loff_t *ppos)
1355 {
1356     struct ath6kl *ar = file->private_data;
1357     char buf[16];
1358     int len;
1359 
1360     len = snprintf(buf, sizeof(buf), "%u\n", ar->debug.disc_timeout);
1361 
1362     return simple_read_from_buffer(user_buf, count, ppos, buf, len);
1363 }
1364 
1365 static ssize_t ath6kl_disconnect_timeout_write(struct file *file,
1366                            const char __user *user_buf,
1367                            size_t count, loff_t *ppos)
1368 {
1369     struct ath6kl *ar = file->private_data;
1370     int ret;
1371     u8 val;
1372 
1373     ret = kstrtou8_from_user(user_buf, count, 0, &val);
1374     if (ret)
1375         return ret;
1376 
1377     ret = ath6kl_wmi_disctimeout_cmd(ar->wmi, 0, val);
1378     if (ret)
1379         return ret;
1380 
1381     return count;
1382 }
1383 
1384 static const struct file_operations fops_disconnect_timeout = {
1385     .open = simple_open,
1386     .read = ath6kl_disconnect_timeout_read,
1387     .write = ath6kl_disconnect_timeout_write,
1388     .owner = THIS_MODULE,
1389     .llseek = default_llseek,
1390 };
1391 
1392 static ssize_t ath6kl_create_qos_write(struct file *file,
1393                         const char __user *user_buf,
1394                         size_t count, loff_t *ppos)
1395 {
1396     struct ath6kl *ar = file->private_data;
1397     struct ath6kl_vif *vif;
1398     char buf[200];
1399     ssize_t len;
1400     char *sptr, *token;
1401     struct wmi_create_pstream_cmd pstream;
1402     u32 val32;
1403     u16 val16;
1404 
1405     vif = ath6kl_vif_first(ar);
1406     if (!vif)
1407         return -EIO;
1408 
1409     len = min(count, sizeof(buf) - 1);
1410     if (copy_from_user(buf, user_buf, len))
1411         return -EFAULT;
1412     buf[len] = '\0';
1413     sptr = buf;
1414 
1415     token = strsep(&sptr, " ");
1416     if (!token)
1417         return -EINVAL;
1418     if (kstrtou8(token, 0, &pstream.user_pri))
1419         return -EINVAL;
1420 
1421     token = strsep(&sptr, " ");
1422     if (!token)
1423         return -EINVAL;
1424     if (kstrtou8(token, 0, &pstream.traffic_direc))
1425         return -EINVAL;
1426 
1427     token = strsep(&sptr, " ");
1428     if (!token)
1429         return -EINVAL;
1430     if (kstrtou8(token, 0, &pstream.traffic_class))
1431         return -EINVAL;
1432 
1433     token = strsep(&sptr, " ");
1434     if (!token)
1435         return -EINVAL;
1436     if (kstrtou8(token, 0, &pstream.traffic_type))
1437         return -EINVAL;
1438 
1439     token = strsep(&sptr, " ");
1440     if (!token)
1441         return -EINVAL;
1442     if (kstrtou8(token, 0, &pstream.voice_psc_cap))
1443         return -EINVAL;
1444 
1445     token = strsep(&sptr, " ");
1446     if (!token)
1447         return -EINVAL;
1448     if (kstrtou32(token, 0, &val32))
1449         return -EINVAL;
1450     pstream.min_service_int = cpu_to_le32(val32);
1451 
1452     token = strsep(&sptr, " ");
1453     if (!token)
1454         return -EINVAL;
1455     if (kstrtou32(token, 0, &val32))
1456         return -EINVAL;
1457     pstream.max_service_int = cpu_to_le32(val32);
1458 
1459     token = strsep(&sptr, " ");
1460     if (!token)
1461         return -EINVAL;
1462     if (kstrtou32(token, 0, &val32))
1463         return -EINVAL;
1464     pstream.inactivity_int = cpu_to_le32(val32);
1465 
1466     token = strsep(&sptr, " ");
1467     if (!token)
1468         return -EINVAL;
1469     if (kstrtou32(token, 0, &val32))
1470         return -EINVAL;
1471     pstream.suspension_int = cpu_to_le32(val32);
1472 
1473     token = strsep(&sptr, " ");
1474     if (!token)
1475         return -EINVAL;
1476     if (kstrtou32(token, 0, &val32))
1477         return -EINVAL;
1478     pstream.service_start_time = cpu_to_le32(val32);
1479 
1480     token = strsep(&sptr, " ");
1481     if (!token)
1482         return -EINVAL;
1483     if (kstrtou8(token, 0, &pstream.tsid))
1484         return -EINVAL;
1485 
1486     token = strsep(&sptr, " ");
1487     if (!token)
1488         return -EINVAL;
1489     if (kstrtou16(token, 0, &val16))
1490         return -EINVAL;
1491     pstream.nominal_msdu = cpu_to_le16(val16);
1492 
1493     token = strsep(&sptr, " ");
1494     if (!token)
1495         return -EINVAL;
1496     if (kstrtou16(token, 0, &val16))
1497         return -EINVAL;
1498     pstream.max_msdu = cpu_to_le16(val16);
1499 
1500     token = strsep(&sptr, " ");
1501     if (!token)
1502         return -EINVAL;
1503     if (kstrtou32(token, 0, &val32))
1504         return -EINVAL;
1505     pstream.min_data_rate = cpu_to_le32(val32);
1506 
1507     token = strsep(&sptr, " ");
1508     if (!token)
1509         return -EINVAL;
1510     if (kstrtou32(token, 0, &val32))
1511         return -EINVAL;
1512     pstream.mean_data_rate = cpu_to_le32(val32);
1513 
1514     token = strsep(&sptr, " ");
1515     if (!token)
1516         return -EINVAL;
1517     if (kstrtou32(token, 0, &val32))
1518         return -EINVAL;
1519     pstream.peak_data_rate = cpu_to_le32(val32);
1520 
1521     token = strsep(&sptr, " ");
1522     if (!token)
1523         return -EINVAL;
1524     if (kstrtou32(token, 0, &val32))
1525         return -EINVAL;
1526     pstream.max_burst_size = cpu_to_le32(val32);
1527 
1528     token = strsep(&sptr, " ");
1529     if (!token)
1530         return -EINVAL;
1531     if (kstrtou32(token, 0, &val32))
1532         return -EINVAL;
1533     pstream.delay_bound = cpu_to_le32(val32);
1534 
1535     token = strsep(&sptr, " ");
1536     if (!token)
1537         return -EINVAL;
1538     if (kstrtou32(token, 0, &val32))
1539         return -EINVAL;
1540     pstream.min_phy_rate = cpu_to_le32(val32);
1541 
1542     token = strsep(&sptr, " ");
1543     if (!token)
1544         return -EINVAL;
1545     if (kstrtou32(token, 0, &val32))
1546         return -EINVAL;
1547     pstream.sba = cpu_to_le32(val32);
1548 
1549     token = strsep(&sptr, " ");
1550     if (!token)
1551         return -EINVAL;
1552     if (kstrtou32(token, 0, &val32))
1553         return -EINVAL;
1554     pstream.medium_time = cpu_to_le32(val32);
1555 
1556     pstream.nominal_phy = le32_to_cpu(pstream.min_phy_rate) / 1000000;
1557 
1558     ath6kl_wmi_create_pstream_cmd(ar->wmi, vif->fw_vif_idx, &pstream);
1559 
1560     return count;
1561 }
1562 
1563 static const struct file_operations fops_create_qos = {
1564     .write = ath6kl_create_qos_write,
1565     .open = simple_open,
1566     .owner = THIS_MODULE,
1567     .llseek = default_llseek,
1568 };
1569 
1570 static ssize_t ath6kl_delete_qos_write(struct file *file,
1571                 const char __user *user_buf,
1572                 size_t count, loff_t *ppos)
1573 {
1574     struct ath6kl *ar = file->private_data;
1575     struct ath6kl_vif *vif;
1576     char buf[100];
1577     ssize_t len;
1578     char *sptr, *token;
1579     u8 traffic_class;
1580     u8 tsid;
1581 
1582     vif = ath6kl_vif_first(ar);
1583     if (!vif)
1584         return -EIO;
1585 
1586     len = min(count, sizeof(buf) - 1);
1587     if (copy_from_user(buf, user_buf, len))
1588         return -EFAULT;
1589     buf[len] = '\0';
1590     sptr = buf;
1591 
1592     token = strsep(&sptr, " ");
1593     if (!token)
1594         return -EINVAL;
1595     if (kstrtou8(token, 0, &traffic_class))
1596         return -EINVAL;
1597 
1598     token = strsep(&sptr, " ");
1599     if (!token)
1600         return -EINVAL;
1601     if (kstrtou8(token, 0, &tsid))
1602         return -EINVAL;
1603 
1604     ath6kl_wmi_delete_pstream_cmd(ar->wmi, vif->fw_vif_idx,
1605                       traffic_class, tsid);
1606 
1607     return count;
1608 }
1609 
1610 static const struct file_operations fops_delete_qos = {
1611     .write = ath6kl_delete_qos_write,
1612     .open = simple_open,
1613     .owner = THIS_MODULE,
1614     .llseek = default_llseek,
1615 };
1616 
1617 static ssize_t ath6kl_bgscan_int_write(struct file *file,
1618                 const char __user *user_buf,
1619                 size_t count, loff_t *ppos)
1620 {
1621     struct ath6kl *ar = file->private_data;
1622     struct ath6kl_vif *vif;
1623     u16 bgscan_int;
1624     char buf[32];
1625     ssize_t len;
1626 
1627     vif = ath6kl_vif_first(ar);
1628     if (!vif)
1629         return -EIO;
1630 
1631     len = min(count, sizeof(buf) - 1);
1632     if (copy_from_user(buf, user_buf, len))
1633         return -EFAULT;
1634 
1635     buf[len] = '\0';
1636     if (kstrtou16(buf, 0, &bgscan_int))
1637         return -EINVAL;
1638 
1639     if (bgscan_int == 0)
1640         bgscan_int = 0xffff;
1641 
1642     vif->bg_scan_period = bgscan_int;
1643 
1644     ath6kl_wmi_scanparams_cmd(ar->wmi, 0, 0, 0, bgscan_int, 0, 0, 0, 3,
1645                   0, 0, 0);
1646 
1647     return count;
1648 }
1649 
1650 static const struct file_operations fops_bgscan_int = {
1651     .write = ath6kl_bgscan_int_write,
1652     .open = simple_open,
1653     .owner = THIS_MODULE,
1654     .llseek = default_llseek,
1655 };
1656 
1657 static ssize_t ath6kl_listen_int_write(struct file *file,
1658                        const char __user *user_buf,
1659                        size_t count, loff_t *ppos)
1660 {
1661     struct ath6kl *ar = file->private_data;
1662     struct ath6kl_vif *vif;
1663     u16 listen_interval;
1664     char buf[32];
1665     ssize_t len;
1666 
1667     vif = ath6kl_vif_first(ar);
1668     if (!vif)
1669         return -EIO;
1670 
1671     len = min(count, sizeof(buf) - 1);
1672     if (copy_from_user(buf, user_buf, len))
1673         return -EFAULT;
1674 
1675     buf[len] = '\0';
1676     if (kstrtou16(buf, 0, &listen_interval))
1677         return -EINVAL;
1678 
1679     if ((listen_interval < 15) || (listen_interval > 3000))
1680         return -EINVAL;
1681 
1682     vif->listen_intvl_t = listen_interval;
1683     ath6kl_wmi_listeninterval_cmd(ar->wmi, vif->fw_vif_idx,
1684                       vif->listen_intvl_t, 0);
1685 
1686     return count;
1687 }
1688 
1689 static ssize_t ath6kl_listen_int_read(struct file *file,
1690                       char __user *user_buf,
1691                       size_t count, loff_t *ppos)
1692 {
1693     struct ath6kl *ar = file->private_data;
1694     struct ath6kl_vif *vif;
1695     char buf[32];
1696     int len;
1697 
1698     vif = ath6kl_vif_first(ar);
1699     if (!vif)
1700         return -EIO;
1701 
1702     len = scnprintf(buf, sizeof(buf), "%u\n", vif->listen_intvl_t);
1703 
1704     return simple_read_from_buffer(user_buf, count, ppos, buf, len);
1705 }
1706 
1707 static const struct file_operations fops_listen_int = {
1708     .read = ath6kl_listen_int_read,
1709     .write = ath6kl_listen_int_write,
1710     .open = simple_open,
1711     .owner = THIS_MODULE,
1712     .llseek = default_llseek,
1713 };
1714 
1715 static ssize_t ath6kl_power_params_write(struct file *file,
1716                         const char __user *user_buf,
1717                         size_t count, loff_t *ppos)
1718 {
1719     struct ath6kl *ar = file->private_data;
1720     u8 buf[100];
1721     unsigned int len = 0;
1722     char *sptr, *token;
1723     u16 idle_period, ps_poll_num, dtim,
1724         tx_wakeup, num_tx;
1725 
1726     len = min(count, sizeof(buf) - 1);
1727     if (copy_from_user(buf, user_buf, len))
1728         return -EFAULT;
1729     buf[len] = '\0';
1730     sptr = buf;
1731 
1732     token = strsep(&sptr, " ");
1733     if (!token)
1734         return -EINVAL;
1735     if (kstrtou16(token, 0, &idle_period))
1736         return -EINVAL;
1737 
1738     token = strsep(&sptr, " ");
1739     if (!token)
1740         return -EINVAL;
1741     if (kstrtou16(token, 0, &ps_poll_num))
1742         return -EINVAL;
1743 
1744     token = strsep(&sptr, " ");
1745     if (!token)
1746         return -EINVAL;
1747     if (kstrtou16(token, 0, &dtim))
1748         return -EINVAL;
1749 
1750     token = strsep(&sptr, " ");
1751     if (!token)
1752         return -EINVAL;
1753     if (kstrtou16(token, 0, &tx_wakeup))
1754         return -EINVAL;
1755 
1756     token = strsep(&sptr, " ");
1757     if (!token)
1758         return -EINVAL;
1759     if (kstrtou16(token, 0, &num_tx))
1760         return -EINVAL;
1761 
1762     ath6kl_wmi_pmparams_cmd(ar->wmi, 0, idle_period, ps_poll_num,
1763                 dtim, tx_wakeup, num_tx, 0);
1764 
1765     return count;
1766 }
1767 
1768 static const struct file_operations fops_power_params = {
1769     .write = ath6kl_power_params_write,
1770     .open = simple_open,
1771     .owner = THIS_MODULE,
1772     .llseek = default_llseek,
1773 };
1774 
1775 void ath6kl_debug_init(struct ath6kl *ar)
1776 {
1777     skb_queue_head_init(&ar->debug.fwlog_queue);
1778     init_completion(&ar->debug.fwlog_completion);
1779 
1780     /*
1781      * Actually we are lying here but don't know how to read the mask
1782      * value from the firmware.
1783      */
1784     ar->debug.fwlog_mask = 0;
1785 }
1786 
1787 /*
1788  * Initialisation needs to happen in two stages as fwlog events can come
1789  * before cfg80211 is initialised, and debugfs depends on cfg80211
1790  * initialisation.
1791  */
1792 int ath6kl_debug_init_fs(struct ath6kl *ar)
1793 {
1794     ar->debugfs_phy = debugfs_create_dir("ath6kl",
1795                          ar->wiphy->debugfsdir);
1796     if (!ar->debugfs_phy)
1797         return -ENOMEM;
1798 
1799     debugfs_create_file("tgt_stats", 0400, ar->debugfs_phy, ar,
1800                 &fops_tgt_stats);
1801 
1802     if (ar->hif_type == ATH6KL_HIF_TYPE_SDIO)
1803         debugfs_create_file("credit_dist_stats", 0400,
1804                     ar->debugfs_phy, ar,
1805                     &fops_credit_dist_stats);
1806 
1807     debugfs_create_file("endpoint_stats", 0600,
1808                 ar->debugfs_phy, ar, &fops_endpoint_stats);
1809 
1810     debugfs_create_file("fwlog", 0400, ar->debugfs_phy, ar, &fops_fwlog);
1811 
1812     debugfs_create_file("fwlog_block", 0400, ar->debugfs_phy, ar,
1813                 &fops_fwlog_block);
1814 
1815     debugfs_create_file("fwlog_mask", 0600, ar->debugfs_phy,
1816                 ar, &fops_fwlog_mask);
1817 
1818     debugfs_create_file("reg_addr", 0600, ar->debugfs_phy, ar,
1819                 &fops_diag_reg_read);
1820 
1821     debugfs_create_file("reg_dump", 0400, ar->debugfs_phy, ar,
1822                 &fops_reg_dump);
1823 
1824     debugfs_create_file("lrssi_roam_threshold", 0600,
1825                 ar->debugfs_phy, ar, &fops_lrssi_roam_threshold);
1826 
1827     debugfs_create_file("reg_write", 0600,
1828                 ar->debugfs_phy, ar, &fops_diag_reg_write);
1829 
1830     debugfs_create_file("war_stats", 0400, ar->debugfs_phy, ar,
1831                 &fops_war_stats);
1832 
1833     debugfs_create_file("roam_table", 0400, ar->debugfs_phy, ar,
1834                 &fops_roam_table);
1835 
1836     debugfs_create_file("force_roam", 0200, ar->debugfs_phy, ar,
1837                 &fops_force_roam);
1838 
1839     debugfs_create_file("roam_mode", 0200, ar->debugfs_phy, ar,
1840                 &fops_roam_mode);
1841 
1842     debugfs_create_file("keepalive", 0600, ar->debugfs_phy, ar,
1843                 &fops_keepalive);
1844 
1845     debugfs_create_file("disconnect_timeout", 0600,
1846                 ar->debugfs_phy, ar, &fops_disconnect_timeout);
1847 
1848     debugfs_create_file("create_qos", 0200, ar->debugfs_phy, ar,
1849                 &fops_create_qos);
1850 
1851     debugfs_create_file("delete_qos", 0200, ar->debugfs_phy, ar,
1852                 &fops_delete_qos);
1853 
1854     debugfs_create_file("bgscan_interval", 0200,
1855                 ar->debugfs_phy, ar, &fops_bgscan_int);
1856 
1857     debugfs_create_file("listen_interval", 0600,
1858                 ar->debugfs_phy, ar, &fops_listen_int);
1859 
1860     debugfs_create_file("power_params", 0200, ar->debugfs_phy, ar,
1861                 &fops_power_params);
1862 
1863     return 0;
1864 }
1865 
1866 void ath6kl_debug_cleanup(struct ath6kl *ar)
1867 {
1868     skb_queue_purge(&ar->debug.fwlog_queue);
1869     complete(&ar->debug.fwlog_completion);
1870     kfree(ar->debug.roam_tbl);
1871 }
1872 
1873 #endif