cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

debug.c (46478B)


      1/*
      2 * Copyright (c) 2004-2011 Atheros Communications Inc.
      3 * Copyright (c) 2011-2012 Qualcomm Atheros, Inc.
      4 *
      5 * Permission to use, copy, modify, and/or distribute this software for any
      6 * purpose with or without fee is hereby granted, provided that the above
      7 * copyright notice and this permission notice appear in all copies.
      8 *
      9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     16 */
     17
     18#include "core.h"
     19
     20#include <linux/skbuff.h>
     21#include <linux/fs.h>
     22#include <linux/vmalloc.h>
     23#include <linux/export.h>
     24
     25#include "debug.h"
     26#include "target.h"
     27
     28struct ath6kl_fwlog_slot {
     29	__le32 timestamp;
     30	__le32 length;
     31
     32	/* max ATH6KL_FWLOG_PAYLOAD_SIZE bytes */
     33	u8 payload[];
     34};
     35
     36#define ATH6KL_FWLOG_MAX_ENTRIES 20
     37
     38#define ATH6KL_FWLOG_VALID_MASK 0x1ffff
     39
     40void ath6kl_printk(const char *level, const char *fmt, ...)
     41{
     42	struct va_format vaf;
     43	va_list args;
     44
     45	va_start(args, fmt);
     46
     47	vaf.fmt = fmt;
     48	vaf.va = &args;
     49
     50	printk("%sath6kl: %pV", level, &vaf);
     51
     52	va_end(args);
     53}
     54EXPORT_SYMBOL(ath6kl_printk);
     55
     56void ath6kl_info(const char *fmt, ...)
     57{
     58	struct va_format vaf = {
     59		.fmt = fmt,
     60	};
     61	va_list args;
     62
     63	va_start(args, fmt);
     64	vaf.va = &args;
     65	ath6kl_printk(KERN_INFO, "%pV", &vaf);
     66	trace_ath6kl_log_info(&vaf);
     67	va_end(args);
     68}
     69EXPORT_SYMBOL(ath6kl_info);
     70
     71void ath6kl_err(const char *fmt, ...)
     72{
     73	struct va_format vaf = {
     74		.fmt = fmt,
     75	};
     76	va_list args;
     77
     78	va_start(args, fmt);
     79	vaf.va = &args;
     80	ath6kl_printk(KERN_ERR, "%pV", &vaf);
     81	trace_ath6kl_log_err(&vaf);
     82	va_end(args);
     83}
     84EXPORT_SYMBOL(ath6kl_err);
     85
     86void ath6kl_warn(const char *fmt, ...)
     87{
     88	struct va_format vaf = {
     89		.fmt = fmt,
     90	};
     91	va_list args;
     92
     93	va_start(args, fmt);
     94	vaf.va = &args;
     95	ath6kl_printk(KERN_WARNING, "%pV", &vaf);
     96	trace_ath6kl_log_warn(&vaf);
     97	va_end(args);
     98}
     99EXPORT_SYMBOL(ath6kl_warn);
    100
    101int ath6kl_read_tgt_stats(struct ath6kl *ar, struct ath6kl_vif *vif)
    102{
    103	long left;
    104
    105	if (down_interruptible(&ar->sem))
    106		return -EBUSY;
    107
    108	set_bit(STATS_UPDATE_PEND, &vif->flags);
    109
    110	if (ath6kl_wmi_get_stats_cmd(ar->wmi, 0)) {
    111		up(&ar->sem);
    112		return -EIO;
    113	}
    114
    115	left = wait_event_interruptible_timeout(ar->event_wq,
    116						!test_bit(STATS_UPDATE_PEND,
    117						&vif->flags), WMI_TIMEOUT);
    118
    119	up(&ar->sem);
    120
    121	if (left <= 0)
    122		return -ETIMEDOUT;
    123
    124	return 0;
    125}
    126EXPORT_SYMBOL(ath6kl_read_tgt_stats);
    127
    128#ifdef CONFIG_ATH6KL_DEBUG
    129
    130void ath6kl_dbg(enum ATH6K_DEBUG_MASK mask, const char *fmt, ...)
    131{
    132	struct va_format vaf;
    133	va_list args;
    134
    135	va_start(args, fmt);
    136
    137	vaf.fmt = fmt;
    138	vaf.va = &args;
    139
    140	if (debug_mask & mask)
    141		ath6kl_printk(KERN_DEBUG, "%pV", &vaf);
    142
    143	trace_ath6kl_log_dbg(mask, &vaf);
    144
    145	va_end(args);
    146}
    147EXPORT_SYMBOL(ath6kl_dbg);
    148
    149void ath6kl_dbg_dump(enum ATH6K_DEBUG_MASK mask,
    150		     const char *msg, const char *prefix,
    151		     const void *buf, size_t len)
    152{
    153	if (debug_mask & mask) {
    154		if (msg)
    155			ath6kl_dbg(mask, "%s\n", msg);
    156
    157		print_hex_dump_bytes(prefix, DUMP_PREFIX_OFFSET, buf, len);
    158	}
    159
    160	/* tracing code doesn't like null strings :/ */
    161	trace_ath6kl_log_dbg_dump(msg ? msg : "", prefix ? prefix : "",
    162				  buf, len);
    163}
    164EXPORT_SYMBOL(ath6kl_dbg_dump);
    165
    166#define REG_OUTPUT_LEN_PER_LINE	25
    167#define REGTYPE_STR_LEN		100
    168
    169struct ath6kl_diag_reg_info {
    170	u32 reg_start;
    171	u32 reg_end;
    172	const char *reg_info;
    173};
    174
    175static const struct ath6kl_diag_reg_info diag_reg[] = {
    176	{ 0x20000, 0x200fc, "General DMA and Rx registers" },
    177	{ 0x28000, 0x28900, "MAC PCU register & keycache" },
    178	{ 0x20800, 0x20a40, "QCU" },
    179	{ 0x21000, 0x212f0, "DCU" },
    180	{ 0x4000,  0x42e4, "RTC" },
    181	{ 0x540000, 0x540000 + (256 * 1024), "RAM" },
    182	{ 0x29800, 0x2B210, "Base Band" },
    183	{ 0x1C000, 0x1C748, "Analog" },
    184};
    185
    186void ath6kl_dump_registers(struct ath6kl_device *dev,
    187			   struct ath6kl_irq_proc_registers *irq_proc_reg,
    188			   struct ath6kl_irq_enable_reg *irq_enable_reg)
    189{
    190	ath6kl_dbg(ATH6KL_DBG_IRQ, ("<------- Register Table -------->\n"));
    191
    192	if (irq_proc_reg != NULL) {
    193		ath6kl_dbg(ATH6KL_DBG_IRQ,
    194			   "Host Int status:           0x%x\n",
    195			   irq_proc_reg->host_int_status);
    196		ath6kl_dbg(ATH6KL_DBG_IRQ,
    197			   "CPU Int status:            0x%x\n",
    198			   irq_proc_reg->cpu_int_status);
    199		ath6kl_dbg(ATH6KL_DBG_IRQ,
    200			   "Error Int status:          0x%x\n",
    201			   irq_proc_reg->error_int_status);
    202		ath6kl_dbg(ATH6KL_DBG_IRQ,
    203			   "Counter Int status:        0x%x\n",
    204			   irq_proc_reg->counter_int_status);
    205		ath6kl_dbg(ATH6KL_DBG_IRQ,
    206			   "Mbox Frame:                0x%x\n",
    207			   irq_proc_reg->mbox_frame);
    208		ath6kl_dbg(ATH6KL_DBG_IRQ,
    209			   "Rx Lookahead Valid:        0x%x\n",
    210			   irq_proc_reg->rx_lkahd_valid);
    211		ath6kl_dbg(ATH6KL_DBG_IRQ,
    212			   "Rx Lookahead 0:            0x%x\n",
    213			   irq_proc_reg->rx_lkahd[0]);
    214		ath6kl_dbg(ATH6KL_DBG_IRQ,
    215			   "Rx Lookahead 1:            0x%x\n",
    216			   irq_proc_reg->rx_lkahd[1]);
    217
    218		if (dev->ar->mbox_info.gmbox_addr != 0) {
    219			/*
    220			 * If the target supports GMBOX hardware, dump some
    221			 * additional state.
    222			 */
    223			ath6kl_dbg(ATH6KL_DBG_IRQ,
    224				   "GMBOX Host Int status 2:   0x%x\n",
    225				   irq_proc_reg->host_int_status2);
    226			ath6kl_dbg(ATH6KL_DBG_IRQ,
    227				   "GMBOX RX Avail:            0x%x\n",
    228				   irq_proc_reg->gmbox_rx_avail);
    229			ath6kl_dbg(ATH6KL_DBG_IRQ,
    230				   "GMBOX lookahead alias 0:   0x%x\n",
    231				   irq_proc_reg->rx_gmbox_lkahd_alias[0]);
    232			ath6kl_dbg(ATH6KL_DBG_IRQ,
    233				   "GMBOX lookahead alias 1:   0x%x\n",
    234				   irq_proc_reg->rx_gmbox_lkahd_alias[1]);
    235		}
    236	}
    237
    238	if (irq_enable_reg != NULL) {
    239		ath6kl_dbg(ATH6KL_DBG_IRQ,
    240			   "Int status Enable:         0x%x\n",
    241			   irq_enable_reg->int_status_en);
    242		ath6kl_dbg(ATH6KL_DBG_IRQ, "Counter Int status Enable: 0x%x\n",
    243			   irq_enable_reg->cntr_int_status_en);
    244	}
    245	ath6kl_dbg(ATH6KL_DBG_IRQ, "<------------------------------->\n");
    246}
    247
    248static void dump_cred_dist(struct htc_endpoint_credit_dist *ep_dist)
    249{
    250	ath6kl_dbg(ATH6KL_DBG_CREDIT,
    251		   "--- endpoint: %d  svc_id: 0x%X ---\n",
    252		   ep_dist->endpoint, ep_dist->svc_id);
    253	ath6kl_dbg(ATH6KL_DBG_CREDIT, " dist_flags     : 0x%X\n",
    254		   ep_dist->dist_flags);
    255	ath6kl_dbg(ATH6KL_DBG_CREDIT, " cred_norm      : %d\n",
    256		   ep_dist->cred_norm);
    257	ath6kl_dbg(ATH6KL_DBG_CREDIT, " cred_min       : %d\n",
    258		   ep_dist->cred_min);
    259	ath6kl_dbg(ATH6KL_DBG_CREDIT, " credits        : %d\n",
    260		   ep_dist->credits);
    261	ath6kl_dbg(ATH6KL_DBG_CREDIT, " cred_assngd    : %d\n",
    262		   ep_dist->cred_assngd);
    263	ath6kl_dbg(ATH6KL_DBG_CREDIT, " seek_cred      : %d\n",
    264		   ep_dist->seek_cred);
    265	ath6kl_dbg(ATH6KL_DBG_CREDIT, " cred_sz        : %d\n",
    266		   ep_dist->cred_sz);
    267	ath6kl_dbg(ATH6KL_DBG_CREDIT, " cred_per_msg   : %d\n",
    268		   ep_dist->cred_per_msg);
    269	ath6kl_dbg(ATH6KL_DBG_CREDIT, " cred_to_dist   : %d\n",
    270		   ep_dist->cred_to_dist);
    271	ath6kl_dbg(ATH6KL_DBG_CREDIT, " txq_depth      : %d\n",
    272		   get_queue_depth(&ep_dist->htc_ep->txq));
    273	ath6kl_dbg(ATH6KL_DBG_CREDIT,
    274		   "----------------------------------\n");
    275}
    276
    277/* FIXME: move to htc.c */
    278void dump_cred_dist_stats(struct htc_target *target)
    279{
    280	struct htc_endpoint_credit_dist *ep_list;
    281
    282	list_for_each_entry(ep_list, &target->cred_dist_list, list)
    283		dump_cred_dist(ep_list);
    284
    285	ath6kl_dbg(ATH6KL_DBG_CREDIT,
    286		   "credit distribution total %d free %d\n",
    287		   target->credit_info->total_avail_credits,
    288		   target->credit_info->cur_free_credits);
    289}
    290
    291void ath6kl_debug_war(struct ath6kl *ar, enum ath6kl_war war)
    292{
    293	switch (war) {
    294	case ATH6KL_WAR_INVALID_RATE:
    295		ar->debug.war_stats.invalid_rate++;
    296		break;
    297	}
    298}
    299
    300static ssize_t read_file_war_stats(struct file *file, char __user *user_buf,
    301				   size_t count, loff_t *ppos)
    302{
    303	struct ath6kl *ar = file->private_data;
    304	char *buf;
    305	unsigned int len = 0, buf_len = 1500;
    306	ssize_t ret_cnt;
    307
    308	buf = kzalloc(buf_len, GFP_KERNEL);
    309	if (!buf)
    310		return -ENOMEM;
    311
    312	len += scnprintf(buf + len, buf_len - len, "\n");
    313	len += scnprintf(buf + len, buf_len - len, "%25s\n",
    314			 "Workaround stats");
    315	len += scnprintf(buf + len, buf_len - len, "%25s\n\n",
    316			 "=================");
    317	len += scnprintf(buf + len, buf_len - len, "%20s %10u\n",
    318			 "Invalid rates", ar->debug.war_stats.invalid_rate);
    319
    320	if (WARN_ON(len > buf_len))
    321		len = buf_len;
    322
    323	ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
    324
    325	kfree(buf);
    326	return ret_cnt;
    327}
    328
    329static const struct file_operations fops_war_stats = {
    330	.read = read_file_war_stats,
    331	.open = simple_open,
    332	.owner = THIS_MODULE,
    333	.llseek = default_llseek,
    334};
    335
    336void ath6kl_debug_fwlog_event(struct ath6kl *ar, const void *buf, size_t len)
    337{
    338	struct ath6kl_fwlog_slot *slot;
    339	struct sk_buff *skb;
    340	size_t slot_len;
    341
    342	if (WARN_ON(len > ATH6KL_FWLOG_PAYLOAD_SIZE))
    343		return;
    344
    345	slot_len = sizeof(*slot) + ATH6KL_FWLOG_PAYLOAD_SIZE;
    346
    347	skb = alloc_skb(slot_len, GFP_KERNEL);
    348	if (!skb)
    349		return;
    350
    351	slot = skb_put(skb, slot_len);
    352	slot->timestamp = cpu_to_le32(jiffies);
    353	slot->length = cpu_to_le32(len);
    354	memcpy(slot->payload, buf, len);
    355
    356	/* Need to pad each record to fixed length ATH6KL_FWLOG_PAYLOAD_SIZE */
    357	memset(slot->payload + len, 0, ATH6KL_FWLOG_PAYLOAD_SIZE - len);
    358
    359	spin_lock(&ar->debug.fwlog_queue.lock);
    360
    361	__skb_queue_tail(&ar->debug.fwlog_queue, skb);
    362	complete(&ar->debug.fwlog_completion);
    363
    364	/* drop oldest entries */
    365	while (skb_queue_len(&ar->debug.fwlog_queue) >
    366	       ATH6KL_FWLOG_MAX_ENTRIES) {
    367		skb = __skb_dequeue(&ar->debug.fwlog_queue);
    368		kfree_skb(skb);
    369	}
    370
    371	spin_unlock(&ar->debug.fwlog_queue.lock);
    372
    373	return;
    374}
    375
    376static int ath6kl_fwlog_open(struct inode *inode, struct file *file)
    377{
    378	struct ath6kl *ar = inode->i_private;
    379
    380	if (ar->debug.fwlog_open)
    381		return -EBUSY;
    382
    383	ar->debug.fwlog_open = true;
    384
    385	file->private_data = inode->i_private;
    386	return 0;
    387}
    388
    389static int ath6kl_fwlog_release(struct inode *inode, struct file *file)
    390{
    391	struct ath6kl *ar = inode->i_private;
    392
    393	ar->debug.fwlog_open = false;
    394
    395	return 0;
    396}
    397
    398static ssize_t ath6kl_fwlog_read(struct file *file, char __user *user_buf,
    399				 size_t count, loff_t *ppos)
    400{
    401	struct ath6kl *ar = file->private_data;
    402	struct sk_buff *skb;
    403	ssize_t ret_cnt;
    404	size_t len = 0;
    405	char *buf;
    406
    407	buf = vmalloc(count);
    408	if (!buf)
    409		return -ENOMEM;
    410
    411	/* read undelivered logs from firmware */
    412	ath6kl_read_fwlogs(ar);
    413
    414	spin_lock(&ar->debug.fwlog_queue.lock);
    415
    416	while ((skb = __skb_dequeue(&ar->debug.fwlog_queue))) {
    417		if (skb->len > count - len) {
    418			/* not enough space, put skb back and leave */
    419			__skb_queue_head(&ar->debug.fwlog_queue, skb);
    420			break;
    421		}
    422
    423
    424		memcpy(buf + len, skb->data, skb->len);
    425		len += skb->len;
    426
    427		kfree_skb(skb);
    428	}
    429
    430	spin_unlock(&ar->debug.fwlog_queue.lock);
    431
    432	/* FIXME: what to do if len == 0? */
    433
    434	ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
    435
    436	vfree(buf);
    437
    438	return ret_cnt;
    439}
    440
    441static const struct file_operations fops_fwlog = {
    442	.open = ath6kl_fwlog_open,
    443	.release = ath6kl_fwlog_release,
    444	.read = ath6kl_fwlog_read,
    445	.owner = THIS_MODULE,
    446	.llseek = default_llseek,
    447};
    448
    449static ssize_t ath6kl_fwlog_block_read(struct file *file,
    450				       char __user *user_buf,
    451				       size_t count,
    452				       loff_t *ppos)
    453{
    454	struct ath6kl *ar = file->private_data;
    455	struct sk_buff *skb;
    456	ssize_t ret_cnt;
    457	size_t len = 0, not_copied;
    458	char *buf;
    459	int ret;
    460
    461	buf = vmalloc(count);
    462	if (!buf)
    463		return -ENOMEM;
    464
    465	spin_lock(&ar->debug.fwlog_queue.lock);
    466
    467	if (skb_queue_len(&ar->debug.fwlog_queue) == 0) {
    468		/* we must init under queue lock */
    469		init_completion(&ar->debug.fwlog_completion);
    470
    471		spin_unlock(&ar->debug.fwlog_queue.lock);
    472
    473		ret = wait_for_completion_interruptible(
    474			&ar->debug.fwlog_completion);
    475		if (ret == -ERESTARTSYS) {
    476			vfree(buf);
    477			return ret;
    478		}
    479
    480		spin_lock(&ar->debug.fwlog_queue.lock);
    481	}
    482
    483	while ((skb = __skb_dequeue(&ar->debug.fwlog_queue))) {
    484		if (skb->len > count - len) {
    485			/* not enough space, put skb back and leave */
    486			__skb_queue_head(&ar->debug.fwlog_queue, skb);
    487			break;
    488		}
    489
    490
    491		memcpy(buf + len, skb->data, skb->len);
    492		len += skb->len;
    493
    494		kfree_skb(skb);
    495	}
    496
    497	spin_unlock(&ar->debug.fwlog_queue.lock);
    498
    499	/* FIXME: what to do if len == 0? */
    500
    501	not_copied = copy_to_user(user_buf, buf, len);
    502	if (not_copied != 0) {
    503		ret_cnt = -EFAULT;
    504		goto out;
    505	}
    506
    507	*ppos = *ppos + len;
    508
    509	ret_cnt = len;
    510
    511out:
    512	vfree(buf);
    513
    514	return ret_cnt;
    515}
    516
    517static const struct file_operations fops_fwlog_block = {
    518	.open = ath6kl_fwlog_open,
    519	.release = ath6kl_fwlog_release,
    520	.read = ath6kl_fwlog_block_read,
    521	.owner = THIS_MODULE,
    522	.llseek = default_llseek,
    523};
    524
    525static ssize_t ath6kl_fwlog_mask_read(struct file *file, char __user *user_buf,
    526				      size_t count, loff_t *ppos)
    527{
    528	struct ath6kl *ar = file->private_data;
    529	char buf[16];
    530	int len;
    531
    532	len = snprintf(buf, sizeof(buf), "0x%x\n", ar->debug.fwlog_mask);
    533
    534	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
    535}
    536
    537static ssize_t ath6kl_fwlog_mask_write(struct file *file,
    538				       const char __user *user_buf,
    539				       size_t count, loff_t *ppos)
    540{
    541	struct ath6kl *ar = file->private_data;
    542	int ret;
    543
    544	ret = kstrtou32_from_user(user_buf, count, 0, &ar->debug.fwlog_mask);
    545	if (ret)
    546		return ret;
    547
    548	ret = ath6kl_wmi_config_debug_module_cmd(ar->wmi,
    549						 ATH6KL_FWLOG_VALID_MASK,
    550						 ar->debug.fwlog_mask);
    551	if (ret)
    552		return ret;
    553
    554	return count;
    555}
    556
    557static const struct file_operations fops_fwlog_mask = {
    558	.open = simple_open,
    559	.read = ath6kl_fwlog_mask_read,
    560	.write = ath6kl_fwlog_mask_write,
    561	.owner = THIS_MODULE,
    562	.llseek = default_llseek,
    563};
    564
    565static ssize_t read_file_tgt_stats(struct file *file, char __user *user_buf,
    566				   size_t count, loff_t *ppos)
    567{
    568	struct ath6kl *ar = file->private_data;
    569	struct ath6kl_vif *vif;
    570	struct target_stats *tgt_stats;
    571	char *buf;
    572	unsigned int len = 0, buf_len = 1500;
    573	int i;
    574	ssize_t ret_cnt;
    575	int rv;
    576
    577	vif = ath6kl_vif_first(ar);
    578	if (!vif)
    579		return -EIO;
    580
    581	buf = kzalloc(buf_len, GFP_KERNEL);
    582	if (!buf)
    583		return -ENOMEM;
    584
    585	rv = ath6kl_read_tgt_stats(ar, vif);
    586	if (rv < 0) {
    587		kfree(buf);
    588		return rv;
    589	}
    590
    591	tgt_stats = &vif->target_stats;
    592
    593	len += scnprintf(buf + len, buf_len - len, "\n");
    594	len += scnprintf(buf + len, buf_len - len, "%25s\n",
    595			 "Target Tx stats");
    596	len += scnprintf(buf + len, buf_len - len, "%25s\n\n",
    597			 "=================");
    598	len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
    599			 "Ucast packets", tgt_stats->tx_ucast_pkt);
    600	len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
    601			 "Bcast packets", tgt_stats->tx_bcast_pkt);
    602	len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
    603			 "Ucast byte", tgt_stats->tx_ucast_byte);
    604	len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
    605			 "Bcast byte", tgt_stats->tx_bcast_byte);
    606	len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
    607			 "Rts success cnt", tgt_stats->tx_rts_success_cnt);
    608	for (i = 0; i < 4; i++)
    609		len += scnprintf(buf + len, buf_len - len,
    610				 "%18s %d %10llu\n", "PER on ac",
    611				 i, tgt_stats->tx_pkt_per_ac[i]);
    612	len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
    613			 "Error", tgt_stats->tx_err);
    614	len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
    615			 "Fail count", tgt_stats->tx_fail_cnt);
    616	len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
    617			 "Retry count", tgt_stats->tx_retry_cnt);
    618	len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
    619			 "Multi retry cnt", tgt_stats->tx_mult_retry_cnt);
    620	len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
    621			 "Rts fail cnt", tgt_stats->tx_rts_fail_cnt);
    622	len += scnprintf(buf + len, buf_len - len, "%25s %10llu\n\n",
    623			 "TKIP counter measure used",
    624			 tgt_stats->tkip_cnter_measures_invoked);
    625
    626	len += scnprintf(buf + len, buf_len - len, "%25s\n",
    627			 "Target Rx stats");
    628	len += scnprintf(buf + len, buf_len - len, "%25s\n",
    629			 "=================");
    630
    631	len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
    632			 "Ucast packets", tgt_stats->rx_ucast_pkt);
    633	len += scnprintf(buf + len, buf_len - len, "%20s %10d\n",
    634			 "Ucast Rate", tgt_stats->rx_ucast_rate);
    635	len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
    636			 "Bcast packets", tgt_stats->rx_bcast_pkt);
    637	len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
    638			 "Ucast byte", tgt_stats->rx_ucast_byte);
    639	len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
    640			 "Bcast byte", tgt_stats->rx_bcast_byte);
    641	len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
    642			 "Fragmented pkt", tgt_stats->rx_frgment_pkt);
    643	len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
    644			 "Error", tgt_stats->rx_err);
    645	len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
    646			 "CRC Err", tgt_stats->rx_crc_err);
    647	len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
    648			 "Key cache miss", tgt_stats->rx_key_cache_miss);
    649	len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
    650			 "Decrypt Err", tgt_stats->rx_decrypt_err);
    651	len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
    652			 "Duplicate frame", tgt_stats->rx_dupl_frame);
    653	len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
    654			 "Tkip Mic failure", tgt_stats->tkip_local_mic_fail);
    655	len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
    656			 "TKIP format err", tgt_stats->tkip_fmt_err);
    657	len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
    658			 "CCMP format Err", tgt_stats->ccmp_fmt_err);
    659	len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n\n",
    660			 "CCMP Replay Err", tgt_stats->ccmp_replays);
    661
    662	len += scnprintf(buf + len, buf_len - len, "%25s\n",
    663			 "Misc Target stats");
    664	len += scnprintf(buf + len, buf_len - len, "%25s\n",
    665			 "=================");
    666	len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
    667			 "Beacon Miss count", tgt_stats->cs_bmiss_cnt);
    668	len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
    669			 "Num Connects", tgt_stats->cs_connect_cnt);
    670	len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
    671			 "Num disconnects", tgt_stats->cs_discon_cnt);
    672	len += scnprintf(buf + len, buf_len - len, "%20s %10d\n",
    673			 "Beacon avg rssi", tgt_stats->cs_ave_beacon_rssi);
    674	len += scnprintf(buf + len, buf_len - len, "%20s %10d\n",
    675			 "ARP pkt received", tgt_stats->arp_received);
    676	len += scnprintf(buf + len, buf_len - len, "%20s %10d\n",
    677			 "ARP pkt matched", tgt_stats->arp_matched);
    678	len += scnprintf(buf + len, buf_len - len, "%20s %10d\n",
    679			 "ARP pkt replied", tgt_stats->arp_replied);
    680
    681	if (len > buf_len)
    682		len = buf_len;
    683
    684	ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
    685
    686	kfree(buf);
    687	return ret_cnt;
    688}
    689
    690static const struct file_operations fops_tgt_stats = {
    691	.read = read_file_tgt_stats,
    692	.open = simple_open,
    693	.owner = THIS_MODULE,
    694	.llseek = default_llseek,
    695};
    696
    697#define print_credit_info(fmt_str, ep_list_field)		\
    698	(len += scnprintf(buf + len, buf_len - len, fmt_str,	\
    699			 ep_list->ep_list_field))
    700#define CREDIT_INFO_DISPLAY_STRING_LEN	200
    701#define CREDIT_INFO_LEN	128
    702
    703static ssize_t read_file_credit_dist_stats(struct file *file,
    704					   char __user *user_buf,
    705					   size_t count, loff_t *ppos)
    706{
    707	struct ath6kl *ar = file->private_data;
    708	struct htc_target *target = ar->htc_target;
    709	struct htc_endpoint_credit_dist *ep_list;
    710	char *buf;
    711	unsigned int buf_len, len = 0;
    712	ssize_t ret_cnt;
    713
    714	buf_len = CREDIT_INFO_DISPLAY_STRING_LEN +
    715		  get_queue_depth(&target->cred_dist_list) * CREDIT_INFO_LEN;
    716	buf = kzalloc(buf_len, GFP_KERNEL);
    717	if (!buf)
    718		return -ENOMEM;
    719
    720	len += scnprintf(buf + len, buf_len - len, "%25s%5d\n",
    721			 "Total Avail Credits: ",
    722			 target->credit_info->total_avail_credits);
    723	len += scnprintf(buf + len, buf_len - len, "%25s%5d\n",
    724			 "Free credits :",
    725			 target->credit_info->cur_free_credits);
    726
    727	len += scnprintf(buf + len, buf_len - len,
    728			 " Epid  Flags    Cred_norm  Cred_min  Credits  Cred_assngd"
    729			 "  Seek_cred  Cred_sz  Cred_per_msg  Cred_to_dist"
    730			 "  qdepth\n");
    731
    732	list_for_each_entry(ep_list, &target->cred_dist_list, list) {
    733		print_credit_info("  %2d", endpoint);
    734		print_credit_info("%10x", dist_flags);
    735		print_credit_info("%8d", cred_norm);
    736		print_credit_info("%9d", cred_min);
    737		print_credit_info("%9d", credits);
    738		print_credit_info("%10d", cred_assngd);
    739		print_credit_info("%13d", seek_cred);
    740		print_credit_info("%12d", cred_sz);
    741		print_credit_info("%9d", cred_per_msg);
    742		print_credit_info("%14d", cred_to_dist);
    743		len += scnprintf(buf + len, buf_len - len, "%12d\n",
    744				 get_queue_depth(&ep_list->htc_ep->txq));
    745	}
    746
    747	if (len > buf_len)
    748		len = buf_len;
    749
    750	ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
    751	kfree(buf);
    752	return ret_cnt;
    753}
    754
    755static const struct file_operations fops_credit_dist_stats = {
    756	.read = read_file_credit_dist_stats,
    757	.open = simple_open,
    758	.owner = THIS_MODULE,
    759	.llseek = default_llseek,
    760};
    761
    762static unsigned int print_endpoint_stat(struct htc_target *target, char *buf,
    763					unsigned int buf_len, unsigned int len,
    764					int offset, const char *name)
    765{
    766	int i;
    767	struct htc_endpoint_stats *ep_st;
    768	u32 *counter;
    769
    770	len += scnprintf(buf + len, buf_len - len, "%s:", name);
    771	for (i = 0; i < ENDPOINT_MAX; i++) {
    772		ep_st = &target->endpoint[i].ep_st;
    773		counter = ((u32 *) ep_st) + (offset / 4);
    774		len += scnprintf(buf + len, buf_len - len, " %u", *counter);
    775	}
    776	len += scnprintf(buf + len, buf_len - len, "\n");
    777
    778	return len;
    779}
    780
    781static ssize_t ath6kl_endpoint_stats_read(struct file *file,
    782					  char __user *user_buf,
    783					  size_t count, loff_t *ppos)
    784{
    785	struct ath6kl *ar = file->private_data;
    786	struct htc_target *target = ar->htc_target;
    787	char *buf;
    788	unsigned int buf_len, len = 0;
    789	ssize_t ret_cnt;
    790
    791	buf_len = sizeof(struct htc_endpoint_stats) / sizeof(u32) *
    792		(25 + ENDPOINT_MAX * 11);
    793	buf = kmalloc(buf_len, GFP_KERNEL);
    794	if (!buf)
    795		return -ENOMEM;
    796
    797#define EPSTAT(name)							\
    798	do {								\
    799		len = print_endpoint_stat(target, buf, buf_len, len,	\
    800					  offsetof(struct htc_endpoint_stats, \
    801						   name),		\
    802					  #name);			\
    803	} while (0)
    804
    805	EPSTAT(cred_low_indicate);
    806	EPSTAT(tx_issued);
    807	EPSTAT(tx_pkt_bundled);
    808	EPSTAT(tx_bundles);
    809	EPSTAT(tx_dropped);
    810	EPSTAT(tx_cred_rpt);
    811	EPSTAT(cred_rpt_from_rx);
    812	EPSTAT(cred_rpt_from_other);
    813	EPSTAT(cred_rpt_ep0);
    814	EPSTAT(cred_from_rx);
    815	EPSTAT(cred_from_other);
    816	EPSTAT(cred_from_ep0);
    817	EPSTAT(cred_cosumd);
    818	EPSTAT(cred_retnd);
    819	EPSTAT(rx_pkts);
    820	EPSTAT(rx_lkahds);
    821	EPSTAT(rx_bundl);
    822	EPSTAT(rx_bundle_lkahd);
    823	EPSTAT(rx_bundle_from_hdr);
    824	EPSTAT(rx_alloc_thresh_hit);
    825	EPSTAT(rxalloc_thresh_byte);
    826#undef EPSTAT
    827
    828	if (len > buf_len)
    829		len = buf_len;
    830
    831	ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
    832	kfree(buf);
    833	return ret_cnt;
    834}
    835
    836static ssize_t ath6kl_endpoint_stats_write(struct file *file,
    837					   const char __user *user_buf,
    838					   size_t count, loff_t *ppos)
    839{
    840	struct ath6kl *ar = file->private_data;
    841	struct htc_target *target = ar->htc_target;
    842	int ret, i;
    843	u32 val;
    844	struct htc_endpoint_stats *ep_st;
    845
    846	ret = kstrtou32_from_user(user_buf, count, 0, &val);
    847	if (ret)
    848		return ret;
    849	if (val == 0) {
    850		for (i = 0; i < ENDPOINT_MAX; i++) {
    851			ep_st = &target->endpoint[i].ep_st;
    852			memset(ep_st, 0, sizeof(*ep_st));
    853		}
    854	}
    855
    856	return count;
    857}
    858
    859static const struct file_operations fops_endpoint_stats = {
    860	.open = simple_open,
    861	.read = ath6kl_endpoint_stats_read,
    862	.write = ath6kl_endpoint_stats_write,
    863	.owner = THIS_MODULE,
    864	.llseek = default_llseek,
    865};
    866
    867static unsigned long ath6kl_get_num_reg(void)
    868{
    869	int i;
    870	unsigned long n_reg = 0;
    871
    872	for (i = 0; i < ARRAY_SIZE(diag_reg); i++)
    873		n_reg = n_reg +
    874		     (diag_reg[i].reg_end - diag_reg[i].reg_start) / 4 + 1;
    875
    876	return n_reg;
    877}
    878
    879static bool ath6kl_dbg_is_diag_reg_valid(u32 reg_addr)
    880{
    881	int i;
    882
    883	for (i = 0; i < ARRAY_SIZE(diag_reg); i++) {
    884		if (reg_addr >= diag_reg[i].reg_start &&
    885		    reg_addr <= diag_reg[i].reg_end)
    886			return true;
    887	}
    888
    889	return false;
    890}
    891
    892static ssize_t ath6kl_regread_read(struct file *file, char __user *user_buf,
    893				    size_t count, loff_t *ppos)
    894{
    895	struct ath6kl *ar = file->private_data;
    896	u8 buf[50];
    897	unsigned int len = 0;
    898
    899	if (ar->debug.dbgfs_diag_reg)
    900		len += scnprintf(buf + len, sizeof(buf) - len, "0x%x\n",
    901				ar->debug.dbgfs_diag_reg);
    902	else
    903		len += scnprintf(buf + len, sizeof(buf) - len,
    904				 "All diag registers\n");
    905
    906	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
    907}
    908
    909static ssize_t ath6kl_regread_write(struct file *file,
    910				    const char __user *user_buf,
    911				    size_t count, loff_t *ppos)
    912{
    913	struct ath6kl *ar = file->private_data;
    914	unsigned long reg_addr;
    915
    916	if (kstrtoul_from_user(user_buf, count, 0, &reg_addr))
    917		return -EINVAL;
    918
    919	if ((reg_addr % 4) != 0)
    920		return -EINVAL;
    921
    922	if (reg_addr && !ath6kl_dbg_is_diag_reg_valid(reg_addr))
    923		return -EINVAL;
    924
    925	ar->debug.dbgfs_diag_reg = reg_addr;
    926
    927	return count;
    928}
    929
    930static const struct file_operations fops_diag_reg_read = {
    931	.read = ath6kl_regread_read,
    932	.write = ath6kl_regread_write,
    933	.open = simple_open,
    934	.owner = THIS_MODULE,
    935	.llseek = default_llseek,
    936};
    937
    938static int ath6kl_regdump_open(struct inode *inode, struct file *file)
    939{
    940	struct ath6kl *ar = inode->i_private;
    941	u8 *buf;
    942	unsigned long int reg_len;
    943	unsigned int len = 0, n_reg;
    944	u32 addr;
    945	__le32 reg_val;
    946	int i, status;
    947
    948	/* Dump all the registers if no register is specified */
    949	if (!ar->debug.dbgfs_diag_reg)
    950		n_reg = ath6kl_get_num_reg();
    951	else
    952		n_reg = 1;
    953
    954	reg_len = n_reg * REG_OUTPUT_LEN_PER_LINE;
    955	if (n_reg > 1)
    956		reg_len += REGTYPE_STR_LEN;
    957
    958	buf = vmalloc(reg_len);
    959	if (!buf)
    960		return -ENOMEM;
    961
    962	if (n_reg == 1) {
    963		addr = ar->debug.dbgfs_diag_reg;
    964
    965		status = ath6kl_diag_read32(ar,
    966				TARG_VTOP(ar->target_type, addr),
    967				(u32 *)&reg_val);
    968		if (status)
    969			goto fail_reg_read;
    970
    971		len += scnprintf(buf + len, reg_len - len,
    972				 "0x%06x 0x%08x\n", addr, le32_to_cpu(reg_val));
    973		goto done;
    974	}
    975
    976	for (i = 0; i < ARRAY_SIZE(diag_reg); i++) {
    977		len += scnprintf(buf + len, reg_len - len,
    978				"%s\n", diag_reg[i].reg_info);
    979		for (addr = diag_reg[i].reg_start;
    980		     addr <= diag_reg[i].reg_end; addr += 4) {
    981			status = ath6kl_diag_read32(ar,
    982					TARG_VTOP(ar->target_type, addr),
    983					(u32 *)&reg_val);
    984			if (status)
    985				goto fail_reg_read;
    986
    987			len += scnprintf(buf + len, reg_len - len,
    988					"0x%06x 0x%08x\n",
    989					addr, le32_to_cpu(reg_val));
    990		}
    991	}
    992
    993done:
    994	file->private_data = buf;
    995	return 0;
    996
    997fail_reg_read:
    998	ath6kl_warn("Unable to read memory:%u\n", addr);
    999	vfree(buf);
   1000	return -EIO;
   1001}
   1002
   1003static 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
   1010static int ath6kl_regdump_release(struct inode *inode, struct file *file)
   1011{
   1012	vfree(file->private_data);
   1013	return 0;
   1014}
   1015
   1016static 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
   1024static 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
   1044static 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
   1057static 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
   1065static 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
   1079static 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
   1119static 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
   1127int 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
   1160static 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
   1224static 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
   1231static 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
   1256static 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
   1263static 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
   1296static 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
   1303void ath6kl_debug_set_keepalive(struct ath6kl *ar, u8 keepalive)
   1304{
   1305	ar->debug.keepalive = keepalive;
   1306}
   1307
   1308static 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
   1320static 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
   1339static 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
   1347void ath6kl_debug_set_disconnect_timeout(struct ath6kl *ar, u8 timeout)
   1348{
   1349	ar->debug.disc_timeout = timeout;
   1350}
   1351
   1352static 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
   1365static 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
   1384static 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
   1392static 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
   1563static 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
   1570static 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
   1610static 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
   1617static 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
   1650static 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
   1657static 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
   1689static 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
   1707static 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
   1715static 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
   1768static 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
   1775void 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 */
   1792int 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
   1866void 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