brintos

brintos / linux-shallow public Read only

0
0
Text · 45.3 KiB · b837d31 Raw
1872 lines · c
1/*2 * Copyright (c) 2004-2011 Atheros Communications Inc.3 * Copyright (c) 2011-2012 Qualcomm Atheros, Inc.4 *5 * Permission to use, copy, modify, and/or distribute this software for any6 * purpose with or without fee is hereby granted, provided that the above7 * copyright notice and this permission notice appear in all copies.8 *9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF15 * 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 2037 38#define ATH6KL_FWLOG_VALID_MASK 0x1ffff39 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_DEBUG129 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	25167#define REGTYPE_STR_LEN		100168 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 some221			 * 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	200701#define CREDIT_INFO_LEN	128702 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 EPSTAT827 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	else903		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	else952		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	else1287		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 mask1782	 * 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 come1789 * before cfg80211 is initialised, and debugfs depends on cfg802111790 * initialisation.1791 */1792int ath6kl_debug_init_fs(struct ath6kl *ar)1793{1794	ar->debugfs_phy = debugfs_create_dir("ath6kl",1795					     ar->wiphy->debugfsdir);1796 1797	debugfs_create_file("tgt_stats", 0400, ar->debugfs_phy, ar,1798			    &fops_tgt_stats);1799 1800	if (ar->hif_type == ATH6KL_HIF_TYPE_SDIO)1801		debugfs_create_file("credit_dist_stats", 0400,1802				    ar->debugfs_phy, ar,1803				    &fops_credit_dist_stats);1804 1805	debugfs_create_file("endpoint_stats", 0600,1806			    ar->debugfs_phy, ar, &fops_endpoint_stats);1807 1808	debugfs_create_file("fwlog", 0400, ar->debugfs_phy, ar, &fops_fwlog);1809 1810	debugfs_create_file("fwlog_block", 0400, ar->debugfs_phy, ar,1811			    &fops_fwlog_block);1812 1813	debugfs_create_file("fwlog_mask", 0600, ar->debugfs_phy,1814			    ar, &fops_fwlog_mask);1815 1816	debugfs_create_file("reg_addr", 0600, ar->debugfs_phy, ar,1817			    &fops_diag_reg_read);1818 1819	debugfs_create_file("reg_dump", 0400, ar->debugfs_phy, ar,1820			    &fops_reg_dump);1821 1822	debugfs_create_file("lrssi_roam_threshold", 0600,1823			    ar->debugfs_phy, ar, &fops_lrssi_roam_threshold);1824 1825	debugfs_create_file("reg_write", 0600,1826			    ar->debugfs_phy, ar, &fops_diag_reg_write);1827 1828	debugfs_create_file("war_stats", 0400, ar->debugfs_phy, ar,1829			    &fops_war_stats);1830 1831	debugfs_create_file("roam_table", 0400, ar->debugfs_phy, ar,1832			    &fops_roam_table);1833 1834	debugfs_create_file("force_roam", 0200, ar->debugfs_phy, ar,1835			    &fops_force_roam);1836 1837	debugfs_create_file("roam_mode", 0200, ar->debugfs_phy, ar,1838			    &fops_roam_mode);1839 1840	debugfs_create_file("keepalive", 0600, ar->debugfs_phy, ar,1841			    &fops_keepalive);1842 1843	debugfs_create_file("disconnect_timeout", 0600,1844			    ar->debugfs_phy, ar, &fops_disconnect_timeout);1845 1846	debugfs_create_file("create_qos", 0200, ar->debugfs_phy, ar,1847			    &fops_create_qos);1848 1849	debugfs_create_file("delete_qos", 0200, ar->debugfs_phy, ar,1850			    &fops_delete_qos);1851 1852	debugfs_create_file("bgscan_interval", 0200,1853			    ar->debugfs_phy, ar, &fops_bgscan_int);1854 1855	debugfs_create_file("listen_interval", 0600,1856			    ar->debugfs_phy, ar, &fops_listen_int);1857 1858	debugfs_create_file("power_params", 0200, ar->debugfs_phy, ar,1859			    &fops_power_params);1860 1861	return 0;1862}1863 1864void ath6kl_debug_cleanup(struct ath6kl *ar)1865{1866	skb_queue_purge(&ar->debug.fwlog_queue);1867	complete(&ar->debug.fwlog_completion);1868	kfree(ar->debug.roam_tbl);1869}1870 1871#endif1872