162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * Copyright (c) 2004-2011 Atheros Communications Inc.
362306a36Sopenharmony_ci * Copyright (c) 2011-2012 Qualcomm Atheros, Inc.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Permission to use, copy, modify, and/or distribute this software for any
662306a36Sopenharmony_ci * purpose with or without fee is hereby granted, provided that the above
762306a36Sopenharmony_ci * copyright notice and this permission notice appear in all copies.
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1062306a36Sopenharmony_ci * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1162306a36Sopenharmony_ci * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1262306a36Sopenharmony_ci * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1362306a36Sopenharmony_ci * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1462306a36Sopenharmony_ci * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1562306a36Sopenharmony_ci * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1662306a36Sopenharmony_ci */
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#include "core.h"
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci#include <linux/skbuff.h>
2162306a36Sopenharmony_ci#include <linux/fs.h>
2262306a36Sopenharmony_ci#include <linux/vmalloc.h>
2362306a36Sopenharmony_ci#include <linux/export.h>
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci#include "debug.h"
2662306a36Sopenharmony_ci#include "target.h"
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_cistruct ath6kl_fwlog_slot {
2962306a36Sopenharmony_ci	__le32 timestamp;
3062306a36Sopenharmony_ci	__le32 length;
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci	/* max ATH6KL_FWLOG_PAYLOAD_SIZE bytes */
3362306a36Sopenharmony_ci	u8 payload[];
3462306a36Sopenharmony_ci};
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci#define ATH6KL_FWLOG_MAX_ENTRIES 20
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci#define ATH6KL_FWLOG_VALID_MASK 0x1ffff
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_civoid ath6kl_printk(const char *level, const char *fmt, ...)
4162306a36Sopenharmony_ci{
4262306a36Sopenharmony_ci	struct va_format vaf;
4362306a36Sopenharmony_ci	va_list args;
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci	va_start(args, fmt);
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci	vaf.fmt = fmt;
4862306a36Sopenharmony_ci	vaf.va = &args;
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci	printk("%sath6kl: %pV", level, &vaf);
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	va_end(args);
5362306a36Sopenharmony_ci}
5462306a36Sopenharmony_ciEXPORT_SYMBOL(ath6kl_printk);
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_civoid ath6kl_info(const char *fmt, ...)
5762306a36Sopenharmony_ci{
5862306a36Sopenharmony_ci	struct va_format vaf = {
5962306a36Sopenharmony_ci		.fmt = fmt,
6062306a36Sopenharmony_ci	};
6162306a36Sopenharmony_ci	va_list args;
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	va_start(args, fmt);
6462306a36Sopenharmony_ci	vaf.va = &args;
6562306a36Sopenharmony_ci	ath6kl_printk(KERN_INFO, "%pV", &vaf);
6662306a36Sopenharmony_ci	trace_ath6kl_log_info(&vaf);
6762306a36Sopenharmony_ci	va_end(args);
6862306a36Sopenharmony_ci}
6962306a36Sopenharmony_ciEXPORT_SYMBOL(ath6kl_info);
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_civoid ath6kl_err(const char *fmt, ...)
7262306a36Sopenharmony_ci{
7362306a36Sopenharmony_ci	struct va_format vaf = {
7462306a36Sopenharmony_ci		.fmt = fmt,
7562306a36Sopenharmony_ci	};
7662306a36Sopenharmony_ci	va_list args;
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	va_start(args, fmt);
7962306a36Sopenharmony_ci	vaf.va = &args;
8062306a36Sopenharmony_ci	ath6kl_printk(KERN_ERR, "%pV", &vaf);
8162306a36Sopenharmony_ci	trace_ath6kl_log_err(&vaf);
8262306a36Sopenharmony_ci	va_end(args);
8362306a36Sopenharmony_ci}
8462306a36Sopenharmony_ciEXPORT_SYMBOL(ath6kl_err);
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_civoid ath6kl_warn(const char *fmt, ...)
8762306a36Sopenharmony_ci{
8862306a36Sopenharmony_ci	struct va_format vaf = {
8962306a36Sopenharmony_ci		.fmt = fmt,
9062306a36Sopenharmony_ci	};
9162306a36Sopenharmony_ci	va_list args;
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	va_start(args, fmt);
9462306a36Sopenharmony_ci	vaf.va = &args;
9562306a36Sopenharmony_ci	ath6kl_printk(KERN_WARNING, "%pV", &vaf);
9662306a36Sopenharmony_ci	trace_ath6kl_log_warn(&vaf);
9762306a36Sopenharmony_ci	va_end(args);
9862306a36Sopenharmony_ci}
9962306a36Sopenharmony_ciEXPORT_SYMBOL(ath6kl_warn);
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ciint ath6kl_read_tgt_stats(struct ath6kl *ar, struct ath6kl_vif *vif)
10262306a36Sopenharmony_ci{
10362306a36Sopenharmony_ci	long left;
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	if (down_interruptible(&ar->sem))
10662306a36Sopenharmony_ci		return -EBUSY;
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	set_bit(STATS_UPDATE_PEND, &vif->flags);
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	if (ath6kl_wmi_get_stats_cmd(ar->wmi, 0)) {
11162306a36Sopenharmony_ci		up(&ar->sem);
11262306a36Sopenharmony_ci		return -EIO;
11362306a36Sopenharmony_ci	}
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	left = wait_event_interruptible_timeout(ar->event_wq,
11662306a36Sopenharmony_ci						!test_bit(STATS_UPDATE_PEND,
11762306a36Sopenharmony_ci						&vif->flags), WMI_TIMEOUT);
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	up(&ar->sem);
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci	if (left <= 0)
12262306a36Sopenharmony_ci		return -ETIMEDOUT;
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	return 0;
12562306a36Sopenharmony_ci}
12662306a36Sopenharmony_ciEXPORT_SYMBOL(ath6kl_read_tgt_stats);
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci#ifdef CONFIG_ATH6KL_DEBUG
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_civoid ath6kl_dbg(enum ATH6K_DEBUG_MASK mask, const char *fmt, ...)
13162306a36Sopenharmony_ci{
13262306a36Sopenharmony_ci	struct va_format vaf;
13362306a36Sopenharmony_ci	va_list args;
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	va_start(args, fmt);
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci	vaf.fmt = fmt;
13862306a36Sopenharmony_ci	vaf.va = &args;
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci	if (debug_mask & mask)
14162306a36Sopenharmony_ci		ath6kl_printk(KERN_DEBUG, "%pV", &vaf);
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	trace_ath6kl_log_dbg(mask, &vaf);
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	va_end(args);
14662306a36Sopenharmony_ci}
14762306a36Sopenharmony_ciEXPORT_SYMBOL(ath6kl_dbg);
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_civoid ath6kl_dbg_dump(enum ATH6K_DEBUG_MASK mask,
15062306a36Sopenharmony_ci		     const char *msg, const char *prefix,
15162306a36Sopenharmony_ci		     const void *buf, size_t len)
15262306a36Sopenharmony_ci{
15362306a36Sopenharmony_ci	if (debug_mask & mask) {
15462306a36Sopenharmony_ci		if (msg)
15562306a36Sopenharmony_ci			ath6kl_dbg(mask, "%s\n", msg);
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci		print_hex_dump_bytes(prefix, DUMP_PREFIX_OFFSET, buf, len);
15862306a36Sopenharmony_ci	}
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	/* tracing code doesn't like null strings :/ */
16162306a36Sopenharmony_ci	trace_ath6kl_log_dbg_dump(msg ? msg : "", prefix ? prefix : "",
16262306a36Sopenharmony_ci				  buf, len);
16362306a36Sopenharmony_ci}
16462306a36Sopenharmony_ciEXPORT_SYMBOL(ath6kl_dbg_dump);
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci#define REG_OUTPUT_LEN_PER_LINE	25
16762306a36Sopenharmony_ci#define REGTYPE_STR_LEN		100
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_cistruct ath6kl_diag_reg_info {
17062306a36Sopenharmony_ci	u32 reg_start;
17162306a36Sopenharmony_ci	u32 reg_end;
17262306a36Sopenharmony_ci	const char *reg_info;
17362306a36Sopenharmony_ci};
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_cistatic const struct ath6kl_diag_reg_info diag_reg[] = {
17662306a36Sopenharmony_ci	{ 0x20000, 0x200fc, "General DMA and Rx registers" },
17762306a36Sopenharmony_ci	{ 0x28000, 0x28900, "MAC PCU register & keycache" },
17862306a36Sopenharmony_ci	{ 0x20800, 0x20a40, "QCU" },
17962306a36Sopenharmony_ci	{ 0x21000, 0x212f0, "DCU" },
18062306a36Sopenharmony_ci	{ 0x4000,  0x42e4, "RTC" },
18162306a36Sopenharmony_ci	{ 0x540000, 0x540000 + (256 * 1024), "RAM" },
18262306a36Sopenharmony_ci	{ 0x29800, 0x2B210, "Base Band" },
18362306a36Sopenharmony_ci	{ 0x1C000, 0x1C748, "Analog" },
18462306a36Sopenharmony_ci};
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_civoid ath6kl_dump_registers(struct ath6kl_device *dev,
18762306a36Sopenharmony_ci			   struct ath6kl_irq_proc_registers *irq_proc_reg,
18862306a36Sopenharmony_ci			   struct ath6kl_irq_enable_reg *irq_enable_reg)
18962306a36Sopenharmony_ci{
19062306a36Sopenharmony_ci	ath6kl_dbg(ATH6KL_DBG_IRQ, ("<------- Register Table -------->\n"));
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	if (irq_proc_reg != NULL) {
19362306a36Sopenharmony_ci		ath6kl_dbg(ATH6KL_DBG_IRQ,
19462306a36Sopenharmony_ci			   "Host Int status:           0x%x\n",
19562306a36Sopenharmony_ci			   irq_proc_reg->host_int_status);
19662306a36Sopenharmony_ci		ath6kl_dbg(ATH6KL_DBG_IRQ,
19762306a36Sopenharmony_ci			   "CPU Int status:            0x%x\n",
19862306a36Sopenharmony_ci			   irq_proc_reg->cpu_int_status);
19962306a36Sopenharmony_ci		ath6kl_dbg(ATH6KL_DBG_IRQ,
20062306a36Sopenharmony_ci			   "Error Int status:          0x%x\n",
20162306a36Sopenharmony_ci			   irq_proc_reg->error_int_status);
20262306a36Sopenharmony_ci		ath6kl_dbg(ATH6KL_DBG_IRQ,
20362306a36Sopenharmony_ci			   "Counter Int status:        0x%x\n",
20462306a36Sopenharmony_ci			   irq_proc_reg->counter_int_status);
20562306a36Sopenharmony_ci		ath6kl_dbg(ATH6KL_DBG_IRQ,
20662306a36Sopenharmony_ci			   "Mbox Frame:                0x%x\n",
20762306a36Sopenharmony_ci			   irq_proc_reg->mbox_frame);
20862306a36Sopenharmony_ci		ath6kl_dbg(ATH6KL_DBG_IRQ,
20962306a36Sopenharmony_ci			   "Rx Lookahead Valid:        0x%x\n",
21062306a36Sopenharmony_ci			   irq_proc_reg->rx_lkahd_valid);
21162306a36Sopenharmony_ci		ath6kl_dbg(ATH6KL_DBG_IRQ,
21262306a36Sopenharmony_ci			   "Rx Lookahead 0:            0x%x\n",
21362306a36Sopenharmony_ci			   irq_proc_reg->rx_lkahd[0]);
21462306a36Sopenharmony_ci		ath6kl_dbg(ATH6KL_DBG_IRQ,
21562306a36Sopenharmony_ci			   "Rx Lookahead 1:            0x%x\n",
21662306a36Sopenharmony_ci			   irq_proc_reg->rx_lkahd[1]);
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci		if (dev->ar->mbox_info.gmbox_addr != 0) {
21962306a36Sopenharmony_ci			/*
22062306a36Sopenharmony_ci			 * If the target supports GMBOX hardware, dump some
22162306a36Sopenharmony_ci			 * additional state.
22262306a36Sopenharmony_ci			 */
22362306a36Sopenharmony_ci			ath6kl_dbg(ATH6KL_DBG_IRQ,
22462306a36Sopenharmony_ci				   "GMBOX Host Int status 2:   0x%x\n",
22562306a36Sopenharmony_ci				   irq_proc_reg->host_int_status2);
22662306a36Sopenharmony_ci			ath6kl_dbg(ATH6KL_DBG_IRQ,
22762306a36Sopenharmony_ci				   "GMBOX RX Avail:            0x%x\n",
22862306a36Sopenharmony_ci				   irq_proc_reg->gmbox_rx_avail);
22962306a36Sopenharmony_ci			ath6kl_dbg(ATH6KL_DBG_IRQ,
23062306a36Sopenharmony_ci				   "GMBOX lookahead alias 0:   0x%x\n",
23162306a36Sopenharmony_ci				   irq_proc_reg->rx_gmbox_lkahd_alias[0]);
23262306a36Sopenharmony_ci			ath6kl_dbg(ATH6KL_DBG_IRQ,
23362306a36Sopenharmony_ci				   "GMBOX lookahead alias 1:   0x%x\n",
23462306a36Sopenharmony_ci				   irq_proc_reg->rx_gmbox_lkahd_alias[1]);
23562306a36Sopenharmony_ci		}
23662306a36Sopenharmony_ci	}
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci	if (irq_enable_reg != NULL) {
23962306a36Sopenharmony_ci		ath6kl_dbg(ATH6KL_DBG_IRQ,
24062306a36Sopenharmony_ci			   "Int status Enable:         0x%x\n",
24162306a36Sopenharmony_ci			   irq_enable_reg->int_status_en);
24262306a36Sopenharmony_ci		ath6kl_dbg(ATH6KL_DBG_IRQ, "Counter Int status Enable: 0x%x\n",
24362306a36Sopenharmony_ci			   irq_enable_reg->cntr_int_status_en);
24462306a36Sopenharmony_ci	}
24562306a36Sopenharmony_ci	ath6kl_dbg(ATH6KL_DBG_IRQ, "<------------------------------->\n");
24662306a36Sopenharmony_ci}
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_cistatic void dump_cred_dist(struct htc_endpoint_credit_dist *ep_dist)
24962306a36Sopenharmony_ci{
25062306a36Sopenharmony_ci	ath6kl_dbg(ATH6KL_DBG_CREDIT,
25162306a36Sopenharmony_ci		   "--- endpoint: %d  svc_id: 0x%X ---\n",
25262306a36Sopenharmony_ci		   ep_dist->endpoint, ep_dist->svc_id);
25362306a36Sopenharmony_ci	ath6kl_dbg(ATH6KL_DBG_CREDIT, " dist_flags     : 0x%X\n",
25462306a36Sopenharmony_ci		   ep_dist->dist_flags);
25562306a36Sopenharmony_ci	ath6kl_dbg(ATH6KL_DBG_CREDIT, " cred_norm      : %d\n",
25662306a36Sopenharmony_ci		   ep_dist->cred_norm);
25762306a36Sopenharmony_ci	ath6kl_dbg(ATH6KL_DBG_CREDIT, " cred_min       : %d\n",
25862306a36Sopenharmony_ci		   ep_dist->cred_min);
25962306a36Sopenharmony_ci	ath6kl_dbg(ATH6KL_DBG_CREDIT, " credits        : %d\n",
26062306a36Sopenharmony_ci		   ep_dist->credits);
26162306a36Sopenharmony_ci	ath6kl_dbg(ATH6KL_DBG_CREDIT, " cred_assngd    : %d\n",
26262306a36Sopenharmony_ci		   ep_dist->cred_assngd);
26362306a36Sopenharmony_ci	ath6kl_dbg(ATH6KL_DBG_CREDIT, " seek_cred      : %d\n",
26462306a36Sopenharmony_ci		   ep_dist->seek_cred);
26562306a36Sopenharmony_ci	ath6kl_dbg(ATH6KL_DBG_CREDIT, " cred_sz        : %d\n",
26662306a36Sopenharmony_ci		   ep_dist->cred_sz);
26762306a36Sopenharmony_ci	ath6kl_dbg(ATH6KL_DBG_CREDIT, " cred_per_msg   : %d\n",
26862306a36Sopenharmony_ci		   ep_dist->cred_per_msg);
26962306a36Sopenharmony_ci	ath6kl_dbg(ATH6KL_DBG_CREDIT, " cred_to_dist   : %d\n",
27062306a36Sopenharmony_ci		   ep_dist->cred_to_dist);
27162306a36Sopenharmony_ci	ath6kl_dbg(ATH6KL_DBG_CREDIT, " txq_depth      : %d\n",
27262306a36Sopenharmony_ci		   get_queue_depth(&ep_dist->htc_ep->txq));
27362306a36Sopenharmony_ci	ath6kl_dbg(ATH6KL_DBG_CREDIT,
27462306a36Sopenharmony_ci		   "----------------------------------\n");
27562306a36Sopenharmony_ci}
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci/* FIXME: move to htc.c */
27862306a36Sopenharmony_civoid dump_cred_dist_stats(struct htc_target *target)
27962306a36Sopenharmony_ci{
28062306a36Sopenharmony_ci	struct htc_endpoint_credit_dist *ep_list;
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	list_for_each_entry(ep_list, &target->cred_dist_list, list)
28362306a36Sopenharmony_ci		dump_cred_dist(ep_list);
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	ath6kl_dbg(ATH6KL_DBG_CREDIT,
28662306a36Sopenharmony_ci		   "credit distribution total %d free %d\n",
28762306a36Sopenharmony_ci		   target->credit_info->total_avail_credits,
28862306a36Sopenharmony_ci		   target->credit_info->cur_free_credits);
28962306a36Sopenharmony_ci}
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_civoid ath6kl_debug_war(struct ath6kl *ar, enum ath6kl_war war)
29262306a36Sopenharmony_ci{
29362306a36Sopenharmony_ci	switch (war) {
29462306a36Sopenharmony_ci	case ATH6KL_WAR_INVALID_RATE:
29562306a36Sopenharmony_ci		ar->debug.war_stats.invalid_rate++;
29662306a36Sopenharmony_ci		break;
29762306a36Sopenharmony_ci	}
29862306a36Sopenharmony_ci}
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_cistatic ssize_t read_file_war_stats(struct file *file, char __user *user_buf,
30162306a36Sopenharmony_ci				   size_t count, loff_t *ppos)
30262306a36Sopenharmony_ci{
30362306a36Sopenharmony_ci	struct ath6kl *ar = file->private_data;
30462306a36Sopenharmony_ci	char *buf;
30562306a36Sopenharmony_ci	unsigned int len = 0, buf_len = 1500;
30662306a36Sopenharmony_ci	ssize_t ret_cnt;
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	buf = kzalloc(buf_len, GFP_KERNEL);
30962306a36Sopenharmony_ci	if (!buf)
31062306a36Sopenharmony_ci		return -ENOMEM;
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	len += scnprintf(buf + len, buf_len - len, "\n");
31362306a36Sopenharmony_ci	len += scnprintf(buf + len, buf_len - len, "%25s\n",
31462306a36Sopenharmony_ci			 "Workaround stats");
31562306a36Sopenharmony_ci	len += scnprintf(buf + len, buf_len - len, "%25s\n\n",
31662306a36Sopenharmony_ci			 "=================");
31762306a36Sopenharmony_ci	len += scnprintf(buf + len, buf_len - len, "%20s %10u\n",
31862306a36Sopenharmony_ci			 "Invalid rates", ar->debug.war_stats.invalid_rate);
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci	if (WARN_ON(len > buf_len))
32162306a36Sopenharmony_ci		len = buf_len;
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci	ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	kfree(buf);
32662306a36Sopenharmony_ci	return ret_cnt;
32762306a36Sopenharmony_ci}
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_cistatic const struct file_operations fops_war_stats = {
33062306a36Sopenharmony_ci	.read = read_file_war_stats,
33162306a36Sopenharmony_ci	.open = simple_open,
33262306a36Sopenharmony_ci	.owner = THIS_MODULE,
33362306a36Sopenharmony_ci	.llseek = default_llseek,
33462306a36Sopenharmony_ci};
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_civoid ath6kl_debug_fwlog_event(struct ath6kl *ar, const void *buf, size_t len)
33762306a36Sopenharmony_ci{
33862306a36Sopenharmony_ci	struct ath6kl_fwlog_slot *slot;
33962306a36Sopenharmony_ci	struct sk_buff *skb;
34062306a36Sopenharmony_ci	size_t slot_len;
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci	if (WARN_ON(len > ATH6KL_FWLOG_PAYLOAD_SIZE))
34362306a36Sopenharmony_ci		return;
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	slot_len = sizeof(*slot) + ATH6KL_FWLOG_PAYLOAD_SIZE;
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	skb = alloc_skb(slot_len, GFP_KERNEL);
34862306a36Sopenharmony_ci	if (!skb)
34962306a36Sopenharmony_ci		return;
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci	slot = skb_put(skb, slot_len);
35262306a36Sopenharmony_ci	slot->timestamp = cpu_to_le32(jiffies);
35362306a36Sopenharmony_ci	slot->length = cpu_to_le32(len);
35462306a36Sopenharmony_ci	memcpy(slot->payload, buf, len);
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	/* Need to pad each record to fixed length ATH6KL_FWLOG_PAYLOAD_SIZE */
35762306a36Sopenharmony_ci	memset(slot->payload + len, 0, ATH6KL_FWLOG_PAYLOAD_SIZE - len);
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	spin_lock(&ar->debug.fwlog_queue.lock);
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	__skb_queue_tail(&ar->debug.fwlog_queue, skb);
36262306a36Sopenharmony_ci	complete(&ar->debug.fwlog_completion);
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	/* drop oldest entries */
36562306a36Sopenharmony_ci	while (skb_queue_len(&ar->debug.fwlog_queue) >
36662306a36Sopenharmony_ci	       ATH6KL_FWLOG_MAX_ENTRIES) {
36762306a36Sopenharmony_ci		skb = __skb_dequeue(&ar->debug.fwlog_queue);
36862306a36Sopenharmony_ci		kfree_skb(skb);
36962306a36Sopenharmony_ci	}
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	spin_unlock(&ar->debug.fwlog_queue.lock);
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci	return;
37462306a36Sopenharmony_ci}
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_cistatic int ath6kl_fwlog_open(struct inode *inode, struct file *file)
37762306a36Sopenharmony_ci{
37862306a36Sopenharmony_ci	struct ath6kl *ar = inode->i_private;
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci	if (ar->debug.fwlog_open)
38162306a36Sopenharmony_ci		return -EBUSY;
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci	ar->debug.fwlog_open = true;
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci	file->private_data = inode->i_private;
38662306a36Sopenharmony_ci	return 0;
38762306a36Sopenharmony_ci}
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_cistatic int ath6kl_fwlog_release(struct inode *inode, struct file *file)
39062306a36Sopenharmony_ci{
39162306a36Sopenharmony_ci	struct ath6kl *ar = inode->i_private;
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	ar->debug.fwlog_open = false;
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci	return 0;
39662306a36Sopenharmony_ci}
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_cistatic ssize_t ath6kl_fwlog_read(struct file *file, char __user *user_buf,
39962306a36Sopenharmony_ci				 size_t count, loff_t *ppos)
40062306a36Sopenharmony_ci{
40162306a36Sopenharmony_ci	struct ath6kl *ar = file->private_data;
40262306a36Sopenharmony_ci	struct sk_buff *skb;
40362306a36Sopenharmony_ci	ssize_t ret_cnt;
40462306a36Sopenharmony_ci	size_t len = 0;
40562306a36Sopenharmony_ci	char *buf;
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci	buf = vmalloc(count);
40862306a36Sopenharmony_ci	if (!buf)
40962306a36Sopenharmony_ci		return -ENOMEM;
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	/* read undelivered logs from firmware */
41262306a36Sopenharmony_ci	ath6kl_read_fwlogs(ar);
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci	spin_lock(&ar->debug.fwlog_queue.lock);
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci	while ((skb = __skb_dequeue(&ar->debug.fwlog_queue))) {
41762306a36Sopenharmony_ci		if (skb->len > count - len) {
41862306a36Sopenharmony_ci			/* not enough space, put skb back and leave */
41962306a36Sopenharmony_ci			__skb_queue_head(&ar->debug.fwlog_queue, skb);
42062306a36Sopenharmony_ci			break;
42162306a36Sopenharmony_ci		}
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci		memcpy(buf + len, skb->data, skb->len);
42562306a36Sopenharmony_ci		len += skb->len;
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci		kfree_skb(skb);
42862306a36Sopenharmony_ci	}
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ci	spin_unlock(&ar->debug.fwlog_queue.lock);
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci	/* FIXME: what to do if len == 0? */
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci	ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci	vfree(buf);
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	return ret_cnt;
43962306a36Sopenharmony_ci}
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_cistatic const struct file_operations fops_fwlog = {
44262306a36Sopenharmony_ci	.open = ath6kl_fwlog_open,
44362306a36Sopenharmony_ci	.release = ath6kl_fwlog_release,
44462306a36Sopenharmony_ci	.read = ath6kl_fwlog_read,
44562306a36Sopenharmony_ci	.owner = THIS_MODULE,
44662306a36Sopenharmony_ci	.llseek = default_llseek,
44762306a36Sopenharmony_ci};
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_cistatic ssize_t ath6kl_fwlog_block_read(struct file *file,
45062306a36Sopenharmony_ci				       char __user *user_buf,
45162306a36Sopenharmony_ci				       size_t count,
45262306a36Sopenharmony_ci				       loff_t *ppos)
45362306a36Sopenharmony_ci{
45462306a36Sopenharmony_ci	struct ath6kl *ar = file->private_data;
45562306a36Sopenharmony_ci	struct sk_buff *skb;
45662306a36Sopenharmony_ci	ssize_t ret_cnt;
45762306a36Sopenharmony_ci	size_t len = 0, not_copied;
45862306a36Sopenharmony_ci	char *buf;
45962306a36Sopenharmony_ci	int ret;
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci	buf = vmalloc(count);
46262306a36Sopenharmony_ci	if (!buf)
46362306a36Sopenharmony_ci		return -ENOMEM;
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci	spin_lock(&ar->debug.fwlog_queue.lock);
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci	if (skb_queue_len(&ar->debug.fwlog_queue) == 0) {
46862306a36Sopenharmony_ci		/* we must init under queue lock */
46962306a36Sopenharmony_ci		init_completion(&ar->debug.fwlog_completion);
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci		spin_unlock(&ar->debug.fwlog_queue.lock);
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_ci		ret = wait_for_completion_interruptible(
47462306a36Sopenharmony_ci			&ar->debug.fwlog_completion);
47562306a36Sopenharmony_ci		if (ret == -ERESTARTSYS) {
47662306a36Sopenharmony_ci			vfree(buf);
47762306a36Sopenharmony_ci			return ret;
47862306a36Sopenharmony_ci		}
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci		spin_lock(&ar->debug.fwlog_queue.lock);
48162306a36Sopenharmony_ci	}
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci	while ((skb = __skb_dequeue(&ar->debug.fwlog_queue))) {
48462306a36Sopenharmony_ci		if (skb->len > count - len) {
48562306a36Sopenharmony_ci			/* not enough space, put skb back and leave */
48662306a36Sopenharmony_ci			__skb_queue_head(&ar->debug.fwlog_queue, skb);
48762306a36Sopenharmony_ci			break;
48862306a36Sopenharmony_ci		}
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci		memcpy(buf + len, skb->data, skb->len);
49262306a36Sopenharmony_ci		len += skb->len;
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci		kfree_skb(skb);
49562306a36Sopenharmony_ci	}
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci	spin_unlock(&ar->debug.fwlog_queue.lock);
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci	/* FIXME: what to do if len == 0? */
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci	not_copied = copy_to_user(user_buf, buf, len);
50262306a36Sopenharmony_ci	if (not_copied != 0) {
50362306a36Sopenharmony_ci		ret_cnt = -EFAULT;
50462306a36Sopenharmony_ci		goto out;
50562306a36Sopenharmony_ci	}
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci	*ppos = *ppos + len;
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci	ret_cnt = len;
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ciout:
51262306a36Sopenharmony_ci	vfree(buf);
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci	return ret_cnt;
51562306a36Sopenharmony_ci}
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_cistatic const struct file_operations fops_fwlog_block = {
51862306a36Sopenharmony_ci	.open = ath6kl_fwlog_open,
51962306a36Sopenharmony_ci	.release = ath6kl_fwlog_release,
52062306a36Sopenharmony_ci	.read = ath6kl_fwlog_block_read,
52162306a36Sopenharmony_ci	.owner = THIS_MODULE,
52262306a36Sopenharmony_ci	.llseek = default_llseek,
52362306a36Sopenharmony_ci};
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_cistatic ssize_t ath6kl_fwlog_mask_read(struct file *file, char __user *user_buf,
52662306a36Sopenharmony_ci				      size_t count, loff_t *ppos)
52762306a36Sopenharmony_ci{
52862306a36Sopenharmony_ci	struct ath6kl *ar = file->private_data;
52962306a36Sopenharmony_ci	char buf[16];
53062306a36Sopenharmony_ci	int len;
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_ci	len = snprintf(buf, sizeof(buf), "0x%x\n", ar->debug.fwlog_mask);
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
53562306a36Sopenharmony_ci}
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_cistatic ssize_t ath6kl_fwlog_mask_write(struct file *file,
53862306a36Sopenharmony_ci				       const char __user *user_buf,
53962306a36Sopenharmony_ci				       size_t count, loff_t *ppos)
54062306a36Sopenharmony_ci{
54162306a36Sopenharmony_ci	struct ath6kl *ar = file->private_data;
54262306a36Sopenharmony_ci	int ret;
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_ci	ret = kstrtou32_from_user(user_buf, count, 0, &ar->debug.fwlog_mask);
54562306a36Sopenharmony_ci	if (ret)
54662306a36Sopenharmony_ci		return ret;
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci	ret = ath6kl_wmi_config_debug_module_cmd(ar->wmi,
54962306a36Sopenharmony_ci						 ATH6KL_FWLOG_VALID_MASK,
55062306a36Sopenharmony_ci						 ar->debug.fwlog_mask);
55162306a36Sopenharmony_ci	if (ret)
55262306a36Sopenharmony_ci		return ret;
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci	return count;
55562306a36Sopenharmony_ci}
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_cistatic const struct file_operations fops_fwlog_mask = {
55862306a36Sopenharmony_ci	.open = simple_open,
55962306a36Sopenharmony_ci	.read = ath6kl_fwlog_mask_read,
56062306a36Sopenharmony_ci	.write = ath6kl_fwlog_mask_write,
56162306a36Sopenharmony_ci	.owner = THIS_MODULE,
56262306a36Sopenharmony_ci	.llseek = default_llseek,
56362306a36Sopenharmony_ci};
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_cistatic ssize_t read_file_tgt_stats(struct file *file, char __user *user_buf,
56662306a36Sopenharmony_ci				   size_t count, loff_t *ppos)
56762306a36Sopenharmony_ci{
56862306a36Sopenharmony_ci	struct ath6kl *ar = file->private_data;
56962306a36Sopenharmony_ci	struct ath6kl_vif *vif;
57062306a36Sopenharmony_ci	struct target_stats *tgt_stats;
57162306a36Sopenharmony_ci	char *buf;
57262306a36Sopenharmony_ci	unsigned int len = 0, buf_len = 1500;
57362306a36Sopenharmony_ci	int i;
57462306a36Sopenharmony_ci	ssize_t ret_cnt;
57562306a36Sopenharmony_ci	int rv;
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_ci	vif = ath6kl_vif_first(ar);
57862306a36Sopenharmony_ci	if (!vif)
57962306a36Sopenharmony_ci		return -EIO;
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci	buf = kzalloc(buf_len, GFP_KERNEL);
58262306a36Sopenharmony_ci	if (!buf)
58362306a36Sopenharmony_ci		return -ENOMEM;
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_ci	rv = ath6kl_read_tgt_stats(ar, vif);
58662306a36Sopenharmony_ci	if (rv < 0) {
58762306a36Sopenharmony_ci		kfree(buf);
58862306a36Sopenharmony_ci		return rv;
58962306a36Sopenharmony_ci	}
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci	tgt_stats = &vif->target_stats;
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci	len += scnprintf(buf + len, buf_len - len, "\n");
59462306a36Sopenharmony_ci	len += scnprintf(buf + len, buf_len - len, "%25s\n",
59562306a36Sopenharmony_ci			 "Target Tx stats");
59662306a36Sopenharmony_ci	len += scnprintf(buf + len, buf_len - len, "%25s\n\n",
59762306a36Sopenharmony_ci			 "=================");
59862306a36Sopenharmony_ci	len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
59962306a36Sopenharmony_ci			 "Ucast packets", tgt_stats->tx_ucast_pkt);
60062306a36Sopenharmony_ci	len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
60162306a36Sopenharmony_ci			 "Bcast packets", tgt_stats->tx_bcast_pkt);
60262306a36Sopenharmony_ci	len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
60362306a36Sopenharmony_ci			 "Ucast byte", tgt_stats->tx_ucast_byte);
60462306a36Sopenharmony_ci	len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
60562306a36Sopenharmony_ci			 "Bcast byte", tgt_stats->tx_bcast_byte);
60662306a36Sopenharmony_ci	len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
60762306a36Sopenharmony_ci			 "Rts success cnt", tgt_stats->tx_rts_success_cnt);
60862306a36Sopenharmony_ci	for (i = 0; i < 4; i++)
60962306a36Sopenharmony_ci		len += scnprintf(buf + len, buf_len - len,
61062306a36Sopenharmony_ci				 "%18s %d %10llu\n", "PER on ac",
61162306a36Sopenharmony_ci				 i, tgt_stats->tx_pkt_per_ac[i]);
61262306a36Sopenharmony_ci	len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
61362306a36Sopenharmony_ci			 "Error", tgt_stats->tx_err);
61462306a36Sopenharmony_ci	len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
61562306a36Sopenharmony_ci			 "Fail count", tgt_stats->tx_fail_cnt);
61662306a36Sopenharmony_ci	len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
61762306a36Sopenharmony_ci			 "Retry count", tgt_stats->tx_retry_cnt);
61862306a36Sopenharmony_ci	len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
61962306a36Sopenharmony_ci			 "Multi retry cnt", tgt_stats->tx_mult_retry_cnt);
62062306a36Sopenharmony_ci	len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
62162306a36Sopenharmony_ci			 "Rts fail cnt", tgt_stats->tx_rts_fail_cnt);
62262306a36Sopenharmony_ci	len += scnprintf(buf + len, buf_len - len, "%25s %10llu\n\n",
62362306a36Sopenharmony_ci			 "TKIP counter measure used",
62462306a36Sopenharmony_ci			 tgt_stats->tkip_cnter_measures_invoked);
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci	len += scnprintf(buf + len, buf_len - len, "%25s\n",
62762306a36Sopenharmony_ci			 "Target Rx stats");
62862306a36Sopenharmony_ci	len += scnprintf(buf + len, buf_len - len, "%25s\n",
62962306a36Sopenharmony_ci			 "=================");
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_ci	len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
63262306a36Sopenharmony_ci			 "Ucast packets", tgt_stats->rx_ucast_pkt);
63362306a36Sopenharmony_ci	len += scnprintf(buf + len, buf_len - len, "%20s %10d\n",
63462306a36Sopenharmony_ci			 "Ucast Rate", tgt_stats->rx_ucast_rate);
63562306a36Sopenharmony_ci	len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
63662306a36Sopenharmony_ci			 "Bcast packets", tgt_stats->rx_bcast_pkt);
63762306a36Sopenharmony_ci	len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
63862306a36Sopenharmony_ci			 "Ucast byte", tgt_stats->rx_ucast_byte);
63962306a36Sopenharmony_ci	len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
64062306a36Sopenharmony_ci			 "Bcast byte", tgt_stats->rx_bcast_byte);
64162306a36Sopenharmony_ci	len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
64262306a36Sopenharmony_ci			 "Fragmented pkt", tgt_stats->rx_frgment_pkt);
64362306a36Sopenharmony_ci	len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
64462306a36Sopenharmony_ci			 "Error", tgt_stats->rx_err);
64562306a36Sopenharmony_ci	len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
64662306a36Sopenharmony_ci			 "CRC Err", tgt_stats->rx_crc_err);
64762306a36Sopenharmony_ci	len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
64862306a36Sopenharmony_ci			 "Key cache miss", tgt_stats->rx_key_cache_miss);
64962306a36Sopenharmony_ci	len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
65062306a36Sopenharmony_ci			 "Decrypt Err", tgt_stats->rx_decrypt_err);
65162306a36Sopenharmony_ci	len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
65262306a36Sopenharmony_ci			 "Duplicate frame", tgt_stats->rx_dupl_frame);
65362306a36Sopenharmony_ci	len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
65462306a36Sopenharmony_ci			 "Tkip Mic failure", tgt_stats->tkip_local_mic_fail);
65562306a36Sopenharmony_ci	len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
65662306a36Sopenharmony_ci			 "TKIP format err", tgt_stats->tkip_fmt_err);
65762306a36Sopenharmony_ci	len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
65862306a36Sopenharmony_ci			 "CCMP format Err", tgt_stats->ccmp_fmt_err);
65962306a36Sopenharmony_ci	len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n\n",
66062306a36Sopenharmony_ci			 "CCMP Replay Err", tgt_stats->ccmp_replays);
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_ci	len += scnprintf(buf + len, buf_len - len, "%25s\n",
66362306a36Sopenharmony_ci			 "Misc Target stats");
66462306a36Sopenharmony_ci	len += scnprintf(buf + len, buf_len - len, "%25s\n",
66562306a36Sopenharmony_ci			 "=================");
66662306a36Sopenharmony_ci	len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
66762306a36Sopenharmony_ci			 "Beacon Miss count", tgt_stats->cs_bmiss_cnt);
66862306a36Sopenharmony_ci	len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
66962306a36Sopenharmony_ci			 "Num Connects", tgt_stats->cs_connect_cnt);
67062306a36Sopenharmony_ci	len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
67162306a36Sopenharmony_ci			 "Num disconnects", tgt_stats->cs_discon_cnt);
67262306a36Sopenharmony_ci	len += scnprintf(buf + len, buf_len - len, "%20s %10d\n",
67362306a36Sopenharmony_ci			 "Beacon avg rssi", tgt_stats->cs_ave_beacon_rssi);
67462306a36Sopenharmony_ci	len += scnprintf(buf + len, buf_len - len, "%20s %10d\n",
67562306a36Sopenharmony_ci			 "ARP pkt received", tgt_stats->arp_received);
67662306a36Sopenharmony_ci	len += scnprintf(buf + len, buf_len - len, "%20s %10d\n",
67762306a36Sopenharmony_ci			 "ARP pkt matched", tgt_stats->arp_matched);
67862306a36Sopenharmony_ci	len += scnprintf(buf + len, buf_len - len, "%20s %10d\n",
67962306a36Sopenharmony_ci			 "ARP pkt replied", tgt_stats->arp_replied);
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_ci	if (len > buf_len)
68262306a36Sopenharmony_ci		len = buf_len;
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci	ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_ci	kfree(buf);
68762306a36Sopenharmony_ci	return ret_cnt;
68862306a36Sopenharmony_ci}
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_cistatic const struct file_operations fops_tgt_stats = {
69162306a36Sopenharmony_ci	.read = read_file_tgt_stats,
69262306a36Sopenharmony_ci	.open = simple_open,
69362306a36Sopenharmony_ci	.owner = THIS_MODULE,
69462306a36Sopenharmony_ci	.llseek = default_llseek,
69562306a36Sopenharmony_ci};
69662306a36Sopenharmony_ci
69762306a36Sopenharmony_ci#define print_credit_info(fmt_str, ep_list_field)		\
69862306a36Sopenharmony_ci	(len += scnprintf(buf + len, buf_len - len, fmt_str,	\
69962306a36Sopenharmony_ci			 ep_list->ep_list_field))
70062306a36Sopenharmony_ci#define CREDIT_INFO_DISPLAY_STRING_LEN	200
70162306a36Sopenharmony_ci#define CREDIT_INFO_LEN	128
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_cistatic ssize_t read_file_credit_dist_stats(struct file *file,
70462306a36Sopenharmony_ci					   char __user *user_buf,
70562306a36Sopenharmony_ci					   size_t count, loff_t *ppos)
70662306a36Sopenharmony_ci{
70762306a36Sopenharmony_ci	struct ath6kl *ar = file->private_data;
70862306a36Sopenharmony_ci	struct htc_target *target = ar->htc_target;
70962306a36Sopenharmony_ci	struct htc_endpoint_credit_dist *ep_list;
71062306a36Sopenharmony_ci	char *buf;
71162306a36Sopenharmony_ci	unsigned int buf_len, len = 0;
71262306a36Sopenharmony_ci	ssize_t ret_cnt;
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_ci	buf_len = CREDIT_INFO_DISPLAY_STRING_LEN +
71562306a36Sopenharmony_ci		  get_queue_depth(&target->cred_dist_list) * CREDIT_INFO_LEN;
71662306a36Sopenharmony_ci	buf = kzalloc(buf_len, GFP_KERNEL);
71762306a36Sopenharmony_ci	if (!buf)
71862306a36Sopenharmony_ci		return -ENOMEM;
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_ci	len += scnprintf(buf + len, buf_len - len, "%25s%5d\n",
72162306a36Sopenharmony_ci			 "Total Avail Credits: ",
72262306a36Sopenharmony_ci			 target->credit_info->total_avail_credits);
72362306a36Sopenharmony_ci	len += scnprintf(buf + len, buf_len - len, "%25s%5d\n",
72462306a36Sopenharmony_ci			 "Free credits :",
72562306a36Sopenharmony_ci			 target->credit_info->cur_free_credits);
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_ci	len += scnprintf(buf + len, buf_len - len,
72862306a36Sopenharmony_ci			 " Epid  Flags    Cred_norm  Cred_min  Credits  Cred_assngd"
72962306a36Sopenharmony_ci			 "  Seek_cred  Cred_sz  Cred_per_msg  Cred_to_dist"
73062306a36Sopenharmony_ci			 "  qdepth\n");
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_ci	list_for_each_entry(ep_list, &target->cred_dist_list, list) {
73362306a36Sopenharmony_ci		print_credit_info("  %2d", endpoint);
73462306a36Sopenharmony_ci		print_credit_info("%10x", dist_flags);
73562306a36Sopenharmony_ci		print_credit_info("%8d", cred_norm);
73662306a36Sopenharmony_ci		print_credit_info("%9d", cred_min);
73762306a36Sopenharmony_ci		print_credit_info("%9d", credits);
73862306a36Sopenharmony_ci		print_credit_info("%10d", cred_assngd);
73962306a36Sopenharmony_ci		print_credit_info("%13d", seek_cred);
74062306a36Sopenharmony_ci		print_credit_info("%12d", cred_sz);
74162306a36Sopenharmony_ci		print_credit_info("%9d", cred_per_msg);
74262306a36Sopenharmony_ci		print_credit_info("%14d", cred_to_dist);
74362306a36Sopenharmony_ci		len += scnprintf(buf + len, buf_len - len, "%12d\n",
74462306a36Sopenharmony_ci				 get_queue_depth(&ep_list->htc_ep->txq));
74562306a36Sopenharmony_ci	}
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_ci	if (len > buf_len)
74862306a36Sopenharmony_ci		len = buf_len;
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_ci	ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
75162306a36Sopenharmony_ci	kfree(buf);
75262306a36Sopenharmony_ci	return ret_cnt;
75362306a36Sopenharmony_ci}
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_cistatic const struct file_operations fops_credit_dist_stats = {
75662306a36Sopenharmony_ci	.read = read_file_credit_dist_stats,
75762306a36Sopenharmony_ci	.open = simple_open,
75862306a36Sopenharmony_ci	.owner = THIS_MODULE,
75962306a36Sopenharmony_ci	.llseek = default_llseek,
76062306a36Sopenharmony_ci};
76162306a36Sopenharmony_ci
76262306a36Sopenharmony_cistatic unsigned int print_endpoint_stat(struct htc_target *target, char *buf,
76362306a36Sopenharmony_ci					unsigned int buf_len, unsigned int len,
76462306a36Sopenharmony_ci					int offset, const char *name)
76562306a36Sopenharmony_ci{
76662306a36Sopenharmony_ci	int i;
76762306a36Sopenharmony_ci	struct htc_endpoint_stats *ep_st;
76862306a36Sopenharmony_ci	u32 *counter;
76962306a36Sopenharmony_ci
77062306a36Sopenharmony_ci	len += scnprintf(buf + len, buf_len - len, "%s:", name);
77162306a36Sopenharmony_ci	for (i = 0; i < ENDPOINT_MAX; i++) {
77262306a36Sopenharmony_ci		ep_st = &target->endpoint[i].ep_st;
77362306a36Sopenharmony_ci		counter = ((u32 *) ep_st) + (offset / 4);
77462306a36Sopenharmony_ci		len += scnprintf(buf + len, buf_len - len, " %u", *counter);
77562306a36Sopenharmony_ci	}
77662306a36Sopenharmony_ci	len += scnprintf(buf + len, buf_len - len, "\n");
77762306a36Sopenharmony_ci
77862306a36Sopenharmony_ci	return len;
77962306a36Sopenharmony_ci}
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_cistatic ssize_t ath6kl_endpoint_stats_read(struct file *file,
78262306a36Sopenharmony_ci					  char __user *user_buf,
78362306a36Sopenharmony_ci					  size_t count, loff_t *ppos)
78462306a36Sopenharmony_ci{
78562306a36Sopenharmony_ci	struct ath6kl *ar = file->private_data;
78662306a36Sopenharmony_ci	struct htc_target *target = ar->htc_target;
78762306a36Sopenharmony_ci	char *buf;
78862306a36Sopenharmony_ci	unsigned int buf_len, len = 0;
78962306a36Sopenharmony_ci	ssize_t ret_cnt;
79062306a36Sopenharmony_ci
79162306a36Sopenharmony_ci	buf_len = sizeof(struct htc_endpoint_stats) / sizeof(u32) *
79262306a36Sopenharmony_ci		(25 + ENDPOINT_MAX * 11);
79362306a36Sopenharmony_ci	buf = kmalloc(buf_len, GFP_KERNEL);
79462306a36Sopenharmony_ci	if (!buf)
79562306a36Sopenharmony_ci		return -ENOMEM;
79662306a36Sopenharmony_ci
79762306a36Sopenharmony_ci#define EPSTAT(name)							\
79862306a36Sopenharmony_ci	do {								\
79962306a36Sopenharmony_ci		len = print_endpoint_stat(target, buf, buf_len, len,	\
80062306a36Sopenharmony_ci					  offsetof(struct htc_endpoint_stats, \
80162306a36Sopenharmony_ci						   name),		\
80262306a36Sopenharmony_ci					  #name);			\
80362306a36Sopenharmony_ci	} while (0)
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_ci	EPSTAT(cred_low_indicate);
80662306a36Sopenharmony_ci	EPSTAT(tx_issued);
80762306a36Sopenharmony_ci	EPSTAT(tx_pkt_bundled);
80862306a36Sopenharmony_ci	EPSTAT(tx_bundles);
80962306a36Sopenharmony_ci	EPSTAT(tx_dropped);
81062306a36Sopenharmony_ci	EPSTAT(tx_cred_rpt);
81162306a36Sopenharmony_ci	EPSTAT(cred_rpt_from_rx);
81262306a36Sopenharmony_ci	EPSTAT(cred_rpt_from_other);
81362306a36Sopenharmony_ci	EPSTAT(cred_rpt_ep0);
81462306a36Sopenharmony_ci	EPSTAT(cred_from_rx);
81562306a36Sopenharmony_ci	EPSTAT(cred_from_other);
81662306a36Sopenharmony_ci	EPSTAT(cred_from_ep0);
81762306a36Sopenharmony_ci	EPSTAT(cred_cosumd);
81862306a36Sopenharmony_ci	EPSTAT(cred_retnd);
81962306a36Sopenharmony_ci	EPSTAT(rx_pkts);
82062306a36Sopenharmony_ci	EPSTAT(rx_lkahds);
82162306a36Sopenharmony_ci	EPSTAT(rx_bundl);
82262306a36Sopenharmony_ci	EPSTAT(rx_bundle_lkahd);
82362306a36Sopenharmony_ci	EPSTAT(rx_bundle_from_hdr);
82462306a36Sopenharmony_ci	EPSTAT(rx_alloc_thresh_hit);
82562306a36Sopenharmony_ci	EPSTAT(rxalloc_thresh_byte);
82662306a36Sopenharmony_ci#undef EPSTAT
82762306a36Sopenharmony_ci
82862306a36Sopenharmony_ci	if (len > buf_len)
82962306a36Sopenharmony_ci		len = buf_len;
83062306a36Sopenharmony_ci
83162306a36Sopenharmony_ci	ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
83262306a36Sopenharmony_ci	kfree(buf);
83362306a36Sopenharmony_ci	return ret_cnt;
83462306a36Sopenharmony_ci}
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_cistatic ssize_t ath6kl_endpoint_stats_write(struct file *file,
83762306a36Sopenharmony_ci					   const char __user *user_buf,
83862306a36Sopenharmony_ci					   size_t count, loff_t *ppos)
83962306a36Sopenharmony_ci{
84062306a36Sopenharmony_ci	struct ath6kl *ar = file->private_data;
84162306a36Sopenharmony_ci	struct htc_target *target = ar->htc_target;
84262306a36Sopenharmony_ci	int ret, i;
84362306a36Sopenharmony_ci	u32 val;
84462306a36Sopenharmony_ci	struct htc_endpoint_stats *ep_st;
84562306a36Sopenharmony_ci
84662306a36Sopenharmony_ci	ret = kstrtou32_from_user(user_buf, count, 0, &val);
84762306a36Sopenharmony_ci	if (ret)
84862306a36Sopenharmony_ci		return ret;
84962306a36Sopenharmony_ci	if (val == 0) {
85062306a36Sopenharmony_ci		for (i = 0; i < ENDPOINT_MAX; i++) {
85162306a36Sopenharmony_ci			ep_st = &target->endpoint[i].ep_st;
85262306a36Sopenharmony_ci			memset(ep_st, 0, sizeof(*ep_st));
85362306a36Sopenharmony_ci		}
85462306a36Sopenharmony_ci	}
85562306a36Sopenharmony_ci
85662306a36Sopenharmony_ci	return count;
85762306a36Sopenharmony_ci}
85862306a36Sopenharmony_ci
85962306a36Sopenharmony_cistatic const struct file_operations fops_endpoint_stats = {
86062306a36Sopenharmony_ci	.open = simple_open,
86162306a36Sopenharmony_ci	.read = ath6kl_endpoint_stats_read,
86262306a36Sopenharmony_ci	.write = ath6kl_endpoint_stats_write,
86362306a36Sopenharmony_ci	.owner = THIS_MODULE,
86462306a36Sopenharmony_ci	.llseek = default_llseek,
86562306a36Sopenharmony_ci};
86662306a36Sopenharmony_ci
86762306a36Sopenharmony_cistatic unsigned long ath6kl_get_num_reg(void)
86862306a36Sopenharmony_ci{
86962306a36Sopenharmony_ci	int i;
87062306a36Sopenharmony_ci	unsigned long n_reg = 0;
87162306a36Sopenharmony_ci
87262306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(diag_reg); i++)
87362306a36Sopenharmony_ci		n_reg = n_reg +
87462306a36Sopenharmony_ci		     (diag_reg[i].reg_end - diag_reg[i].reg_start) / 4 + 1;
87562306a36Sopenharmony_ci
87662306a36Sopenharmony_ci	return n_reg;
87762306a36Sopenharmony_ci}
87862306a36Sopenharmony_ci
87962306a36Sopenharmony_cistatic bool ath6kl_dbg_is_diag_reg_valid(u32 reg_addr)
88062306a36Sopenharmony_ci{
88162306a36Sopenharmony_ci	int i;
88262306a36Sopenharmony_ci
88362306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(diag_reg); i++) {
88462306a36Sopenharmony_ci		if (reg_addr >= diag_reg[i].reg_start &&
88562306a36Sopenharmony_ci		    reg_addr <= diag_reg[i].reg_end)
88662306a36Sopenharmony_ci			return true;
88762306a36Sopenharmony_ci	}
88862306a36Sopenharmony_ci
88962306a36Sopenharmony_ci	return false;
89062306a36Sopenharmony_ci}
89162306a36Sopenharmony_ci
89262306a36Sopenharmony_cistatic ssize_t ath6kl_regread_read(struct file *file, char __user *user_buf,
89362306a36Sopenharmony_ci				    size_t count, loff_t *ppos)
89462306a36Sopenharmony_ci{
89562306a36Sopenharmony_ci	struct ath6kl *ar = file->private_data;
89662306a36Sopenharmony_ci	u8 buf[50];
89762306a36Sopenharmony_ci	unsigned int len = 0;
89862306a36Sopenharmony_ci
89962306a36Sopenharmony_ci	if (ar->debug.dbgfs_diag_reg)
90062306a36Sopenharmony_ci		len += scnprintf(buf + len, sizeof(buf) - len, "0x%x\n",
90162306a36Sopenharmony_ci				ar->debug.dbgfs_diag_reg);
90262306a36Sopenharmony_ci	else
90362306a36Sopenharmony_ci		len += scnprintf(buf + len, sizeof(buf) - len,
90462306a36Sopenharmony_ci				 "All diag registers\n");
90562306a36Sopenharmony_ci
90662306a36Sopenharmony_ci	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
90762306a36Sopenharmony_ci}
90862306a36Sopenharmony_ci
90962306a36Sopenharmony_cistatic ssize_t ath6kl_regread_write(struct file *file,
91062306a36Sopenharmony_ci				    const char __user *user_buf,
91162306a36Sopenharmony_ci				    size_t count, loff_t *ppos)
91262306a36Sopenharmony_ci{
91362306a36Sopenharmony_ci	struct ath6kl *ar = file->private_data;
91462306a36Sopenharmony_ci	unsigned long reg_addr;
91562306a36Sopenharmony_ci
91662306a36Sopenharmony_ci	if (kstrtoul_from_user(user_buf, count, 0, &reg_addr))
91762306a36Sopenharmony_ci		return -EINVAL;
91862306a36Sopenharmony_ci
91962306a36Sopenharmony_ci	if ((reg_addr % 4) != 0)
92062306a36Sopenharmony_ci		return -EINVAL;
92162306a36Sopenharmony_ci
92262306a36Sopenharmony_ci	if (reg_addr && !ath6kl_dbg_is_diag_reg_valid(reg_addr))
92362306a36Sopenharmony_ci		return -EINVAL;
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_ci	ar->debug.dbgfs_diag_reg = reg_addr;
92662306a36Sopenharmony_ci
92762306a36Sopenharmony_ci	return count;
92862306a36Sopenharmony_ci}
92962306a36Sopenharmony_ci
93062306a36Sopenharmony_cistatic const struct file_operations fops_diag_reg_read = {
93162306a36Sopenharmony_ci	.read = ath6kl_regread_read,
93262306a36Sopenharmony_ci	.write = ath6kl_regread_write,
93362306a36Sopenharmony_ci	.open = simple_open,
93462306a36Sopenharmony_ci	.owner = THIS_MODULE,
93562306a36Sopenharmony_ci	.llseek = default_llseek,
93662306a36Sopenharmony_ci};
93762306a36Sopenharmony_ci
93862306a36Sopenharmony_cistatic int ath6kl_regdump_open(struct inode *inode, struct file *file)
93962306a36Sopenharmony_ci{
94062306a36Sopenharmony_ci	struct ath6kl *ar = inode->i_private;
94162306a36Sopenharmony_ci	u8 *buf;
94262306a36Sopenharmony_ci	unsigned long int reg_len;
94362306a36Sopenharmony_ci	unsigned int len = 0, n_reg;
94462306a36Sopenharmony_ci	u32 addr;
94562306a36Sopenharmony_ci	__le32 reg_val;
94662306a36Sopenharmony_ci	int i, status;
94762306a36Sopenharmony_ci
94862306a36Sopenharmony_ci	/* Dump all the registers if no register is specified */
94962306a36Sopenharmony_ci	if (!ar->debug.dbgfs_diag_reg)
95062306a36Sopenharmony_ci		n_reg = ath6kl_get_num_reg();
95162306a36Sopenharmony_ci	else
95262306a36Sopenharmony_ci		n_reg = 1;
95362306a36Sopenharmony_ci
95462306a36Sopenharmony_ci	reg_len = n_reg * REG_OUTPUT_LEN_PER_LINE;
95562306a36Sopenharmony_ci	if (n_reg > 1)
95662306a36Sopenharmony_ci		reg_len += REGTYPE_STR_LEN;
95762306a36Sopenharmony_ci
95862306a36Sopenharmony_ci	buf = vmalloc(reg_len);
95962306a36Sopenharmony_ci	if (!buf)
96062306a36Sopenharmony_ci		return -ENOMEM;
96162306a36Sopenharmony_ci
96262306a36Sopenharmony_ci	if (n_reg == 1) {
96362306a36Sopenharmony_ci		addr = ar->debug.dbgfs_diag_reg;
96462306a36Sopenharmony_ci
96562306a36Sopenharmony_ci		status = ath6kl_diag_read32(ar,
96662306a36Sopenharmony_ci				TARG_VTOP(ar->target_type, addr),
96762306a36Sopenharmony_ci				(u32 *)&reg_val);
96862306a36Sopenharmony_ci		if (status)
96962306a36Sopenharmony_ci			goto fail_reg_read;
97062306a36Sopenharmony_ci
97162306a36Sopenharmony_ci		len += scnprintf(buf + len, reg_len - len,
97262306a36Sopenharmony_ci				 "0x%06x 0x%08x\n", addr, le32_to_cpu(reg_val));
97362306a36Sopenharmony_ci		goto done;
97462306a36Sopenharmony_ci	}
97562306a36Sopenharmony_ci
97662306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(diag_reg); i++) {
97762306a36Sopenharmony_ci		len += scnprintf(buf + len, reg_len - len,
97862306a36Sopenharmony_ci				"%s\n", diag_reg[i].reg_info);
97962306a36Sopenharmony_ci		for (addr = diag_reg[i].reg_start;
98062306a36Sopenharmony_ci		     addr <= diag_reg[i].reg_end; addr += 4) {
98162306a36Sopenharmony_ci			status = ath6kl_diag_read32(ar,
98262306a36Sopenharmony_ci					TARG_VTOP(ar->target_type, addr),
98362306a36Sopenharmony_ci					(u32 *)&reg_val);
98462306a36Sopenharmony_ci			if (status)
98562306a36Sopenharmony_ci				goto fail_reg_read;
98662306a36Sopenharmony_ci
98762306a36Sopenharmony_ci			len += scnprintf(buf + len, reg_len - len,
98862306a36Sopenharmony_ci					"0x%06x 0x%08x\n",
98962306a36Sopenharmony_ci					addr, le32_to_cpu(reg_val));
99062306a36Sopenharmony_ci		}
99162306a36Sopenharmony_ci	}
99262306a36Sopenharmony_ci
99362306a36Sopenharmony_cidone:
99462306a36Sopenharmony_ci	file->private_data = buf;
99562306a36Sopenharmony_ci	return 0;
99662306a36Sopenharmony_ci
99762306a36Sopenharmony_cifail_reg_read:
99862306a36Sopenharmony_ci	ath6kl_warn("Unable to read memory:%u\n", addr);
99962306a36Sopenharmony_ci	vfree(buf);
100062306a36Sopenharmony_ci	return -EIO;
100162306a36Sopenharmony_ci}
100262306a36Sopenharmony_ci
100362306a36Sopenharmony_cistatic ssize_t ath6kl_regdump_read(struct file *file, char __user *user_buf,
100462306a36Sopenharmony_ci				  size_t count, loff_t *ppos)
100562306a36Sopenharmony_ci{
100662306a36Sopenharmony_ci	u8 *buf = file->private_data;
100762306a36Sopenharmony_ci	return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));
100862306a36Sopenharmony_ci}
100962306a36Sopenharmony_ci
101062306a36Sopenharmony_cistatic int ath6kl_regdump_release(struct inode *inode, struct file *file)
101162306a36Sopenharmony_ci{
101262306a36Sopenharmony_ci	vfree(file->private_data);
101362306a36Sopenharmony_ci	return 0;
101462306a36Sopenharmony_ci}
101562306a36Sopenharmony_ci
101662306a36Sopenharmony_cistatic const struct file_operations fops_reg_dump = {
101762306a36Sopenharmony_ci	.open = ath6kl_regdump_open,
101862306a36Sopenharmony_ci	.read = ath6kl_regdump_read,
101962306a36Sopenharmony_ci	.release = ath6kl_regdump_release,
102062306a36Sopenharmony_ci	.owner = THIS_MODULE,
102162306a36Sopenharmony_ci	.llseek = default_llseek,
102262306a36Sopenharmony_ci};
102362306a36Sopenharmony_ci
102462306a36Sopenharmony_cistatic ssize_t ath6kl_lrssi_roam_write(struct file *file,
102562306a36Sopenharmony_ci				       const char __user *user_buf,
102662306a36Sopenharmony_ci				       size_t count, loff_t *ppos)
102762306a36Sopenharmony_ci{
102862306a36Sopenharmony_ci	struct ath6kl *ar = file->private_data;
102962306a36Sopenharmony_ci	unsigned long lrssi_roam_threshold;
103062306a36Sopenharmony_ci	int ret;
103162306a36Sopenharmony_ci
103262306a36Sopenharmony_ci	if (kstrtoul_from_user(user_buf, count, 0, &lrssi_roam_threshold))
103362306a36Sopenharmony_ci		return -EINVAL;
103462306a36Sopenharmony_ci
103562306a36Sopenharmony_ci	ar->lrssi_roam_threshold = lrssi_roam_threshold;
103662306a36Sopenharmony_ci
103762306a36Sopenharmony_ci	ret = ath6kl_wmi_set_roam_lrssi_cmd(ar->wmi, ar->lrssi_roam_threshold);
103862306a36Sopenharmony_ci
103962306a36Sopenharmony_ci	if (ret)
104062306a36Sopenharmony_ci		return ret;
104162306a36Sopenharmony_ci	return count;
104262306a36Sopenharmony_ci}
104362306a36Sopenharmony_ci
104462306a36Sopenharmony_cistatic ssize_t ath6kl_lrssi_roam_read(struct file *file,
104562306a36Sopenharmony_ci				      char __user *user_buf,
104662306a36Sopenharmony_ci				      size_t count, loff_t *ppos)
104762306a36Sopenharmony_ci{
104862306a36Sopenharmony_ci	struct ath6kl *ar = file->private_data;
104962306a36Sopenharmony_ci	char buf[32];
105062306a36Sopenharmony_ci	unsigned int len;
105162306a36Sopenharmony_ci
105262306a36Sopenharmony_ci	len = snprintf(buf, sizeof(buf), "%u\n", ar->lrssi_roam_threshold);
105362306a36Sopenharmony_ci
105462306a36Sopenharmony_ci	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
105562306a36Sopenharmony_ci}
105662306a36Sopenharmony_ci
105762306a36Sopenharmony_cistatic const struct file_operations fops_lrssi_roam_threshold = {
105862306a36Sopenharmony_ci	.read = ath6kl_lrssi_roam_read,
105962306a36Sopenharmony_ci	.write = ath6kl_lrssi_roam_write,
106062306a36Sopenharmony_ci	.open = simple_open,
106162306a36Sopenharmony_ci	.owner = THIS_MODULE,
106262306a36Sopenharmony_ci	.llseek = default_llseek,
106362306a36Sopenharmony_ci};
106462306a36Sopenharmony_ci
106562306a36Sopenharmony_cistatic ssize_t ath6kl_regwrite_read(struct file *file,
106662306a36Sopenharmony_ci				    char __user *user_buf,
106762306a36Sopenharmony_ci				    size_t count, loff_t *ppos)
106862306a36Sopenharmony_ci{
106962306a36Sopenharmony_ci	struct ath6kl *ar = file->private_data;
107062306a36Sopenharmony_ci	u8 buf[32];
107162306a36Sopenharmony_ci	unsigned int len = 0;
107262306a36Sopenharmony_ci
107362306a36Sopenharmony_ci	len = scnprintf(buf, sizeof(buf), "Addr: 0x%x Val: 0x%x\n",
107462306a36Sopenharmony_ci			ar->debug.diag_reg_addr_wr, ar->debug.diag_reg_val_wr);
107562306a36Sopenharmony_ci
107662306a36Sopenharmony_ci	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
107762306a36Sopenharmony_ci}
107862306a36Sopenharmony_ci
107962306a36Sopenharmony_cistatic ssize_t ath6kl_regwrite_write(struct file *file,
108062306a36Sopenharmony_ci				     const char __user *user_buf,
108162306a36Sopenharmony_ci				     size_t count, loff_t *ppos)
108262306a36Sopenharmony_ci{
108362306a36Sopenharmony_ci	struct ath6kl *ar = file->private_data;
108462306a36Sopenharmony_ci	char buf[32];
108562306a36Sopenharmony_ci	char *sptr, *token;
108662306a36Sopenharmony_ci	unsigned int len = 0;
108762306a36Sopenharmony_ci	u32 reg_addr, reg_val;
108862306a36Sopenharmony_ci
108962306a36Sopenharmony_ci	len = min(count, sizeof(buf) - 1);
109062306a36Sopenharmony_ci	if (copy_from_user(buf, user_buf, len))
109162306a36Sopenharmony_ci		return -EFAULT;
109262306a36Sopenharmony_ci
109362306a36Sopenharmony_ci	buf[len] = '\0';
109462306a36Sopenharmony_ci	sptr = buf;
109562306a36Sopenharmony_ci
109662306a36Sopenharmony_ci	token = strsep(&sptr, "=");
109762306a36Sopenharmony_ci	if (!token)
109862306a36Sopenharmony_ci		return -EINVAL;
109962306a36Sopenharmony_ci
110062306a36Sopenharmony_ci	if (kstrtou32(token, 0, &reg_addr))
110162306a36Sopenharmony_ci		return -EINVAL;
110262306a36Sopenharmony_ci
110362306a36Sopenharmony_ci	if (!ath6kl_dbg_is_diag_reg_valid(reg_addr))
110462306a36Sopenharmony_ci		return -EINVAL;
110562306a36Sopenharmony_ci
110662306a36Sopenharmony_ci	if (kstrtou32(sptr, 0, &reg_val))
110762306a36Sopenharmony_ci		return -EINVAL;
110862306a36Sopenharmony_ci
110962306a36Sopenharmony_ci	ar->debug.diag_reg_addr_wr = reg_addr;
111062306a36Sopenharmony_ci	ar->debug.diag_reg_val_wr = reg_val;
111162306a36Sopenharmony_ci
111262306a36Sopenharmony_ci	if (ath6kl_diag_write32(ar, ar->debug.diag_reg_addr_wr,
111362306a36Sopenharmony_ci				cpu_to_le32(ar->debug.diag_reg_val_wr)))
111462306a36Sopenharmony_ci		return -EIO;
111562306a36Sopenharmony_ci
111662306a36Sopenharmony_ci	return count;
111762306a36Sopenharmony_ci}
111862306a36Sopenharmony_ci
111962306a36Sopenharmony_cistatic const struct file_operations fops_diag_reg_write = {
112062306a36Sopenharmony_ci	.read = ath6kl_regwrite_read,
112162306a36Sopenharmony_ci	.write = ath6kl_regwrite_write,
112262306a36Sopenharmony_ci	.open = simple_open,
112362306a36Sopenharmony_ci	.owner = THIS_MODULE,
112462306a36Sopenharmony_ci	.llseek = default_llseek,
112562306a36Sopenharmony_ci};
112662306a36Sopenharmony_ci
112762306a36Sopenharmony_ciint ath6kl_debug_roam_tbl_event(struct ath6kl *ar, const void *buf,
112862306a36Sopenharmony_ci				size_t len)
112962306a36Sopenharmony_ci{
113062306a36Sopenharmony_ci	const struct wmi_target_roam_tbl *tbl;
113162306a36Sopenharmony_ci	u16 num_entries;
113262306a36Sopenharmony_ci
113362306a36Sopenharmony_ci	if (len < sizeof(*tbl))
113462306a36Sopenharmony_ci		return -EINVAL;
113562306a36Sopenharmony_ci
113662306a36Sopenharmony_ci	tbl = (const struct wmi_target_roam_tbl *) buf;
113762306a36Sopenharmony_ci	num_entries = le16_to_cpu(tbl->num_entries);
113862306a36Sopenharmony_ci	if (struct_size(tbl, info, num_entries) > len)
113962306a36Sopenharmony_ci		return -EINVAL;
114062306a36Sopenharmony_ci
114162306a36Sopenharmony_ci	if (ar->debug.roam_tbl == NULL ||
114262306a36Sopenharmony_ci	    ar->debug.roam_tbl_len < (unsigned int) len) {
114362306a36Sopenharmony_ci		kfree(ar->debug.roam_tbl);
114462306a36Sopenharmony_ci		ar->debug.roam_tbl = kmalloc(len, GFP_ATOMIC);
114562306a36Sopenharmony_ci		if (ar->debug.roam_tbl == NULL)
114662306a36Sopenharmony_ci			return -ENOMEM;
114762306a36Sopenharmony_ci	}
114862306a36Sopenharmony_ci
114962306a36Sopenharmony_ci	memcpy(ar->debug.roam_tbl, buf, len);
115062306a36Sopenharmony_ci	ar->debug.roam_tbl_len = len;
115162306a36Sopenharmony_ci
115262306a36Sopenharmony_ci	if (test_bit(ROAM_TBL_PEND, &ar->flag)) {
115362306a36Sopenharmony_ci		clear_bit(ROAM_TBL_PEND, &ar->flag);
115462306a36Sopenharmony_ci		wake_up(&ar->event_wq);
115562306a36Sopenharmony_ci	}
115662306a36Sopenharmony_ci
115762306a36Sopenharmony_ci	return 0;
115862306a36Sopenharmony_ci}
115962306a36Sopenharmony_ci
116062306a36Sopenharmony_cistatic ssize_t ath6kl_roam_table_read(struct file *file, char __user *user_buf,
116162306a36Sopenharmony_ci				      size_t count, loff_t *ppos)
116262306a36Sopenharmony_ci{
116362306a36Sopenharmony_ci	struct ath6kl *ar = file->private_data;
116462306a36Sopenharmony_ci	int ret;
116562306a36Sopenharmony_ci	long left;
116662306a36Sopenharmony_ci	struct wmi_target_roam_tbl *tbl;
116762306a36Sopenharmony_ci	u16 num_entries, i;
116862306a36Sopenharmony_ci	char *buf;
116962306a36Sopenharmony_ci	unsigned int len, buf_len;
117062306a36Sopenharmony_ci	ssize_t ret_cnt;
117162306a36Sopenharmony_ci
117262306a36Sopenharmony_ci	if (down_interruptible(&ar->sem))
117362306a36Sopenharmony_ci		return -EBUSY;
117462306a36Sopenharmony_ci
117562306a36Sopenharmony_ci	set_bit(ROAM_TBL_PEND, &ar->flag);
117662306a36Sopenharmony_ci
117762306a36Sopenharmony_ci	ret = ath6kl_wmi_get_roam_tbl_cmd(ar->wmi);
117862306a36Sopenharmony_ci	if (ret) {
117962306a36Sopenharmony_ci		up(&ar->sem);
118062306a36Sopenharmony_ci		return ret;
118162306a36Sopenharmony_ci	}
118262306a36Sopenharmony_ci
118362306a36Sopenharmony_ci	left = wait_event_interruptible_timeout(
118462306a36Sopenharmony_ci		ar->event_wq, !test_bit(ROAM_TBL_PEND, &ar->flag), WMI_TIMEOUT);
118562306a36Sopenharmony_ci	up(&ar->sem);
118662306a36Sopenharmony_ci
118762306a36Sopenharmony_ci	if (left <= 0)
118862306a36Sopenharmony_ci		return -ETIMEDOUT;
118962306a36Sopenharmony_ci
119062306a36Sopenharmony_ci	if (ar->debug.roam_tbl == NULL)
119162306a36Sopenharmony_ci		return -ENOMEM;
119262306a36Sopenharmony_ci
119362306a36Sopenharmony_ci	tbl = (struct wmi_target_roam_tbl *) ar->debug.roam_tbl;
119462306a36Sopenharmony_ci	num_entries = le16_to_cpu(tbl->num_entries);
119562306a36Sopenharmony_ci
119662306a36Sopenharmony_ci	buf_len = 100 + num_entries * 100;
119762306a36Sopenharmony_ci	buf = kzalloc(buf_len, GFP_KERNEL);
119862306a36Sopenharmony_ci	if (buf == NULL)
119962306a36Sopenharmony_ci		return -ENOMEM;
120062306a36Sopenharmony_ci	len = 0;
120162306a36Sopenharmony_ci	len += scnprintf(buf + len, buf_len - len,
120262306a36Sopenharmony_ci			 "roam_mode=%u\n\n"
120362306a36Sopenharmony_ci			 "# roam_util bssid rssi rssidt last_rssi util bias\n",
120462306a36Sopenharmony_ci			 le16_to_cpu(tbl->roam_mode));
120562306a36Sopenharmony_ci
120662306a36Sopenharmony_ci	for (i = 0; i < num_entries; i++) {
120762306a36Sopenharmony_ci		struct wmi_bss_roam_info *info = &tbl->info[i];
120862306a36Sopenharmony_ci		len += scnprintf(buf + len, buf_len - len,
120962306a36Sopenharmony_ci				 "%d %pM %d %d %d %d %d\n",
121062306a36Sopenharmony_ci				 a_sle32_to_cpu(info->roam_util), info->bssid,
121162306a36Sopenharmony_ci				 info->rssi, info->rssidt, info->last_rssi,
121262306a36Sopenharmony_ci				 info->util, info->bias);
121362306a36Sopenharmony_ci	}
121462306a36Sopenharmony_ci
121562306a36Sopenharmony_ci	if (len > buf_len)
121662306a36Sopenharmony_ci		len = buf_len;
121762306a36Sopenharmony_ci
121862306a36Sopenharmony_ci	ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
121962306a36Sopenharmony_ci
122062306a36Sopenharmony_ci	kfree(buf);
122162306a36Sopenharmony_ci	return ret_cnt;
122262306a36Sopenharmony_ci}
122362306a36Sopenharmony_ci
122462306a36Sopenharmony_cistatic const struct file_operations fops_roam_table = {
122562306a36Sopenharmony_ci	.read = ath6kl_roam_table_read,
122662306a36Sopenharmony_ci	.open = simple_open,
122762306a36Sopenharmony_ci	.owner = THIS_MODULE,
122862306a36Sopenharmony_ci	.llseek = default_llseek,
122962306a36Sopenharmony_ci};
123062306a36Sopenharmony_ci
123162306a36Sopenharmony_cistatic ssize_t ath6kl_force_roam_write(struct file *file,
123262306a36Sopenharmony_ci				       const char __user *user_buf,
123362306a36Sopenharmony_ci				       size_t count, loff_t *ppos)
123462306a36Sopenharmony_ci{
123562306a36Sopenharmony_ci	struct ath6kl *ar = file->private_data;
123662306a36Sopenharmony_ci	int ret;
123762306a36Sopenharmony_ci	char buf[20];
123862306a36Sopenharmony_ci	size_t len;
123962306a36Sopenharmony_ci	u8 bssid[ETH_ALEN];
124062306a36Sopenharmony_ci
124162306a36Sopenharmony_ci	len = min(count, sizeof(buf) - 1);
124262306a36Sopenharmony_ci	if (copy_from_user(buf, user_buf, len))
124362306a36Sopenharmony_ci		return -EFAULT;
124462306a36Sopenharmony_ci	buf[len] = '\0';
124562306a36Sopenharmony_ci
124662306a36Sopenharmony_ci	if (!mac_pton(buf, bssid))
124762306a36Sopenharmony_ci		return -EINVAL;
124862306a36Sopenharmony_ci
124962306a36Sopenharmony_ci	ret = ath6kl_wmi_force_roam_cmd(ar->wmi, bssid);
125062306a36Sopenharmony_ci	if (ret)
125162306a36Sopenharmony_ci		return ret;
125262306a36Sopenharmony_ci
125362306a36Sopenharmony_ci	return count;
125462306a36Sopenharmony_ci}
125562306a36Sopenharmony_ci
125662306a36Sopenharmony_cistatic const struct file_operations fops_force_roam = {
125762306a36Sopenharmony_ci	.write = ath6kl_force_roam_write,
125862306a36Sopenharmony_ci	.open = simple_open,
125962306a36Sopenharmony_ci	.owner = THIS_MODULE,
126062306a36Sopenharmony_ci	.llseek = default_llseek,
126162306a36Sopenharmony_ci};
126262306a36Sopenharmony_ci
126362306a36Sopenharmony_cistatic ssize_t ath6kl_roam_mode_write(struct file *file,
126462306a36Sopenharmony_ci				      const char __user *user_buf,
126562306a36Sopenharmony_ci				      size_t count, loff_t *ppos)
126662306a36Sopenharmony_ci{
126762306a36Sopenharmony_ci	struct ath6kl *ar = file->private_data;
126862306a36Sopenharmony_ci	int ret;
126962306a36Sopenharmony_ci	char buf[20];
127062306a36Sopenharmony_ci	size_t len;
127162306a36Sopenharmony_ci	enum wmi_roam_mode mode;
127262306a36Sopenharmony_ci
127362306a36Sopenharmony_ci	len = min(count, sizeof(buf) - 1);
127462306a36Sopenharmony_ci	if (copy_from_user(buf, user_buf, len))
127562306a36Sopenharmony_ci		return -EFAULT;
127662306a36Sopenharmony_ci	buf[len] = '\0';
127762306a36Sopenharmony_ci	if (len > 0 && buf[len - 1] == '\n')
127862306a36Sopenharmony_ci		buf[len - 1] = '\0';
127962306a36Sopenharmony_ci
128062306a36Sopenharmony_ci	if (strcasecmp(buf, "default") == 0)
128162306a36Sopenharmony_ci		mode = WMI_DEFAULT_ROAM_MODE;
128262306a36Sopenharmony_ci	else if (strcasecmp(buf, "bssbias") == 0)
128362306a36Sopenharmony_ci		mode = WMI_HOST_BIAS_ROAM_MODE;
128462306a36Sopenharmony_ci	else if (strcasecmp(buf, "lock") == 0)
128562306a36Sopenharmony_ci		mode = WMI_LOCK_BSS_MODE;
128662306a36Sopenharmony_ci	else
128762306a36Sopenharmony_ci		return -EINVAL;
128862306a36Sopenharmony_ci
128962306a36Sopenharmony_ci	ret = ath6kl_wmi_set_roam_mode_cmd(ar->wmi, mode);
129062306a36Sopenharmony_ci	if (ret)
129162306a36Sopenharmony_ci		return ret;
129262306a36Sopenharmony_ci
129362306a36Sopenharmony_ci	return count;
129462306a36Sopenharmony_ci}
129562306a36Sopenharmony_ci
129662306a36Sopenharmony_cistatic const struct file_operations fops_roam_mode = {
129762306a36Sopenharmony_ci	.write = ath6kl_roam_mode_write,
129862306a36Sopenharmony_ci	.open = simple_open,
129962306a36Sopenharmony_ci	.owner = THIS_MODULE,
130062306a36Sopenharmony_ci	.llseek = default_llseek,
130162306a36Sopenharmony_ci};
130262306a36Sopenharmony_ci
130362306a36Sopenharmony_civoid ath6kl_debug_set_keepalive(struct ath6kl *ar, u8 keepalive)
130462306a36Sopenharmony_ci{
130562306a36Sopenharmony_ci	ar->debug.keepalive = keepalive;
130662306a36Sopenharmony_ci}
130762306a36Sopenharmony_ci
130862306a36Sopenharmony_cistatic ssize_t ath6kl_keepalive_read(struct file *file, char __user *user_buf,
130962306a36Sopenharmony_ci				     size_t count, loff_t *ppos)
131062306a36Sopenharmony_ci{
131162306a36Sopenharmony_ci	struct ath6kl *ar = file->private_data;
131262306a36Sopenharmony_ci	char buf[16];
131362306a36Sopenharmony_ci	int len;
131462306a36Sopenharmony_ci
131562306a36Sopenharmony_ci	len = snprintf(buf, sizeof(buf), "%u\n", ar->debug.keepalive);
131662306a36Sopenharmony_ci
131762306a36Sopenharmony_ci	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
131862306a36Sopenharmony_ci}
131962306a36Sopenharmony_ci
132062306a36Sopenharmony_cistatic ssize_t ath6kl_keepalive_write(struct file *file,
132162306a36Sopenharmony_ci				      const char __user *user_buf,
132262306a36Sopenharmony_ci				      size_t count, loff_t *ppos)
132362306a36Sopenharmony_ci{
132462306a36Sopenharmony_ci	struct ath6kl *ar = file->private_data;
132562306a36Sopenharmony_ci	int ret;
132662306a36Sopenharmony_ci	u8 val;
132762306a36Sopenharmony_ci
132862306a36Sopenharmony_ci	ret = kstrtou8_from_user(user_buf, count, 0, &val);
132962306a36Sopenharmony_ci	if (ret)
133062306a36Sopenharmony_ci		return ret;
133162306a36Sopenharmony_ci
133262306a36Sopenharmony_ci	ret = ath6kl_wmi_set_keepalive_cmd(ar->wmi, 0, val);
133362306a36Sopenharmony_ci	if (ret)
133462306a36Sopenharmony_ci		return ret;
133562306a36Sopenharmony_ci
133662306a36Sopenharmony_ci	return count;
133762306a36Sopenharmony_ci}
133862306a36Sopenharmony_ci
133962306a36Sopenharmony_cistatic const struct file_operations fops_keepalive = {
134062306a36Sopenharmony_ci	.open = simple_open,
134162306a36Sopenharmony_ci	.read = ath6kl_keepalive_read,
134262306a36Sopenharmony_ci	.write = ath6kl_keepalive_write,
134362306a36Sopenharmony_ci	.owner = THIS_MODULE,
134462306a36Sopenharmony_ci	.llseek = default_llseek,
134562306a36Sopenharmony_ci};
134662306a36Sopenharmony_ci
134762306a36Sopenharmony_civoid ath6kl_debug_set_disconnect_timeout(struct ath6kl *ar, u8 timeout)
134862306a36Sopenharmony_ci{
134962306a36Sopenharmony_ci	ar->debug.disc_timeout = timeout;
135062306a36Sopenharmony_ci}
135162306a36Sopenharmony_ci
135262306a36Sopenharmony_cistatic ssize_t ath6kl_disconnect_timeout_read(struct file *file,
135362306a36Sopenharmony_ci					      char __user *user_buf,
135462306a36Sopenharmony_ci					      size_t count, loff_t *ppos)
135562306a36Sopenharmony_ci{
135662306a36Sopenharmony_ci	struct ath6kl *ar = file->private_data;
135762306a36Sopenharmony_ci	char buf[16];
135862306a36Sopenharmony_ci	int len;
135962306a36Sopenharmony_ci
136062306a36Sopenharmony_ci	len = snprintf(buf, sizeof(buf), "%u\n", ar->debug.disc_timeout);
136162306a36Sopenharmony_ci
136262306a36Sopenharmony_ci	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
136362306a36Sopenharmony_ci}
136462306a36Sopenharmony_ci
136562306a36Sopenharmony_cistatic ssize_t ath6kl_disconnect_timeout_write(struct file *file,
136662306a36Sopenharmony_ci					       const char __user *user_buf,
136762306a36Sopenharmony_ci					       size_t count, loff_t *ppos)
136862306a36Sopenharmony_ci{
136962306a36Sopenharmony_ci	struct ath6kl *ar = file->private_data;
137062306a36Sopenharmony_ci	int ret;
137162306a36Sopenharmony_ci	u8 val;
137262306a36Sopenharmony_ci
137362306a36Sopenharmony_ci	ret = kstrtou8_from_user(user_buf, count, 0, &val);
137462306a36Sopenharmony_ci	if (ret)
137562306a36Sopenharmony_ci		return ret;
137662306a36Sopenharmony_ci
137762306a36Sopenharmony_ci	ret = ath6kl_wmi_disctimeout_cmd(ar->wmi, 0, val);
137862306a36Sopenharmony_ci	if (ret)
137962306a36Sopenharmony_ci		return ret;
138062306a36Sopenharmony_ci
138162306a36Sopenharmony_ci	return count;
138262306a36Sopenharmony_ci}
138362306a36Sopenharmony_ci
138462306a36Sopenharmony_cistatic const struct file_operations fops_disconnect_timeout = {
138562306a36Sopenharmony_ci	.open = simple_open,
138662306a36Sopenharmony_ci	.read = ath6kl_disconnect_timeout_read,
138762306a36Sopenharmony_ci	.write = ath6kl_disconnect_timeout_write,
138862306a36Sopenharmony_ci	.owner = THIS_MODULE,
138962306a36Sopenharmony_ci	.llseek = default_llseek,
139062306a36Sopenharmony_ci};
139162306a36Sopenharmony_ci
139262306a36Sopenharmony_cistatic ssize_t ath6kl_create_qos_write(struct file *file,
139362306a36Sopenharmony_ci						const char __user *user_buf,
139462306a36Sopenharmony_ci						size_t count, loff_t *ppos)
139562306a36Sopenharmony_ci{
139662306a36Sopenharmony_ci	struct ath6kl *ar = file->private_data;
139762306a36Sopenharmony_ci	struct ath6kl_vif *vif;
139862306a36Sopenharmony_ci	char buf[200];
139962306a36Sopenharmony_ci	ssize_t len;
140062306a36Sopenharmony_ci	char *sptr, *token;
140162306a36Sopenharmony_ci	struct wmi_create_pstream_cmd pstream;
140262306a36Sopenharmony_ci	u32 val32;
140362306a36Sopenharmony_ci	u16 val16;
140462306a36Sopenharmony_ci
140562306a36Sopenharmony_ci	vif = ath6kl_vif_first(ar);
140662306a36Sopenharmony_ci	if (!vif)
140762306a36Sopenharmony_ci		return -EIO;
140862306a36Sopenharmony_ci
140962306a36Sopenharmony_ci	len = min(count, sizeof(buf) - 1);
141062306a36Sopenharmony_ci	if (copy_from_user(buf, user_buf, len))
141162306a36Sopenharmony_ci		return -EFAULT;
141262306a36Sopenharmony_ci	buf[len] = '\0';
141362306a36Sopenharmony_ci	sptr = buf;
141462306a36Sopenharmony_ci
141562306a36Sopenharmony_ci	token = strsep(&sptr, " ");
141662306a36Sopenharmony_ci	if (!token)
141762306a36Sopenharmony_ci		return -EINVAL;
141862306a36Sopenharmony_ci	if (kstrtou8(token, 0, &pstream.user_pri))
141962306a36Sopenharmony_ci		return -EINVAL;
142062306a36Sopenharmony_ci
142162306a36Sopenharmony_ci	token = strsep(&sptr, " ");
142262306a36Sopenharmony_ci	if (!token)
142362306a36Sopenharmony_ci		return -EINVAL;
142462306a36Sopenharmony_ci	if (kstrtou8(token, 0, &pstream.traffic_direc))
142562306a36Sopenharmony_ci		return -EINVAL;
142662306a36Sopenharmony_ci
142762306a36Sopenharmony_ci	token = strsep(&sptr, " ");
142862306a36Sopenharmony_ci	if (!token)
142962306a36Sopenharmony_ci		return -EINVAL;
143062306a36Sopenharmony_ci	if (kstrtou8(token, 0, &pstream.traffic_class))
143162306a36Sopenharmony_ci		return -EINVAL;
143262306a36Sopenharmony_ci
143362306a36Sopenharmony_ci	token = strsep(&sptr, " ");
143462306a36Sopenharmony_ci	if (!token)
143562306a36Sopenharmony_ci		return -EINVAL;
143662306a36Sopenharmony_ci	if (kstrtou8(token, 0, &pstream.traffic_type))
143762306a36Sopenharmony_ci		return -EINVAL;
143862306a36Sopenharmony_ci
143962306a36Sopenharmony_ci	token = strsep(&sptr, " ");
144062306a36Sopenharmony_ci	if (!token)
144162306a36Sopenharmony_ci		return -EINVAL;
144262306a36Sopenharmony_ci	if (kstrtou8(token, 0, &pstream.voice_psc_cap))
144362306a36Sopenharmony_ci		return -EINVAL;
144462306a36Sopenharmony_ci
144562306a36Sopenharmony_ci	token = strsep(&sptr, " ");
144662306a36Sopenharmony_ci	if (!token)
144762306a36Sopenharmony_ci		return -EINVAL;
144862306a36Sopenharmony_ci	if (kstrtou32(token, 0, &val32))
144962306a36Sopenharmony_ci		return -EINVAL;
145062306a36Sopenharmony_ci	pstream.min_service_int = cpu_to_le32(val32);
145162306a36Sopenharmony_ci
145262306a36Sopenharmony_ci	token = strsep(&sptr, " ");
145362306a36Sopenharmony_ci	if (!token)
145462306a36Sopenharmony_ci		return -EINVAL;
145562306a36Sopenharmony_ci	if (kstrtou32(token, 0, &val32))
145662306a36Sopenharmony_ci		return -EINVAL;
145762306a36Sopenharmony_ci	pstream.max_service_int = cpu_to_le32(val32);
145862306a36Sopenharmony_ci
145962306a36Sopenharmony_ci	token = strsep(&sptr, " ");
146062306a36Sopenharmony_ci	if (!token)
146162306a36Sopenharmony_ci		return -EINVAL;
146262306a36Sopenharmony_ci	if (kstrtou32(token, 0, &val32))
146362306a36Sopenharmony_ci		return -EINVAL;
146462306a36Sopenharmony_ci	pstream.inactivity_int = cpu_to_le32(val32);
146562306a36Sopenharmony_ci
146662306a36Sopenharmony_ci	token = strsep(&sptr, " ");
146762306a36Sopenharmony_ci	if (!token)
146862306a36Sopenharmony_ci		return -EINVAL;
146962306a36Sopenharmony_ci	if (kstrtou32(token, 0, &val32))
147062306a36Sopenharmony_ci		return -EINVAL;
147162306a36Sopenharmony_ci	pstream.suspension_int = cpu_to_le32(val32);
147262306a36Sopenharmony_ci
147362306a36Sopenharmony_ci	token = strsep(&sptr, " ");
147462306a36Sopenharmony_ci	if (!token)
147562306a36Sopenharmony_ci		return -EINVAL;
147662306a36Sopenharmony_ci	if (kstrtou32(token, 0, &val32))
147762306a36Sopenharmony_ci		return -EINVAL;
147862306a36Sopenharmony_ci	pstream.service_start_time = cpu_to_le32(val32);
147962306a36Sopenharmony_ci
148062306a36Sopenharmony_ci	token = strsep(&sptr, " ");
148162306a36Sopenharmony_ci	if (!token)
148262306a36Sopenharmony_ci		return -EINVAL;
148362306a36Sopenharmony_ci	if (kstrtou8(token, 0, &pstream.tsid))
148462306a36Sopenharmony_ci		return -EINVAL;
148562306a36Sopenharmony_ci
148662306a36Sopenharmony_ci	token = strsep(&sptr, " ");
148762306a36Sopenharmony_ci	if (!token)
148862306a36Sopenharmony_ci		return -EINVAL;
148962306a36Sopenharmony_ci	if (kstrtou16(token, 0, &val16))
149062306a36Sopenharmony_ci		return -EINVAL;
149162306a36Sopenharmony_ci	pstream.nominal_msdu = cpu_to_le16(val16);
149262306a36Sopenharmony_ci
149362306a36Sopenharmony_ci	token = strsep(&sptr, " ");
149462306a36Sopenharmony_ci	if (!token)
149562306a36Sopenharmony_ci		return -EINVAL;
149662306a36Sopenharmony_ci	if (kstrtou16(token, 0, &val16))
149762306a36Sopenharmony_ci		return -EINVAL;
149862306a36Sopenharmony_ci	pstream.max_msdu = cpu_to_le16(val16);
149962306a36Sopenharmony_ci
150062306a36Sopenharmony_ci	token = strsep(&sptr, " ");
150162306a36Sopenharmony_ci	if (!token)
150262306a36Sopenharmony_ci		return -EINVAL;
150362306a36Sopenharmony_ci	if (kstrtou32(token, 0, &val32))
150462306a36Sopenharmony_ci		return -EINVAL;
150562306a36Sopenharmony_ci	pstream.min_data_rate = cpu_to_le32(val32);
150662306a36Sopenharmony_ci
150762306a36Sopenharmony_ci	token = strsep(&sptr, " ");
150862306a36Sopenharmony_ci	if (!token)
150962306a36Sopenharmony_ci		return -EINVAL;
151062306a36Sopenharmony_ci	if (kstrtou32(token, 0, &val32))
151162306a36Sopenharmony_ci		return -EINVAL;
151262306a36Sopenharmony_ci	pstream.mean_data_rate = cpu_to_le32(val32);
151362306a36Sopenharmony_ci
151462306a36Sopenharmony_ci	token = strsep(&sptr, " ");
151562306a36Sopenharmony_ci	if (!token)
151662306a36Sopenharmony_ci		return -EINVAL;
151762306a36Sopenharmony_ci	if (kstrtou32(token, 0, &val32))
151862306a36Sopenharmony_ci		return -EINVAL;
151962306a36Sopenharmony_ci	pstream.peak_data_rate = cpu_to_le32(val32);
152062306a36Sopenharmony_ci
152162306a36Sopenharmony_ci	token = strsep(&sptr, " ");
152262306a36Sopenharmony_ci	if (!token)
152362306a36Sopenharmony_ci		return -EINVAL;
152462306a36Sopenharmony_ci	if (kstrtou32(token, 0, &val32))
152562306a36Sopenharmony_ci		return -EINVAL;
152662306a36Sopenharmony_ci	pstream.max_burst_size = cpu_to_le32(val32);
152762306a36Sopenharmony_ci
152862306a36Sopenharmony_ci	token = strsep(&sptr, " ");
152962306a36Sopenharmony_ci	if (!token)
153062306a36Sopenharmony_ci		return -EINVAL;
153162306a36Sopenharmony_ci	if (kstrtou32(token, 0, &val32))
153262306a36Sopenharmony_ci		return -EINVAL;
153362306a36Sopenharmony_ci	pstream.delay_bound = cpu_to_le32(val32);
153462306a36Sopenharmony_ci
153562306a36Sopenharmony_ci	token = strsep(&sptr, " ");
153662306a36Sopenharmony_ci	if (!token)
153762306a36Sopenharmony_ci		return -EINVAL;
153862306a36Sopenharmony_ci	if (kstrtou32(token, 0, &val32))
153962306a36Sopenharmony_ci		return -EINVAL;
154062306a36Sopenharmony_ci	pstream.min_phy_rate = cpu_to_le32(val32);
154162306a36Sopenharmony_ci
154262306a36Sopenharmony_ci	token = strsep(&sptr, " ");
154362306a36Sopenharmony_ci	if (!token)
154462306a36Sopenharmony_ci		return -EINVAL;
154562306a36Sopenharmony_ci	if (kstrtou32(token, 0, &val32))
154662306a36Sopenharmony_ci		return -EINVAL;
154762306a36Sopenharmony_ci	pstream.sba = cpu_to_le32(val32);
154862306a36Sopenharmony_ci
154962306a36Sopenharmony_ci	token = strsep(&sptr, " ");
155062306a36Sopenharmony_ci	if (!token)
155162306a36Sopenharmony_ci		return -EINVAL;
155262306a36Sopenharmony_ci	if (kstrtou32(token, 0, &val32))
155362306a36Sopenharmony_ci		return -EINVAL;
155462306a36Sopenharmony_ci	pstream.medium_time = cpu_to_le32(val32);
155562306a36Sopenharmony_ci
155662306a36Sopenharmony_ci	pstream.nominal_phy = le32_to_cpu(pstream.min_phy_rate) / 1000000;
155762306a36Sopenharmony_ci
155862306a36Sopenharmony_ci	ath6kl_wmi_create_pstream_cmd(ar->wmi, vif->fw_vif_idx, &pstream);
155962306a36Sopenharmony_ci
156062306a36Sopenharmony_ci	return count;
156162306a36Sopenharmony_ci}
156262306a36Sopenharmony_ci
156362306a36Sopenharmony_cistatic const struct file_operations fops_create_qos = {
156462306a36Sopenharmony_ci	.write = ath6kl_create_qos_write,
156562306a36Sopenharmony_ci	.open = simple_open,
156662306a36Sopenharmony_ci	.owner = THIS_MODULE,
156762306a36Sopenharmony_ci	.llseek = default_llseek,
156862306a36Sopenharmony_ci};
156962306a36Sopenharmony_ci
157062306a36Sopenharmony_cistatic ssize_t ath6kl_delete_qos_write(struct file *file,
157162306a36Sopenharmony_ci				const char __user *user_buf,
157262306a36Sopenharmony_ci				size_t count, loff_t *ppos)
157362306a36Sopenharmony_ci{
157462306a36Sopenharmony_ci	struct ath6kl *ar = file->private_data;
157562306a36Sopenharmony_ci	struct ath6kl_vif *vif;
157662306a36Sopenharmony_ci	char buf[100];
157762306a36Sopenharmony_ci	ssize_t len;
157862306a36Sopenharmony_ci	char *sptr, *token;
157962306a36Sopenharmony_ci	u8 traffic_class;
158062306a36Sopenharmony_ci	u8 tsid;
158162306a36Sopenharmony_ci
158262306a36Sopenharmony_ci	vif = ath6kl_vif_first(ar);
158362306a36Sopenharmony_ci	if (!vif)
158462306a36Sopenharmony_ci		return -EIO;
158562306a36Sopenharmony_ci
158662306a36Sopenharmony_ci	len = min(count, sizeof(buf) - 1);
158762306a36Sopenharmony_ci	if (copy_from_user(buf, user_buf, len))
158862306a36Sopenharmony_ci		return -EFAULT;
158962306a36Sopenharmony_ci	buf[len] = '\0';
159062306a36Sopenharmony_ci	sptr = buf;
159162306a36Sopenharmony_ci
159262306a36Sopenharmony_ci	token = strsep(&sptr, " ");
159362306a36Sopenharmony_ci	if (!token)
159462306a36Sopenharmony_ci		return -EINVAL;
159562306a36Sopenharmony_ci	if (kstrtou8(token, 0, &traffic_class))
159662306a36Sopenharmony_ci		return -EINVAL;
159762306a36Sopenharmony_ci
159862306a36Sopenharmony_ci	token = strsep(&sptr, " ");
159962306a36Sopenharmony_ci	if (!token)
160062306a36Sopenharmony_ci		return -EINVAL;
160162306a36Sopenharmony_ci	if (kstrtou8(token, 0, &tsid))
160262306a36Sopenharmony_ci		return -EINVAL;
160362306a36Sopenharmony_ci
160462306a36Sopenharmony_ci	ath6kl_wmi_delete_pstream_cmd(ar->wmi, vif->fw_vif_idx,
160562306a36Sopenharmony_ci				      traffic_class, tsid);
160662306a36Sopenharmony_ci
160762306a36Sopenharmony_ci	return count;
160862306a36Sopenharmony_ci}
160962306a36Sopenharmony_ci
161062306a36Sopenharmony_cistatic const struct file_operations fops_delete_qos = {
161162306a36Sopenharmony_ci	.write = ath6kl_delete_qos_write,
161262306a36Sopenharmony_ci	.open = simple_open,
161362306a36Sopenharmony_ci	.owner = THIS_MODULE,
161462306a36Sopenharmony_ci	.llseek = default_llseek,
161562306a36Sopenharmony_ci};
161662306a36Sopenharmony_ci
161762306a36Sopenharmony_cistatic ssize_t ath6kl_bgscan_int_write(struct file *file,
161862306a36Sopenharmony_ci				const char __user *user_buf,
161962306a36Sopenharmony_ci				size_t count, loff_t *ppos)
162062306a36Sopenharmony_ci{
162162306a36Sopenharmony_ci	struct ath6kl *ar = file->private_data;
162262306a36Sopenharmony_ci	struct ath6kl_vif *vif;
162362306a36Sopenharmony_ci	u16 bgscan_int;
162462306a36Sopenharmony_ci	char buf[32];
162562306a36Sopenharmony_ci	ssize_t len;
162662306a36Sopenharmony_ci
162762306a36Sopenharmony_ci	vif = ath6kl_vif_first(ar);
162862306a36Sopenharmony_ci	if (!vif)
162962306a36Sopenharmony_ci		return -EIO;
163062306a36Sopenharmony_ci
163162306a36Sopenharmony_ci	len = min(count, sizeof(buf) - 1);
163262306a36Sopenharmony_ci	if (copy_from_user(buf, user_buf, len))
163362306a36Sopenharmony_ci		return -EFAULT;
163462306a36Sopenharmony_ci
163562306a36Sopenharmony_ci	buf[len] = '\0';
163662306a36Sopenharmony_ci	if (kstrtou16(buf, 0, &bgscan_int))
163762306a36Sopenharmony_ci		return -EINVAL;
163862306a36Sopenharmony_ci
163962306a36Sopenharmony_ci	if (bgscan_int == 0)
164062306a36Sopenharmony_ci		bgscan_int = 0xffff;
164162306a36Sopenharmony_ci
164262306a36Sopenharmony_ci	vif->bg_scan_period = bgscan_int;
164362306a36Sopenharmony_ci
164462306a36Sopenharmony_ci	ath6kl_wmi_scanparams_cmd(ar->wmi, 0, 0, 0, bgscan_int, 0, 0, 0, 3,
164562306a36Sopenharmony_ci				  0, 0, 0);
164662306a36Sopenharmony_ci
164762306a36Sopenharmony_ci	return count;
164862306a36Sopenharmony_ci}
164962306a36Sopenharmony_ci
165062306a36Sopenharmony_cistatic const struct file_operations fops_bgscan_int = {
165162306a36Sopenharmony_ci	.write = ath6kl_bgscan_int_write,
165262306a36Sopenharmony_ci	.open = simple_open,
165362306a36Sopenharmony_ci	.owner = THIS_MODULE,
165462306a36Sopenharmony_ci	.llseek = default_llseek,
165562306a36Sopenharmony_ci};
165662306a36Sopenharmony_ci
165762306a36Sopenharmony_cistatic ssize_t ath6kl_listen_int_write(struct file *file,
165862306a36Sopenharmony_ci				       const char __user *user_buf,
165962306a36Sopenharmony_ci				       size_t count, loff_t *ppos)
166062306a36Sopenharmony_ci{
166162306a36Sopenharmony_ci	struct ath6kl *ar = file->private_data;
166262306a36Sopenharmony_ci	struct ath6kl_vif *vif;
166362306a36Sopenharmony_ci	u16 listen_interval;
166462306a36Sopenharmony_ci	char buf[32];
166562306a36Sopenharmony_ci	ssize_t len;
166662306a36Sopenharmony_ci
166762306a36Sopenharmony_ci	vif = ath6kl_vif_first(ar);
166862306a36Sopenharmony_ci	if (!vif)
166962306a36Sopenharmony_ci		return -EIO;
167062306a36Sopenharmony_ci
167162306a36Sopenharmony_ci	len = min(count, sizeof(buf) - 1);
167262306a36Sopenharmony_ci	if (copy_from_user(buf, user_buf, len))
167362306a36Sopenharmony_ci		return -EFAULT;
167462306a36Sopenharmony_ci
167562306a36Sopenharmony_ci	buf[len] = '\0';
167662306a36Sopenharmony_ci	if (kstrtou16(buf, 0, &listen_interval))
167762306a36Sopenharmony_ci		return -EINVAL;
167862306a36Sopenharmony_ci
167962306a36Sopenharmony_ci	if ((listen_interval < 15) || (listen_interval > 3000))
168062306a36Sopenharmony_ci		return -EINVAL;
168162306a36Sopenharmony_ci
168262306a36Sopenharmony_ci	vif->listen_intvl_t = listen_interval;
168362306a36Sopenharmony_ci	ath6kl_wmi_listeninterval_cmd(ar->wmi, vif->fw_vif_idx,
168462306a36Sopenharmony_ci				      vif->listen_intvl_t, 0);
168562306a36Sopenharmony_ci
168662306a36Sopenharmony_ci	return count;
168762306a36Sopenharmony_ci}
168862306a36Sopenharmony_ci
168962306a36Sopenharmony_cistatic ssize_t ath6kl_listen_int_read(struct file *file,
169062306a36Sopenharmony_ci				      char __user *user_buf,
169162306a36Sopenharmony_ci				      size_t count, loff_t *ppos)
169262306a36Sopenharmony_ci{
169362306a36Sopenharmony_ci	struct ath6kl *ar = file->private_data;
169462306a36Sopenharmony_ci	struct ath6kl_vif *vif;
169562306a36Sopenharmony_ci	char buf[32];
169662306a36Sopenharmony_ci	int len;
169762306a36Sopenharmony_ci
169862306a36Sopenharmony_ci	vif = ath6kl_vif_first(ar);
169962306a36Sopenharmony_ci	if (!vif)
170062306a36Sopenharmony_ci		return -EIO;
170162306a36Sopenharmony_ci
170262306a36Sopenharmony_ci	len = scnprintf(buf, sizeof(buf), "%u\n", vif->listen_intvl_t);
170362306a36Sopenharmony_ci
170462306a36Sopenharmony_ci	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
170562306a36Sopenharmony_ci}
170662306a36Sopenharmony_ci
170762306a36Sopenharmony_cistatic const struct file_operations fops_listen_int = {
170862306a36Sopenharmony_ci	.read = ath6kl_listen_int_read,
170962306a36Sopenharmony_ci	.write = ath6kl_listen_int_write,
171062306a36Sopenharmony_ci	.open = simple_open,
171162306a36Sopenharmony_ci	.owner = THIS_MODULE,
171262306a36Sopenharmony_ci	.llseek = default_llseek,
171362306a36Sopenharmony_ci};
171462306a36Sopenharmony_ci
171562306a36Sopenharmony_cistatic ssize_t ath6kl_power_params_write(struct file *file,
171662306a36Sopenharmony_ci						const char __user *user_buf,
171762306a36Sopenharmony_ci						size_t count, loff_t *ppos)
171862306a36Sopenharmony_ci{
171962306a36Sopenharmony_ci	struct ath6kl *ar = file->private_data;
172062306a36Sopenharmony_ci	u8 buf[100];
172162306a36Sopenharmony_ci	unsigned int len = 0;
172262306a36Sopenharmony_ci	char *sptr, *token;
172362306a36Sopenharmony_ci	u16 idle_period, ps_poll_num, dtim,
172462306a36Sopenharmony_ci		tx_wakeup, num_tx;
172562306a36Sopenharmony_ci
172662306a36Sopenharmony_ci	len = min(count, sizeof(buf) - 1);
172762306a36Sopenharmony_ci	if (copy_from_user(buf, user_buf, len))
172862306a36Sopenharmony_ci		return -EFAULT;
172962306a36Sopenharmony_ci	buf[len] = '\0';
173062306a36Sopenharmony_ci	sptr = buf;
173162306a36Sopenharmony_ci
173262306a36Sopenharmony_ci	token = strsep(&sptr, " ");
173362306a36Sopenharmony_ci	if (!token)
173462306a36Sopenharmony_ci		return -EINVAL;
173562306a36Sopenharmony_ci	if (kstrtou16(token, 0, &idle_period))
173662306a36Sopenharmony_ci		return -EINVAL;
173762306a36Sopenharmony_ci
173862306a36Sopenharmony_ci	token = strsep(&sptr, " ");
173962306a36Sopenharmony_ci	if (!token)
174062306a36Sopenharmony_ci		return -EINVAL;
174162306a36Sopenharmony_ci	if (kstrtou16(token, 0, &ps_poll_num))
174262306a36Sopenharmony_ci		return -EINVAL;
174362306a36Sopenharmony_ci
174462306a36Sopenharmony_ci	token = strsep(&sptr, " ");
174562306a36Sopenharmony_ci	if (!token)
174662306a36Sopenharmony_ci		return -EINVAL;
174762306a36Sopenharmony_ci	if (kstrtou16(token, 0, &dtim))
174862306a36Sopenharmony_ci		return -EINVAL;
174962306a36Sopenharmony_ci
175062306a36Sopenharmony_ci	token = strsep(&sptr, " ");
175162306a36Sopenharmony_ci	if (!token)
175262306a36Sopenharmony_ci		return -EINVAL;
175362306a36Sopenharmony_ci	if (kstrtou16(token, 0, &tx_wakeup))
175462306a36Sopenharmony_ci		return -EINVAL;
175562306a36Sopenharmony_ci
175662306a36Sopenharmony_ci	token = strsep(&sptr, " ");
175762306a36Sopenharmony_ci	if (!token)
175862306a36Sopenharmony_ci		return -EINVAL;
175962306a36Sopenharmony_ci	if (kstrtou16(token, 0, &num_tx))
176062306a36Sopenharmony_ci		return -EINVAL;
176162306a36Sopenharmony_ci
176262306a36Sopenharmony_ci	ath6kl_wmi_pmparams_cmd(ar->wmi, 0, idle_period, ps_poll_num,
176362306a36Sopenharmony_ci				dtim, tx_wakeup, num_tx, 0);
176462306a36Sopenharmony_ci
176562306a36Sopenharmony_ci	return count;
176662306a36Sopenharmony_ci}
176762306a36Sopenharmony_ci
176862306a36Sopenharmony_cistatic const struct file_operations fops_power_params = {
176962306a36Sopenharmony_ci	.write = ath6kl_power_params_write,
177062306a36Sopenharmony_ci	.open = simple_open,
177162306a36Sopenharmony_ci	.owner = THIS_MODULE,
177262306a36Sopenharmony_ci	.llseek = default_llseek,
177362306a36Sopenharmony_ci};
177462306a36Sopenharmony_ci
177562306a36Sopenharmony_civoid ath6kl_debug_init(struct ath6kl *ar)
177662306a36Sopenharmony_ci{
177762306a36Sopenharmony_ci	skb_queue_head_init(&ar->debug.fwlog_queue);
177862306a36Sopenharmony_ci	init_completion(&ar->debug.fwlog_completion);
177962306a36Sopenharmony_ci
178062306a36Sopenharmony_ci	/*
178162306a36Sopenharmony_ci	 * Actually we are lying here but don't know how to read the mask
178262306a36Sopenharmony_ci	 * value from the firmware.
178362306a36Sopenharmony_ci	 */
178462306a36Sopenharmony_ci	ar->debug.fwlog_mask = 0;
178562306a36Sopenharmony_ci}
178662306a36Sopenharmony_ci
178762306a36Sopenharmony_ci/*
178862306a36Sopenharmony_ci * Initialisation needs to happen in two stages as fwlog events can come
178962306a36Sopenharmony_ci * before cfg80211 is initialised, and debugfs depends on cfg80211
179062306a36Sopenharmony_ci * initialisation.
179162306a36Sopenharmony_ci */
179262306a36Sopenharmony_ciint ath6kl_debug_init_fs(struct ath6kl *ar)
179362306a36Sopenharmony_ci{
179462306a36Sopenharmony_ci	ar->debugfs_phy = debugfs_create_dir("ath6kl",
179562306a36Sopenharmony_ci					     ar->wiphy->debugfsdir);
179662306a36Sopenharmony_ci
179762306a36Sopenharmony_ci	debugfs_create_file("tgt_stats", 0400, ar->debugfs_phy, ar,
179862306a36Sopenharmony_ci			    &fops_tgt_stats);
179962306a36Sopenharmony_ci
180062306a36Sopenharmony_ci	if (ar->hif_type == ATH6KL_HIF_TYPE_SDIO)
180162306a36Sopenharmony_ci		debugfs_create_file("credit_dist_stats", 0400,
180262306a36Sopenharmony_ci				    ar->debugfs_phy, ar,
180362306a36Sopenharmony_ci				    &fops_credit_dist_stats);
180462306a36Sopenharmony_ci
180562306a36Sopenharmony_ci	debugfs_create_file("endpoint_stats", 0600,
180662306a36Sopenharmony_ci			    ar->debugfs_phy, ar, &fops_endpoint_stats);
180762306a36Sopenharmony_ci
180862306a36Sopenharmony_ci	debugfs_create_file("fwlog", 0400, ar->debugfs_phy, ar, &fops_fwlog);
180962306a36Sopenharmony_ci
181062306a36Sopenharmony_ci	debugfs_create_file("fwlog_block", 0400, ar->debugfs_phy, ar,
181162306a36Sopenharmony_ci			    &fops_fwlog_block);
181262306a36Sopenharmony_ci
181362306a36Sopenharmony_ci	debugfs_create_file("fwlog_mask", 0600, ar->debugfs_phy,
181462306a36Sopenharmony_ci			    ar, &fops_fwlog_mask);
181562306a36Sopenharmony_ci
181662306a36Sopenharmony_ci	debugfs_create_file("reg_addr", 0600, ar->debugfs_phy, ar,
181762306a36Sopenharmony_ci			    &fops_diag_reg_read);
181862306a36Sopenharmony_ci
181962306a36Sopenharmony_ci	debugfs_create_file("reg_dump", 0400, ar->debugfs_phy, ar,
182062306a36Sopenharmony_ci			    &fops_reg_dump);
182162306a36Sopenharmony_ci
182262306a36Sopenharmony_ci	debugfs_create_file("lrssi_roam_threshold", 0600,
182362306a36Sopenharmony_ci			    ar->debugfs_phy, ar, &fops_lrssi_roam_threshold);
182462306a36Sopenharmony_ci
182562306a36Sopenharmony_ci	debugfs_create_file("reg_write", 0600,
182662306a36Sopenharmony_ci			    ar->debugfs_phy, ar, &fops_diag_reg_write);
182762306a36Sopenharmony_ci
182862306a36Sopenharmony_ci	debugfs_create_file("war_stats", 0400, ar->debugfs_phy, ar,
182962306a36Sopenharmony_ci			    &fops_war_stats);
183062306a36Sopenharmony_ci
183162306a36Sopenharmony_ci	debugfs_create_file("roam_table", 0400, ar->debugfs_phy, ar,
183262306a36Sopenharmony_ci			    &fops_roam_table);
183362306a36Sopenharmony_ci
183462306a36Sopenharmony_ci	debugfs_create_file("force_roam", 0200, ar->debugfs_phy, ar,
183562306a36Sopenharmony_ci			    &fops_force_roam);
183662306a36Sopenharmony_ci
183762306a36Sopenharmony_ci	debugfs_create_file("roam_mode", 0200, ar->debugfs_phy, ar,
183862306a36Sopenharmony_ci			    &fops_roam_mode);
183962306a36Sopenharmony_ci
184062306a36Sopenharmony_ci	debugfs_create_file("keepalive", 0600, ar->debugfs_phy, ar,
184162306a36Sopenharmony_ci			    &fops_keepalive);
184262306a36Sopenharmony_ci
184362306a36Sopenharmony_ci	debugfs_create_file("disconnect_timeout", 0600,
184462306a36Sopenharmony_ci			    ar->debugfs_phy, ar, &fops_disconnect_timeout);
184562306a36Sopenharmony_ci
184662306a36Sopenharmony_ci	debugfs_create_file("create_qos", 0200, ar->debugfs_phy, ar,
184762306a36Sopenharmony_ci			    &fops_create_qos);
184862306a36Sopenharmony_ci
184962306a36Sopenharmony_ci	debugfs_create_file("delete_qos", 0200, ar->debugfs_phy, ar,
185062306a36Sopenharmony_ci			    &fops_delete_qos);
185162306a36Sopenharmony_ci
185262306a36Sopenharmony_ci	debugfs_create_file("bgscan_interval", 0200,
185362306a36Sopenharmony_ci			    ar->debugfs_phy, ar, &fops_bgscan_int);
185462306a36Sopenharmony_ci
185562306a36Sopenharmony_ci	debugfs_create_file("listen_interval", 0600,
185662306a36Sopenharmony_ci			    ar->debugfs_phy, ar, &fops_listen_int);
185762306a36Sopenharmony_ci
185862306a36Sopenharmony_ci	debugfs_create_file("power_params", 0200, ar->debugfs_phy, ar,
185962306a36Sopenharmony_ci			    &fops_power_params);
186062306a36Sopenharmony_ci
186162306a36Sopenharmony_ci	return 0;
186262306a36Sopenharmony_ci}
186362306a36Sopenharmony_ci
186462306a36Sopenharmony_civoid ath6kl_debug_cleanup(struct ath6kl *ar)
186562306a36Sopenharmony_ci{
186662306a36Sopenharmony_ci	skb_queue_purge(&ar->debug.fwlog_queue);
186762306a36Sopenharmony_ci	complete(&ar->debug.fwlog_completion);
186862306a36Sopenharmony_ci	kfree(ar->debug.roam_tbl);
186962306a36Sopenharmony_ci}
187062306a36Sopenharmony_ci
187162306a36Sopenharmony_ci#endif
1872