162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * Copyright (c) 2007-2008 Bruno Randolf <bruno@thinktube.com>
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci *  This file is free software: you may copy, redistribute and/or modify it
562306a36Sopenharmony_ci *  under the terms of the GNU General Public License as published by the
662306a36Sopenharmony_ci *  Free Software Foundation, either version 2 of the License, or (at your
762306a36Sopenharmony_ci *  option) any later version.
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci *  This file is distributed in the hope that it will be useful, but
1062306a36Sopenharmony_ci *  WITHOUT ANY WARRANTY; without even the implied warranty of
1162306a36Sopenharmony_ci *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1262306a36Sopenharmony_ci *  General Public License for more details.
1362306a36Sopenharmony_ci *
1462306a36Sopenharmony_ci *  You should have received a copy of the GNU General Public License
1562306a36Sopenharmony_ci *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
1662306a36Sopenharmony_ci *
1762306a36Sopenharmony_ci *
1862306a36Sopenharmony_ci * This file incorporates work covered by the following copyright and
1962306a36Sopenharmony_ci * permission notice:
2062306a36Sopenharmony_ci *
2162306a36Sopenharmony_ci * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
2262306a36Sopenharmony_ci * Copyright (c) 2004-2005 Atheros Communications, Inc.
2362306a36Sopenharmony_ci * Copyright (c) 2006 Devicescape Software, Inc.
2462306a36Sopenharmony_ci * Copyright (c) 2007 Jiri Slaby <jirislaby@gmail.com>
2562306a36Sopenharmony_ci * Copyright (c) 2007 Luis R. Rodriguez <mcgrof@winlab.rutgers.edu>
2662306a36Sopenharmony_ci *
2762306a36Sopenharmony_ci * All rights reserved.
2862306a36Sopenharmony_ci *
2962306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or without
3062306a36Sopenharmony_ci * modification, are permitted provided that the following conditions
3162306a36Sopenharmony_ci * are met:
3262306a36Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright
3362306a36Sopenharmony_ci *    notice, this list of conditions and the following disclaimer,
3462306a36Sopenharmony_ci *    without modification.
3562306a36Sopenharmony_ci * 2. Redistributions in binary form must reproduce at minimum a disclaimer
3662306a36Sopenharmony_ci *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
3762306a36Sopenharmony_ci *    redistribution must be conditioned upon including a substantially
3862306a36Sopenharmony_ci *    similar Disclaimer requirement for further binary redistribution.
3962306a36Sopenharmony_ci * 3. Neither the names of the above-listed copyright holders nor the names
4062306a36Sopenharmony_ci *    of any contributors may be used to endorse or promote products derived
4162306a36Sopenharmony_ci *    from this software without specific prior written permission.
4262306a36Sopenharmony_ci *
4362306a36Sopenharmony_ci * Alternatively, this software may be distributed under the terms of the
4462306a36Sopenharmony_ci * GNU General Public License ("GPL") version 2 as published by the Free
4562306a36Sopenharmony_ci * Software Foundation.
4662306a36Sopenharmony_ci *
4762306a36Sopenharmony_ci * NO WARRANTY
4862306a36Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4962306a36Sopenharmony_ci * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5062306a36Sopenharmony_ci * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
5162306a36Sopenharmony_ci * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
5262306a36Sopenharmony_ci * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
5362306a36Sopenharmony_ci * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
5462306a36Sopenharmony_ci * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
5562306a36Sopenharmony_ci * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
5662306a36Sopenharmony_ci * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
5762306a36Sopenharmony_ci * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
5862306a36Sopenharmony_ci * THE POSSIBILITY OF SUCH DAMAGES.
5962306a36Sopenharmony_ci */
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci#include <linux/export.h>
6462306a36Sopenharmony_ci#include <linux/moduleparam.h>
6562306a36Sopenharmony_ci#include <linux/vmalloc.h>
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci#include <linux/seq_file.h>
6862306a36Sopenharmony_ci#include <linux/list.h>
6962306a36Sopenharmony_ci#include "debug.h"
7062306a36Sopenharmony_ci#include "ath5k.h"
7162306a36Sopenharmony_ci#include "reg.h"
7262306a36Sopenharmony_ci#include "base.h"
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_cistatic unsigned int ath5k_debug;
7562306a36Sopenharmony_cimodule_param_named(debug, ath5k_debug, uint, 0);
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci/* debugfs: registers */
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_cistruct reg {
8162306a36Sopenharmony_ci	const char *name;
8262306a36Sopenharmony_ci	int addr;
8362306a36Sopenharmony_ci};
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci#define REG_STRUCT_INIT(r) { #r, r }
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci/* just a few random registers, might want to add more */
8862306a36Sopenharmony_cistatic const struct reg regs[] = {
8962306a36Sopenharmony_ci	REG_STRUCT_INIT(AR5K_CR),
9062306a36Sopenharmony_ci	REG_STRUCT_INIT(AR5K_RXDP),
9162306a36Sopenharmony_ci	REG_STRUCT_INIT(AR5K_CFG),
9262306a36Sopenharmony_ci	REG_STRUCT_INIT(AR5K_IER),
9362306a36Sopenharmony_ci	REG_STRUCT_INIT(AR5K_BCR),
9462306a36Sopenharmony_ci	REG_STRUCT_INIT(AR5K_RTSD0),
9562306a36Sopenharmony_ci	REG_STRUCT_INIT(AR5K_RTSD1),
9662306a36Sopenharmony_ci	REG_STRUCT_INIT(AR5K_TXCFG),
9762306a36Sopenharmony_ci	REG_STRUCT_INIT(AR5K_RXCFG),
9862306a36Sopenharmony_ci	REG_STRUCT_INIT(AR5K_RXJLA),
9962306a36Sopenharmony_ci	REG_STRUCT_INIT(AR5K_MIBC),
10062306a36Sopenharmony_ci	REG_STRUCT_INIT(AR5K_TOPS),
10162306a36Sopenharmony_ci	REG_STRUCT_INIT(AR5K_RXNOFRM),
10262306a36Sopenharmony_ci	REG_STRUCT_INIT(AR5K_TXNOFRM),
10362306a36Sopenharmony_ci	REG_STRUCT_INIT(AR5K_RPGTO),
10462306a36Sopenharmony_ci	REG_STRUCT_INIT(AR5K_RFCNT),
10562306a36Sopenharmony_ci	REG_STRUCT_INIT(AR5K_MISC),
10662306a36Sopenharmony_ci	REG_STRUCT_INIT(AR5K_QCUDCU_CLKGT),
10762306a36Sopenharmony_ci	REG_STRUCT_INIT(AR5K_ISR),
10862306a36Sopenharmony_ci	REG_STRUCT_INIT(AR5K_PISR),
10962306a36Sopenharmony_ci	REG_STRUCT_INIT(AR5K_SISR0),
11062306a36Sopenharmony_ci	REG_STRUCT_INIT(AR5K_SISR1),
11162306a36Sopenharmony_ci	REG_STRUCT_INIT(AR5K_SISR2),
11262306a36Sopenharmony_ci	REG_STRUCT_INIT(AR5K_SISR3),
11362306a36Sopenharmony_ci	REG_STRUCT_INIT(AR5K_SISR4),
11462306a36Sopenharmony_ci	REG_STRUCT_INIT(AR5K_IMR),
11562306a36Sopenharmony_ci	REG_STRUCT_INIT(AR5K_PIMR),
11662306a36Sopenharmony_ci	REG_STRUCT_INIT(AR5K_SIMR0),
11762306a36Sopenharmony_ci	REG_STRUCT_INIT(AR5K_SIMR1),
11862306a36Sopenharmony_ci	REG_STRUCT_INIT(AR5K_SIMR2),
11962306a36Sopenharmony_ci	REG_STRUCT_INIT(AR5K_SIMR3),
12062306a36Sopenharmony_ci	REG_STRUCT_INIT(AR5K_SIMR4),
12162306a36Sopenharmony_ci	REG_STRUCT_INIT(AR5K_DCM_ADDR),
12262306a36Sopenharmony_ci	REG_STRUCT_INIT(AR5K_DCCFG),
12362306a36Sopenharmony_ci	REG_STRUCT_INIT(AR5K_CCFG),
12462306a36Sopenharmony_ci	REG_STRUCT_INIT(AR5K_CPC0),
12562306a36Sopenharmony_ci	REG_STRUCT_INIT(AR5K_CPC1),
12662306a36Sopenharmony_ci	REG_STRUCT_INIT(AR5K_CPC2),
12762306a36Sopenharmony_ci	REG_STRUCT_INIT(AR5K_CPC3),
12862306a36Sopenharmony_ci	REG_STRUCT_INIT(AR5K_CPCOVF),
12962306a36Sopenharmony_ci	REG_STRUCT_INIT(AR5K_RESET_CTL),
13062306a36Sopenharmony_ci	REG_STRUCT_INIT(AR5K_SLEEP_CTL),
13162306a36Sopenharmony_ci	REG_STRUCT_INIT(AR5K_INTPEND),
13262306a36Sopenharmony_ci	REG_STRUCT_INIT(AR5K_SFR),
13362306a36Sopenharmony_ci	REG_STRUCT_INIT(AR5K_PCICFG),
13462306a36Sopenharmony_ci	REG_STRUCT_INIT(AR5K_GPIOCR),
13562306a36Sopenharmony_ci	REG_STRUCT_INIT(AR5K_GPIODO),
13662306a36Sopenharmony_ci	REG_STRUCT_INIT(AR5K_SREV),
13762306a36Sopenharmony_ci};
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_cistatic void *reg_start(struct seq_file *seq, loff_t *pos)
14062306a36Sopenharmony_ci{
14162306a36Sopenharmony_ci	return *pos < ARRAY_SIZE(regs) ? (void *)&regs[*pos] : NULL;
14262306a36Sopenharmony_ci}
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_cistatic void reg_stop(struct seq_file *seq, void *p)
14562306a36Sopenharmony_ci{
14662306a36Sopenharmony_ci	/* nothing to do */
14762306a36Sopenharmony_ci}
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_cistatic void *reg_next(struct seq_file *seq, void *p, loff_t *pos)
15062306a36Sopenharmony_ci{
15162306a36Sopenharmony_ci	++*pos;
15262306a36Sopenharmony_ci	return *pos < ARRAY_SIZE(regs) ? (void *)&regs[*pos] : NULL;
15362306a36Sopenharmony_ci}
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_cistatic int reg_show(struct seq_file *seq, void *p)
15662306a36Sopenharmony_ci{
15762306a36Sopenharmony_ci	struct ath5k_hw *ah = seq->private;
15862306a36Sopenharmony_ci	struct reg *r = p;
15962306a36Sopenharmony_ci	seq_printf(seq, "%-25s0x%08x\n", r->name,
16062306a36Sopenharmony_ci		ath5k_hw_reg_read(ah, r->addr));
16162306a36Sopenharmony_ci	return 0;
16262306a36Sopenharmony_ci}
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_cistatic const struct seq_operations registers_sops = {
16562306a36Sopenharmony_ci	.start = reg_start,
16662306a36Sopenharmony_ci	.next  = reg_next,
16762306a36Sopenharmony_ci	.stop  = reg_stop,
16862306a36Sopenharmony_ci	.show  = reg_show
16962306a36Sopenharmony_ci};
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ciDEFINE_SEQ_ATTRIBUTE(registers);
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci/* debugfs: beacons */
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_cistatic ssize_t read_file_beacon(struct file *file, char __user *user_buf,
17662306a36Sopenharmony_ci				   size_t count, loff_t *ppos)
17762306a36Sopenharmony_ci{
17862306a36Sopenharmony_ci	struct ath5k_hw *ah = file->private_data;
17962306a36Sopenharmony_ci	char buf[500];
18062306a36Sopenharmony_ci	unsigned int len = 0;
18162306a36Sopenharmony_ci	unsigned int v;
18262306a36Sopenharmony_ci	u64 tsf;
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	v = ath5k_hw_reg_read(ah, AR5K_BEACON);
18562306a36Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len,
18662306a36Sopenharmony_ci		"%-24s0x%08x\tintval: %d\tTIM: 0x%x\n",
18762306a36Sopenharmony_ci		"AR5K_BEACON", v, v & AR5K_BEACON_PERIOD,
18862306a36Sopenharmony_ci		(v & AR5K_BEACON_TIM) >> AR5K_BEACON_TIM_S);
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len, "%-24s0x%08x\n",
19162306a36Sopenharmony_ci		"AR5K_LAST_TSTP", ath5k_hw_reg_read(ah, AR5K_LAST_TSTP));
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len, "%-24s0x%08x\n\n",
19462306a36Sopenharmony_ci		"AR5K_BEACON_CNT", ath5k_hw_reg_read(ah, AR5K_BEACON_CNT));
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	v = ath5k_hw_reg_read(ah, AR5K_TIMER0);
19762306a36Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len, "%-24s0x%08x\tTU: %08x\n",
19862306a36Sopenharmony_ci		"AR5K_TIMER0 (TBTT)", v, v);
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	v = ath5k_hw_reg_read(ah, AR5K_TIMER1);
20162306a36Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len, "%-24s0x%08x\tTU: %08x\n",
20262306a36Sopenharmony_ci		"AR5K_TIMER1 (DMA)", v, v >> 3);
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	v = ath5k_hw_reg_read(ah, AR5K_TIMER2);
20562306a36Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len, "%-24s0x%08x\tTU: %08x\n",
20662306a36Sopenharmony_ci		"AR5K_TIMER2 (SWBA)", v, v >> 3);
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	v = ath5k_hw_reg_read(ah, AR5K_TIMER3);
20962306a36Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len, "%-24s0x%08x\tTU: %08x\n",
21062306a36Sopenharmony_ci		"AR5K_TIMER3 (ATIM)", v, v);
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	tsf = ath5k_hw_get_tsf64(ah);
21362306a36Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len,
21462306a36Sopenharmony_ci		"TSF\t\t0x%016llx\tTU: %08x\n",
21562306a36Sopenharmony_ci		(unsigned long long)tsf, TSF_TO_TU(tsf));
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci	if (len > sizeof(buf))
21862306a36Sopenharmony_ci		len = sizeof(buf);
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
22162306a36Sopenharmony_ci}
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_cistatic ssize_t write_file_beacon(struct file *file,
22462306a36Sopenharmony_ci				 const char __user *userbuf,
22562306a36Sopenharmony_ci				 size_t count, loff_t *ppos)
22662306a36Sopenharmony_ci{
22762306a36Sopenharmony_ci	struct ath5k_hw *ah = file->private_data;
22862306a36Sopenharmony_ci	char buf[20];
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci	count = min_t(size_t, count, sizeof(buf) - 1);
23162306a36Sopenharmony_ci	if (copy_from_user(buf, userbuf, count))
23262306a36Sopenharmony_ci		return -EFAULT;
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	buf[count] = '\0';
23562306a36Sopenharmony_ci	if (strncmp(buf, "disable", 7) == 0) {
23662306a36Sopenharmony_ci		AR5K_REG_DISABLE_BITS(ah, AR5K_BEACON, AR5K_BEACON_ENABLE);
23762306a36Sopenharmony_ci		pr_info("debugfs disable beacons\n");
23862306a36Sopenharmony_ci	} else if (strncmp(buf, "enable", 6) == 0) {
23962306a36Sopenharmony_ci		AR5K_REG_ENABLE_BITS(ah, AR5K_BEACON, AR5K_BEACON_ENABLE);
24062306a36Sopenharmony_ci		pr_info("debugfs enable beacons\n");
24162306a36Sopenharmony_ci	}
24262306a36Sopenharmony_ci	return count;
24362306a36Sopenharmony_ci}
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_cistatic const struct file_operations fops_beacon = {
24662306a36Sopenharmony_ci	.read = read_file_beacon,
24762306a36Sopenharmony_ci	.write = write_file_beacon,
24862306a36Sopenharmony_ci	.open = simple_open,
24962306a36Sopenharmony_ci	.owner = THIS_MODULE,
25062306a36Sopenharmony_ci	.llseek = default_llseek,
25162306a36Sopenharmony_ci};
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci/* debugfs: reset */
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_cistatic ssize_t write_file_reset(struct file *file,
25762306a36Sopenharmony_ci				 const char __user *userbuf,
25862306a36Sopenharmony_ci				 size_t count, loff_t *ppos)
25962306a36Sopenharmony_ci{
26062306a36Sopenharmony_ci	struct ath5k_hw *ah = file->private_data;
26162306a36Sopenharmony_ci	ATH5K_DBG(ah, ATH5K_DEBUG_RESET, "debug file triggered reset\n");
26262306a36Sopenharmony_ci	ieee80211_queue_work(ah->hw, &ah->reset_work);
26362306a36Sopenharmony_ci	return count;
26462306a36Sopenharmony_ci}
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_cistatic const struct file_operations fops_reset = {
26762306a36Sopenharmony_ci	.write = write_file_reset,
26862306a36Sopenharmony_ci	.open = simple_open,
26962306a36Sopenharmony_ci	.owner = THIS_MODULE,
27062306a36Sopenharmony_ci	.llseek = noop_llseek,
27162306a36Sopenharmony_ci};
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci/* debugfs: debug level */
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_cistatic const struct {
27762306a36Sopenharmony_ci	enum ath5k_debug_level level;
27862306a36Sopenharmony_ci	const char *name;
27962306a36Sopenharmony_ci	const char *desc;
28062306a36Sopenharmony_ci} dbg_info[] = {
28162306a36Sopenharmony_ci	{ ATH5K_DEBUG_RESET,	"reset",	"reset and initialization" },
28262306a36Sopenharmony_ci	{ ATH5K_DEBUG_INTR,	"intr",		"interrupt handling" },
28362306a36Sopenharmony_ci	{ ATH5K_DEBUG_MODE,	"mode",		"mode init/setup" },
28462306a36Sopenharmony_ci	{ ATH5K_DEBUG_XMIT,	"xmit",		"basic xmit operation" },
28562306a36Sopenharmony_ci	{ ATH5K_DEBUG_BEACON,	"beacon",	"beacon handling" },
28662306a36Sopenharmony_ci	{ ATH5K_DEBUG_CALIBRATE, "calib",	"periodic calibration" },
28762306a36Sopenharmony_ci	{ ATH5K_DEBUG_TXPOWER,	"txpower",	"transmit power setting" },
28862306a36Sopenharmony_ci	{ ATH5K_DEBUG_LED,	"led",		"LED management" },
28962306a36Sopenharmony_ci	{ ATH5K_DEBUG_DUMPBANDS, "dumpbands",	"dump bands" },
29062306a36Sopenharmony_ci	{ ATH5K_DEBUG_DMA,	"dma",		"dma start/stop" },
29162306a36Sopenharmony_ci	{ ATH5K_DEBUG_ANI,	"ani",		"adaptive noise immunity" },
29262306a36Sopenharmony_ci	{ ATH5K_DEBUG_DESC,	"desc",		"descriptor chains" },
29362306a36Sopenharmony_ci	{ ATH5K_DEBUG_ANY,	"all",		"show all debug levels" },
29462306a36Sopenharmony_ci};
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_cistatic ssize_t read_file_debug(struct file *file, char __user *user_buf,
29762306a36Sopenharmony_ci				   size_t count, loff_t *ppos)
29862306a36Sopenharmony_ci{
29962306a36Sopenharmony_ci	struct ath5k_hw *ah = file->private_data;
30062306a36Sopenharmony_ci	char buf[700];
30162306a36Sopenharmony_ci	unsigned int len = 0;
30262306a36Sopenharmony_ci	unsigned int i;
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len,
30562306a36Sopenharmony_ci		"DEBUG LEVEL: 0x%08x\n\n", ah->debug.level);
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(dbg_info) - 1; i++) {
30862306a36Sopenharmony_ci		len += scnprintf(buf + len, sizeof(buf) - len,
30962306a36Sopenharmony_ci			"%10s %c 0x%08x - %s\n", dbg_info[i].name,
31062306a36Sopenharmony_ci			ah->debug.level & dbg_info[i].level ? '+' : ' ',
31162306a36Sopenharmony_ci			dbg_info[i].level, dbg_info[i].desc);
31262306a36Sopenharmony_ci	}
31362306a36Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len,
31462306a36Sopenharmony_ci		"%10s %c 0x%08x - %s\n", dbg_info[i].name,
31562306a36Sopenharmony_ci		ah->debug.level == dbg_info[i].level ? '+' : ' ',
31662306a36Sopenharmony_ci		dbg_info[i].level, dbg_info[i].desc);
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	if (len > sizeof(buf))
31962306a36Sopenharmony_ci		len = sizeof(buf);
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
32262306a36Sopenharmony_ci}
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_cistatic ssize_t write_file_debug(struct file *file,
32562306a36Sopenharmony_ci				 const char __user *userbuf,
32662306a36Sopenharmony_ci				 size_t count, loff_t *ppos)
32762306a36Sopenharmony_ci{
32862306a36Sopenharmony_ci	struct ath5k_hw *ah = file->private_data;
32962306a36Sopenharmony_ci	unsigned int i;
33062306a36Sopenharmony_ci	char buf[20];
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	count = min_t(size_t, count, sizeof(buf) - 1);
33362306a36Sopenharmony_ci	if (copy_from_user(buf, userbuf, count))
33462306a36Sopenharmony_ci		return -EFAULT;
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	buf[count] = '\0';
33762306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(dbg_info); i++) {
33862306a36Sopenharmony_ci		if (strncmp(buf, dbg_info[i].name,
33962306a36Sopenharmony_ci					strlen(dbg_info[i].name)) == 0) {
34062306a36Sopenharmony_ci			ah->debug.level ^= dbg_info[i].level; /* toggle bit */
34162306a36Sopenharmony_ci			break;
34262306a36Sopenharmony_ci		}
34362306a36Sopenharmony_ci	}
34462306a36Sopenharmony_ci	return count;
34562306a36Sopenharmony_ci}
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_cistatic const struct file_operations fops_debug = {
34862306a36Sopenharmony_ci	.read = read_file_debug,
34962306a36Sopenharmony_ci	.write = write_file_debug,
35062306a36Sopenharmony_ci	.open = simple_open,
35162306a36Sopenharmony_ci	.owner = THIS_MODULE,
35262306a36Sopenharmony_ci	.llseek = default_llseek,
35362306a36Sopenharmony_ci};
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci/* debugfs: antenna */
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_cistatic ssize_t read_file_antenna(struct file *file, char __user *user_buf,
35962306a36Sopenharmony_ci				   size_t count, loff_t *ppos)
36062306a36Sopenharmony_ci{
36162306a36Sopenharmony_ci	struct ath5k_hw *ah = file->private_data;
36262306a36Sopenharmony_ci	char buf[700];
36362306a36Sopenharmony_ci	unsigned int len = 0;
36462306a36Sopenharmony_ci	unsigned int i;
36562306a36Sopenharmony_ci	unsigned int v;
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len, "antenna mode\t%d\n",
36862306a36Sopenharmony_ci		ah->ah_ant_mode);
36962306a36Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len, "default antenna\t%d\n",
37062306a36Sopenharmony_ci		ah->ah_def_ant);
37162306a36Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len, "tx antenna\t%d\n",
37262306a36Sopenharmony_ci		ah->ah_tx_ant);
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len, "\nANTENNA\t\tRX\tTX\n");
37562306a36Sopenharmony_ci	for (i = 1; i < ARRAY_SIZE(ah->stats.antenna_rx); i++) {
37662306a36Sopenharmony_ci		len += scnprintf(buf + len, sizeof(buf) - len,
37762306a36Sopenharmony_ci			"[antenna %d]\t%d\t%d\n",
37862306a36Sopenharmony_ci			i, ah->stats.antenna_rx[i], ah->stats.antenna_tx[i]);
37962306a36Sopenharmony_ci	}
38062306a36Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len, "[invalid]\t%d\t%d\n",
38162306a36Sopenharmony_ci			ah->stats.antenna_rx[0], ah->stats.antenna_tx[0]);
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci	v = ath5k_hw_reg_read(ah, AR5K_DEFAULT_ANTENNA);
38462306a36Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len,
38562306a36Sopenharmony_ci			"\nAR5K_DEFAULT_ANTENNA\t0x%08x\n", v);
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	v = ath5k_hw_reg_read(ah, AR5K_STA_ID1);
38862306a36Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len,
38962306a36Sopenharmony_ci		"AR5K_STA_ID1_DEFAULT_ANTENNA\t%d\n",
39062306a36Sopenharmony_ci		(v & AR5K_STA_ID1_DEFAULT_ANTENNA) != 0);
39162306a36Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len,
39262306a36Sopenharmony_ci		"AR5K_STA_ID1_DESC_ANTENNA\t%d\n",
39362306a36Sopenharmony_ci		(v & AR5K_STA_ID1_DESC_ANTENNA) != 0);
39462306a36Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len,
39562306a36Sopenharmony_ci		"AR5K_STA_ID1_RTS_DEF_ANTENNA\t%d\n",
39662306a36Sopenharmony_ci		(v & AR5K_STA_ID1_RTS_DEF_ANTENNA) != 0);
39762306a36Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len,
39862306a36Sopenharmony_ci		"AR5K_STA_ID1_SELFGEN_DEF_ANT\t%d\n",
39962306a36Sopenharmony_ci		(v & AR5K_STA_ID1_SELFGEN_DEF_ANT) != 0);
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci	v = ath5k_hw_reg_read(ah, AR5K_PHY_AGCCTL);
40262306a36Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len,
40362306a36Sopenharmony_ci		"\nAR5K_PHY_AGCCTL_OFDM_DIV_DIS\t%d\n",
40462306a36Sopenharmony_ci		(v & AR5K_PHY_AGCCTL_OFDM_DIV_DIS) != 0);
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	v = ath5k_hw_reg_read(ah, AR5K_PHY_RESTART);
40762306a36Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len,
40862306a36Sopenharmony_ci		"AR5K_PHY_RESTART_DIV_GC\t\t%x\n",
40962306a36Sopenharmony_ci		(v & AR5K_PHY_RESTART_DIV_GC) >> AR5K_PHY_RESTART_DIV_GC_S);
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	v = ath5k_hw_reg_read(ah, AR5K_PHY_FAST_ANT_DIV);
41262306a36Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len,
41362306a36Sopenharmony_ci		"AR5K_PHY_FAST_ANT_DIV_EN\t%d\n",
41462306a36Sopenharmony_ci		(v & AR5K_PHY_FAST_ANT_DIV_EN) != 0);
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci	v = ath5k_hw_reg_read(ah, AR5K_PHY_ANT_SWITCH_TABLE_0);
41762306a36Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len,
41862306a36Sopenharmony_ci			"\nAR5K_PHY_ANT_SWITCH_TABLE_0\t0x%08x\n", v);
41962306a36Sopenharmony_ci	v = ath5k_hw_reg_read(ah, AR5K_PHY_ANT_SWITCH_TABLE_1);
42062306a36Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len,
42162306a36Sopenharmony_ci			"AR5K_PHY_ANT_SWITCH_TABLE_1\t0x%08x\n", v);
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	if (len > sizeof(buf))
42462306a36Sopenharmony_ci		len = sizeof(buf);
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
42762306a36Sopenharmony_ci}
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_cistatic ssize_t write_file_antenna(struct file *file,
43062306a36Sopenharmony_ci				 const char __user *userbuf,
43162306a36Sopenharmony_ci				 size_t count, loff_t *ppos)
43262306a36Sopenharmony_ci{
43362306a36Sopenharmony_ci	struct ath5k_hw *ah = file->private_data;
43462306a36Sopenharmony_ci	unsigned int i;
43562306a36Sopenharmony_ci	char buf[20];
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci	count = min_t(size_t, count, sizeof(buf) - 1);
43862306a36Sopenharmony_ci	if (copy_from_user(buf, userbuf, count))
43962306a36Sopenharmony_ci		return -EFAULT;
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci	buf[count] = '\0';
44262306a36Sopenharmony_ci	if (strncmp(buf, "diversity", 9) == 0) {
44362306a36Sopenharmony_ci		ath5k_hw_set_antenna_mode(ah, AR5K_ANTMODE_DEFAULT);
44462306a36Sopenharmony_ci		pr_info("debug: enable diversity\n");
44562306a36Sopenharmony_ci	} else if (strncmp(buf, "fixed-a", 7) == 0) {
44662306a36Sopenharmony_ci		ath5k_hw_set_antenna_mode(ah, AR5K_ANTMODE_FIXED_A);
44762306a36Sopenharmony_ci		pr_info("debug: fixed antenna A\n");
44862306a36Sopenharmony_ci	} else if (strncmp(buf, "fixed-b", 7) == 0) {
44962306a36Sopenharmony_ci		ath5k_hw_set_antenna_mode(ah, AR5K_ANTMODE_FIXED_B);
45062306a36Sopenharmony_ci		pr_info("debug: fixed antenna B\n");
45162306a36Sopenharmony_ci	} else if (strncmp(buf, "clear", 5) == 0) {
45262306a36Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(ah->stats.antenna_rx); i++) {
45362306a36Sopenharmony_ci			ah->stats.antenna_rx[i] = 0;
45462306a36Sopenharmony_ci			ah->stats.antenna_tx[i] = 0;
45562306a36Sopenharmony_ci		}
45662306a36Sopenharmony_ci		pr_info("debug: cleared antenna stats\n");
45762306a36Sopenharmony_ci	}
45862306a36Sopenharmony_ci	return count;
45962306a36Sopenharmony_ci}
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_cistatic const struct file_operations fops_antenna = {
46262306a36Sopenharmony_ci	.read = read_file_antenna,
46362306a36Sopenharmony_ci	.write = write_file_antenna,
46462306a36Sopenharmony_ci	.open = simple_open,
46562306a36Sopenharmony_ci	.owner = THIS_MODULE,
46662306a36Sopenharmony_ci	.llseek = default_llseek,
46762306a36Sopenharmony_ci};
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci/* debugfs: misc */
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_cistatic ssize_t read_file_misc(struct file *file, char __user *user_buf,
47262306a36Sopenharmony_ci				   size_t count, loff_t *ppos)
47362306a36Sopenharmony_ci{
47462306a36Sopenharmony_ci	struct ath5k_hw *ah = file->private_data;
47562306a36Sopenharmony_ci	char buf[700];
47662306a36Sopenharmony_ci	unsigned int len = 0;
47762306a36Sopenharmony_ci	u32 filt = ath5k_hw_get_rx_filter(ah);
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len, "bssid-mask: %pM\n",
48062306a36Sopenharmony_ci			ah->bssidmask);
48162306a36Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len, "filter-flags: 0x%x ",
48262306a36Sopenharmony_ci			filt);
48362306a36Sopenharmony_ci	if (filt & AR5K_RX_FILTER_UCAST)
48462306a36Sopenharmony_ci		len += scnprintf(buf + len, sizeof(buf) - len, " UCAST");
48562306a36Sopenharmony_ci	if (filt & AR5K_RX_FILTER_MCAST)
48662306a36Sopenharmony_ci		len += scnprintf(buf + len, sizeof(buf) - len, " MCAST");
48762306a36Sopenharmony_ci	if (filt & AR5K_RX_FILTER_BCAST)
48862306a36Sopenharmony_ci		len += scnprintf(buf + len, sizeof(buf) - len, " BCAST");
48962306a36Sopenharmony_ci	if (filt & AR5K_RX_FILTER_CONTROL)
49062306a36Sopenharmony_ci		len += scnprintf(buf + len, sizeof(buf) - len, " CONTROL");
49162306a36Sopenharmony_ci	if (filt & AR5K_RX_FILTER_BEACON)
49262306a36Sopenharmony_ci		len += scnprintf(buf + len, sizeof(buf) - len, " BEACON");
49362306a36Sopenharmony_ci	if (filt & AR5K_RX_FILTER_PROM)
49462306a36Sopenharmony_ci		len += scnprintf(buf + len, sizeof(buf) - len, " PROM");
49562306a36Sopenharmony_ci	if (filt & AR5K_RX_FILTER_XRPOLL)
49662306a36Sopenharmony_ci		len += scnprintf(buf + len, sizeof(buf) - len, " XRPOLL");
49762306a36Sopenharmony_ci	if (filt & AR5K_RX_FILTER_PROBEREQ)
49862306a36Sopenharmony_ci		len += scnprintf(buf + len, sizeof(buf) - len, " PROBEREQ");
49962306a36Sopenharmony_ci	if (filt & AR5K_RX_FILTER_PHYERR_5212)
50062306a36Sopenharmony_ci		len += scnprintf(buf + len, sizeof(buf) - len, " PHYERR-5212");
50162306a36Sopenharmony_ci	if (filt & AR5K_RX_FILTER_RADARERR_5212)
50262306a36Sopenharmony_ci		len += scnprintf(buf + len, sizeof(buf) - len, " RADARERR-5212");
50362306a36Sopenharmony_ci	if (filt & AR5K_RX_FILTER_PHYERR_5211)
50462306a36Sopenharmony_ci		snprintf(buf + len, sizeof(buf) - len, " PHYERR-5211");
50562306a36Sopenharmony_ci	if (filt & AR5K_RX_FILTER_RADARERR_5211)
50662306a36Sopenharmony_ci		len += scnprintf(buf + len, sizeof(buf) - len, " RADARERR-5211");
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len, "\nopmode: %s (%d)\n",
50962306a36Sopenharmony_ci			ath_opmode_to_string(ah->opmode), ah->opmode);
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci	if (len > sizeof(buf))
51262306a36Sopenharmony_ci		len = sizeof(buf);
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
51562306a36Sopenharmony_ci}
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_cistatic const struct file_operations fops_misc = {
51862306a36Sopenharmony_ci	.read = read_file_misc,
51962306a36Sopenharmony_ci	.open = simple_open,
52062306a36Sopenharmony_ci	.owner = THIS_MODULE,
52162306a36Sopenharmony_ci};
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci/* debugfs: frameerrors */
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_cistatic ssize_t read_file_frameerrors(struct file *file, char __user *user_buf,
52762306a36Sopenharmony_ci				   size_t count, loff_t *ppos)
52862306a36Sopenharmony_ci{
52962306a36Sopenharmony_ci	struct ath5k_hw *ah = file->private_data;
53062306a36Sopenharmony_ci	struct ath5k_statistics *st = &ah->stats;
53162306a36Sopenharmony_ci	char buf[700];
53262306a36Sopenharmony_ci	unsigned int len = 0;
53362306a36Sopenharmony_ci	int i;
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len,
53662306a36Sopenharmony_ci			"RX\n---------------------\n");
53762306a36Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len, "CRC\t%u\t(%u%%)\n",
53862306a36Sopenharmony_ci			st->rxerr_crc,
53962306a36Sopenharmony_ci			st->rx_all_count > 0 ?
54062306a36Sopenharmony_ci				st->rxerr_crc * 100 / st->rx_all_count : 0);
54162306a36Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len, "PHY\t%u\t(%u%%)\n",
54262306a36Sopenharmony_ci			st->rxerr_phy,
54362306a36Sopenharmony_ci			st->rx_all_count > 0 ?
54462306a36Sopenharmony_ci				st->rxerr_phy * 100 / st->rx_all_count : 0);
54562306a36Sopenharmony_ci	for (i = 0; i < 32; i++) {
54662306a36Sopenharmony_ci		if (st->rxerr_phy_code[i])
54762306a36Sopenharmony_ci			len += scnprintf(buf + len, sizeof(buf) - len,
54862306a36Sopenharmony_ci				" phy_err[%u]\t%u\n",
54962306a36Sopenharmony_ci				i, st->rxerr_phy_code[i]);
55062306a36Sopenharmony_ci	}
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len, "FIFO\t%u\t(%u%%)\n",
55362306a36Sopenharmony_ci			st->rxerr_fifo,
55462306a36Sopenharmony_ci			st->rx_all_count > 0 ?
55562306a36Sopenharmony_ci				st->rxerr_fifo * 100 / st->rx_all_count : 0);
55662306a36Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len, "decrypt\t%u\t(%u%%)\n",
55762306a36Sopenharmony_ci			st->rxerr_decrypt,
55862306a36Sopenharmony_ci			st->rx_all_count > 0 ?
55962306a36Sopenharmony_ci				st->rxerr_decrypt * 100 / st->rx_all_count : 0);
56062306a36Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len, "MIC\t%u\t(%u%%)\n",
56162306a36Sopenharmony_ci			st->rxerr_mic,
56262306a36Sopenharmony_ci			st->rx_all_count > 0 ?
56362306a36Sopenharmony_ci				st->rxerr_mic * 100 / st->rx_all_count : 0);
56462306a36Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len, "process\t%u\t(%u%%)\n",
56562306a36Sopenharmony_ci			st->rxerr_proc,
56662306a36Sopenharmony_ci			st->rx_all_count > 0 ?
56762306a36Sopenharmony_ci				st->rxerr_proc * 100 / st->rx_all_count : 0);
56862306a36Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len, "jumbo\t%u\t(%u%%)\n",
56962306a36Sopenharmony_ci			st->rxerr_jumbo,
57062306a36Sopenharmony_ci			st->rx_all_count > 0 ?
57162306a36Sopenharmony_ci				st->rxerr_jumbo * 100 / st->rx_all_count : 0);
57262306a36Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len, "[RX all\t%u]\n",
57362306a36Sopenharmony_ci			st->rx_all_count);
57462306a36Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len, "RX-all-bytes\t%u\n",
57562306a36Sopenharmony_ci			st->rx_bytes_count);
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len,
57862306a36Sopenharmony_ci			"\nTX\n---------------------\n");
57962306a36Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len, "retry\t%u\t(%u%%)\n",
58062306a36Sopenharmony_ci			st->txerr_retry,
58162306a36Sopenharmony_ci			st->tx_all_count > 0 ?
58262306a36Sopenharmony_ci				st->txerr_retry * 100 / st->tx_all_count : 0);
58362306a36Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len, "FIFO\t%u\t(%u%%)\n",
58462306a36Sopenharmony_ci			st->txerr_fifo,
58562306a36Sopenharmony_ci			st->tx_all_count > 0 ?
58662306a36Sopenharmony_ci				st->txerr_fifo * 100 / st->tx_all_count : 0);
58762306a36Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len, "filter\t%u\t(%u%%)\n",
58862306a36Sopenharmony_ci			st->txerr_filt,
58962306a36Sopenharmony_ci			st->tx_all_count > 0 ?
59062306a36Sopenharmony_ci				st->txerr_filt * 100 / st->tx_all_count : 0);
59162306a36Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len, "[TX all\t%u]\n",
59262306a36Sopenharmony_ci			st->tx_all_count);
59362306a36Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len, "TX-all-bytes\t%u\n",
59462306a36Sopenharmony_ci			st->tx_bytes_count);
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci	if (len > sizeof(buf))
59762306a36Sopenharmony_ci		len = sizeof(buf);
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_ci	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
60062306a36Sopenharmony_ci}
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_cistatic ssize_t write_file_frameerrors(struct file *file,
60362306a36Sopenharmony_ci				 const char __user *userbuf,
60462306a36Sopenharmony_ci				 size_t count, loff_t *ppos)
60562306a36Sopenharmony_ci{
60662306a36Sopenharmony_ci	struct ath5k_hw *ah = file->private_data;
60762306a36Sopenharmony_ci	struct ath5k_statistics *st = &ah->stats;
60862306a36Sopenharmony_ci	char buf[20];
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_ci	count = min_t(size_t, count, sizeof(buf) - 1);
61162306a36Sopenharmony_ci	if (copy_from_user(buf, userbuf, count))
61262306a36Sopenharmony_ci		return -EFAULT;
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ci	buf[count] = '\0';
61562306a36Sopenharmony_ci	if (strncmp(buf, "clear", 5) == 0) {
61662306a36Sopenharmony_ci		st->rxerr_crc = 0;
61762306a36Sopenharmony_ci		st->rxerr_phy = 0;
61862306a36Sopenharmony_ci		st->rxerr_fifo = 0;
61962306a36Sopenharmony_ci		st->rxerr_decrypt = 0;
62062306a36Sopenharmony_ci		st->rxerr_mic = 0;
62162306a36Sopenharmony_ci		st->rxerr_proc = 0;
62262306a36Sopenharmony_ci		st->rxerr_jumbo = 0;
62362306a36Sopenharmony_ci		st->rx_all_count = 0;
62462306a36Sopenharmony_ci		st->txerr_retry = 0;
62562306a36Sopenharmony_ci		st->txerr_fifo = 0;
62662306a36Sopenharmony_ci		st->txerr_filt = 0;
62762306a36Sopenharmony_ci		st->tx_all_count = 0;
62862306a36Sopenharmony_ci		pr_info("debug: cleared frameerrors stats\n");
62962306a36Sopenharmony_ci	}
63062306a36Sopenharmony_ci	return count;
63162306a36Sopenharmony_ci}
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_cistatic const struct file_operations fops_frameerrors = {
63462306a36Sopenharmony_ci	.read = read_file_frameerrors,
63562306a36Sopenharmony_ci	.write = write_file_frameerrors,
63662306a36Sopenharmony_ci	.open = simple_open,
63762306a36Sopenharmony_ci	.owner = THIS_MODULE,
63862306a36Sopenharmony_ci	.llseek = default_llseek,
63962306a36Sopenharmony_ci};
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_ci/* debugfs: ani */
64362306a36Sopenharmony_ci
64462306a36Sopenharmony_cistatic ssize_t read_file_ani(struct file *file, char __user *user_buf,
64562306a36Sopenharmony_ci				   size_t count, loff_t *ppos)
64662306a36Sopenharmony_ci{
64762306a36Sopenharmony_ci	struct ath5k_hw *ah = file->private_data;
64862306a36Sopenharmony_ci	struct ath5k_statistics *st = &ah->stats;
64962306a36Sopenharmony_ci	struct ath5k_ani_state *as = &ah->ani_state;
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_ci	char buf[700];
65262306a36Sopenharmony_ci	unsigned int len = 0;
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len,
65562306a36Sopenharmony_ci			"HW has PHY error counters:\t%s\n",
65662306a36Sopenharmony_ci			ah->ah_capabilities.cap_has_phyerr_counters ?
65762306a36Sopenharmony_ci			"yes" : "no");
65862306a36Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len,
65962306a36Sopenharmony_ci			"HW max spur immunity level:\t%d\n",
66062306a36Sopenharmony_ci			as->max_spur_level);
66162306a36Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len,
66262306a36Sopenharmony_ci		"\nANI state\n--------------------------------------------\n");
66362306a36Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len, "operating mode:\t\t\t");
66462306a36Sopenharmony_ci	switch (as->ani_mode) {
66562306a36Sopenharmony_ci	case ATH5K_ANI_MODE_OFF:
66662306a36Sopenharmony_ci		len += scnprintf(buf + len, sizeof(buf) - len, "OFF\n");
66762306a36Sopenharmony_ci		break;
66862306a36Sopenharmony_ci	case ATH5K_ANI_MODE_MANUAL_LOW:
66962306a36Sopenharmony_ci		len += scnprintf(buf + len, sizeof(buf) - len,
67062306a36Sopenharmony_ci			"MANUAL LOW\n");
67162306a36Sopenharmony_ci		break;
67262306a36Sopenharmony_ci	case ATH5K_ANI_MODE_MANUAL_HIGH:
67362306a36Sopenharmony_ci		len += scnprintf(buf + len, sizeof(buf) - len,
67462306a36Sopenharmony_ci			"MANUAL HIGH\n");
67562306a36Sopenharmony_ci		break;
67662306a36Sopenharmony_ci	case ATH5K_ANI_MODE_AUTO:
67762306a36Sopenharmony_ci		len += scnprintf(buf + len, sizeof(buf) - len, "AUTO\n");
67862306a36Sopenharmony_ci		break;
67962306a36Sopenharmony_ci	default:
68062306a36Sopenharmony_ci		len += scnprintf(buf + len, sizeof(buf) - len,
68162306a36Sopenharmony_ci			"??? (not good)\n");
68262306a36Sopenharmony_ci		break;
68362306a36Sopenharmony_ci	}
68462306a36Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len,
68562306a36Sopenharmony_ci			"noise immunity level:\t\t%d\n",
68662306a36Sopenharmony_ci			as->noise_imm_level);
68762306a36Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len,
68862306a36Sopenharmony_ci			"spur immunity level:\t\t%d\n",
68962306a36Sopenharmony_ci			as->spur_level);
69062306a36Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len,
69162306a36Sopenharmony_ci			"firstep level:\t\t\t%d\n",
69262306a36Sopenharmony_ci			as->firstep_level);
69362306a36Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len,
69462306a36Sopenharmony_ci			"OFDM weak signal detection:\t%s\n",
69562306a36Sopenharmony_ci			as->ofdm_weak_sig ? "on" : "off");
69662306a36Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len,
69762306a36Sopenharmony_ci			"CCK weak signal detection:\t%s\n",
69862306a36Sopenharmony_ci			as->cck_weak_sig ? "on" : "off");
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len,
70162306a36Sopenharmony_ci			"\nMIB INTERRUPTS:\t\t%u\n",
70262306a36Sopenharmony_ci			st->mib_intr);
70362306a36Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len,
70462306a36Sopenharmony_ci			"beacon RSSI average:\t%d\n",
70562306a36Sopenharmony_ci			(int)ewma_beacon_rssi_read(&ah->ah_beacon_rssi_avg));
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_ci#define CC_PRINT(_struct, _field) \
70862306a36Sopenharmony_ci	_struct._field, \
70962306a36Sopenharmony_ci	_struct.cycles > 0 ? \
71062306a36Sopenharmony_ci	_struct._field * 100 / _struct.cycles : 0
71162306a36Sopenharmony_ci
71262306a36Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len,
71362306a36Sopenharmony_ci			"profcnt tx\t\t%u\t(%d%%)\n",
71462306a36Sopenharmony_ci			CC_PRINT(as->last_cc, tx_frame));
71562306a36Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len,
71662306a36Sopenharmony_ci			"profcnt rx\t\t%u\t(%d%%)\n",
71762306a36Sopenharmony_ci			CC_PRINT(as->last_cc, rx_frame));
71862306a36Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len,
71962306a36Sopenharmony_ci			"profcnt busy\t\t%u\t(%d%%)\n",
72062306a36Sopenharmony_ci			CC_PRINT(as->last_cc, rx_busy));
72162306a36Sopenharmony_ci#undef CC_PRINT
72262306a36Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len, "profcnt cycles\t\t%u\n",
72362306a36Sopenharmony_ci			as->last_cc.cycles);
72462306a36Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len,
72562306a36Sopenharmony_ci			"listen time\t\t%d\tlast: %d\n",
72662306a36Sopenharmony_ci			as->listen_time, as->last_listen);
72762306a36Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len,
72862306a36Sopenharmony_ci			"OFDM errors\t\t%u\tlast: %u\tsum: %u\n",
72962306a36Sopenharmony_ci			as->ofdm_errors, as->last_ofdm_errors,
73062306a36Sopenharmony_ci			as->sum_ofdm_errors);
73162306a36Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len,
73262306a36Sopenharmony_ci			"CCK errors\t\t%u\tlast: %u\tsum: %u\n",
73362306a36Sopenharmony_ci			as->cck_errors, as->last_cck_errors,
73462306a36Sopenharmony_ci			as->sum_cck_errors);
73562306a36Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len,
73662306a36Sopenharmony_ci			"AR5K_PHYERR_CNT1\t%x\t(=%d)\n",
73762306a36Sopenharmony_ci			ath5k_hw_reg_read(ah, AR5K_PHYERR_CNT1),
73862306a36Sopenharmony_ci			ATH5K_ANI_OFDM_TRIG_HIGH - (ATH5K_PHYERR_CNT_MAX -
73962306a36Sopenharmony_ci			ath5k_hw_reg_read(ah, AR5K_PHYERR_CNT1)));
74062306a36Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len,
74162306a36Sopenharmony_ci			"AR5K_PHYERR_CNT2\t%x\t(=%d)\n",
74262306a36Sopenharmony_ci			ath5k_hw_reg_read(ah, AR5K_PHYERR_CNT2),
74362306a36Sopenharmony_ci			ATH5K_ANI_CCK_TRIG_HIGH - (ATH5K_PHYERR_CNT_MAX -
74462306a36Sopenharmony_ci			ath5k_hw_reg_read(ah, AR5K_PHYERR_CNT2)));
74562306a36Sopenharmony_ci
74662306a36Sopenharmony_ci	if (len > sizeof(buf))
74762306a36Sopenharmony_ci		len = sizeof(buf);
74862306a36Sopenharmony_ci
74962306a36Sopenharmony_ci	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
75062306a36Sopenharmony_ci}
75162306a36Sopenharmony_ci
75262306a36Sopenharmony_cistatic ssize_t write_file_ani(struct file *file,
75362306a36Sopenharmony_ci				 const char __user *userbuf,
75462306a36Sopenharmony_ci				 size_t count, loff_t *ppos)
75562306a36Sopenharmony_ci{
75662306a36Sopenharmony_ci	struct ath5k_hw *ah = file->private_data;
75762306a36Sopenharmony_ci	char buf[20];
75862306a36Sopenharmony_ci
75962306a36Sopenharmony_ci	count = min_t(size_t, count, sizeof(buf) - 1);
76062306a36Sopenharmony_ci	if (copy_from_user(buf, userbuf, count))
76162306a36Sopenharmony_ci		return -EFAULT;
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_ci	buf[count] = '\0';
76462306a36Sopenharmony_ci	if (strncmp(buf, "sens-low", 8) == 0) {
76562306a36Sopenharmony_ci		ath5k_ani_init(ah, ATH5K_ANI_MODE_MANUAL_HIGH);
76662306a36Sopenharmony_ci	} else if (strncmp(buf, "sens-high", 9) == 0) {
76762306a36Sopenharmony_ci		ath5k_ani_init(ah, ATH5K_ANI_MODE_MANUAL_LOW);
76862306a36Sopenharmony_ci	} else if (strncmp(buf, "ani-off", 7) == 0) {
76962306a36Sopenharmony_ci		ath5k_ani_init(ah, ATH5K_ANI_MODE_OFF);
77062306a36Sopenharmony_ci	} else if (strncmp(buf, "ani-on", 6) == 0) {
77162306a36Sopenharmony_ci		ath5k_ani_init(ah, ATH5K_ANI_MODE_AUTO);
77262306a36Sopenharmony_ci	} else if (strncmp(buf, "noise-low", 9) == 0) {
77362306a36Sopenharmony_ci		ath5k_ani_set_noise_immunity_level(ah, 0);
77462306a36Sopenharmony_ci	} else if (strncmp(buf, "noise-high", 10) == 0) {
77562306a36Sopenharmony_ci		ath5k_ani_set_noise_immunity_level(ah,
77662306a36Sopenharmony_ci						   ATH5K_ANI_MAX_NOISE_IMM_LVL);
77762306a36Sopenharmony_ci	} else if (strncmp(buf, "spur-low", 8) == 0) {
77862306a36Sopenharmony_ci		ath5k_ani_set_spur_immunity_level(ah, 0);
77962306a36Sopenharmony_ci	} else if (strncmp(buf, "spur-high", 9) == 0) {
78062306a36Sopenharmony_ci		ath5k_ani_set_spur_immunity_level(ah,
78162306a36Sopenharmony_ci						  ah->ani_state.max_spur_level);
78262306a36Sopenharmony_ci	} else if (strncmp(buf, "fir-low", 7) == 0) {
78362306a36Sopenharmony_ci		ath5k_ani_set_firstep_level(ah, 0);
78462306a36Sopenharmony_ci	} else if (strncmp(buf, "fir-high", 8) == 0) {
78562306a36Sopenharmony_ci		ath5k_ani_set_firstep_level(ah, ATH5K_ANI_MAX_FIRSTEP_LVL);
78662306a36Sopenharmony_ci	} else if (strncmp(buf, "ofdm-off", 8) == 0) {
78762306a36Sopenharmony_ci		ath5k_ani_set_ofdm_weak_signal_detection(ah, false);
78862306a36Sopenharmony_ci	} else if (strncmp(buf, "ofdm-on", 7) == 0) {
78962306a36Sopenharmony_ci		ath5k_ani_set_ofdm_weak_signal_detection(ah, true);
79062306a36Sopenharmony_ci	} else if (strncmp(buf, "cck-off", 7) == 0) {
79162306a36Sopenharmony_ci		ath5k_ani_set_cck_weak_signal_detection(ah, false);
79262306a36Sopenharmony_ci	} else if (strncmp(buf, "cck-on", 6) == 0) {
79362306a36Sopenharmony_ci		ath5k_ani_set_cck_weak_signal_detection(ah, true);
79462306a36Sopenharmony_ci	}
79562306a36Sopenharmony_ci	return count;
79662306a36Sopenharmony_ci}
79762306a36Sopenharmony_ci
79862306a36Sopenharmony_cistatic const struct file_operations fops_ani = {
79962306a36Sopenharmony_ci	.read = read_file_ani,
80062306a36Sopenharmony_ci	.write = write_file_ani,
80162306a36Sopenharmony_ci	.open = simple_open,
80262306a36Sopenharmony_ci	.owner = THIS_MODULE,
80362306a36Sopenharmony_ci	.llseek = default_llseek,
80462306a36Sopenharmony_ci};
80562306a36Sopenharmony_ci
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_ci/* debugfs: queues etc */
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_cistatic ssize_t read_file_queue(struct file *file, char __user *user_buf,
81062306a36Sopenharmony_ci				   size_t count, loff_t *ppos)
81162306a36Sopenharmony_ci{
81262306a36Sopenharmony_ci	struct ath5k_hw *ah = file->private_data;
81362306a36Sopenharmony_ci	char buf[700];
81462306a36Sopenharmony_ci	unsigned int len = 0;
81562306a36Sopenharmony_ci
81662306a36Sopenharmony_ci	struct ath5k_txq *txq;
81762306a36Sopenharmony_ci	struct ath5k_buf *bf, *bf0;
81862306a36Sopenharmony_ci	int i, n;
81962306a36Sopenharmony_ci
82062306a36Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len,
82162306a36Sopenharmony_ci			"available txbuffers: %d\n", ah->txbuf_len);
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(ah->txqs); i++) {
82462306a36Sopenharmony_ci		txq = &ah->txqs[i];
82562306a36Sopenharmony_ci
82662306a36Sopenharmony_ci		len += scnprintf(buf + len, sizeof(buf) - len,
82762306a36Sopenharmony_ci			"%02d: %ssetup\n", i, txq->setup ? "" : "not ");
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_ci		if (!txq->setup)
83062306a36Sopenharmony_ci			continue;
83162306a36Sopenharmony_ci
83262306a36Sopenharmony_ci		n = 0;
83362306a36Sopenharmony_ci		spin_lock_bh(&txq->lock);
83462306a36Sopenharmony_ci		list_for_each_entry_safe(bf, bf0, &txq->q, list)
83562306a36Sopenharmony_ci			n++;
83662306a36Sopenharmony_ci		spin_unlock_bh(&txq->lock);
83762306a36Sopenharmony_ci
83862306a36Sopenharmony_ci		len += scnprintf(buf + len, sizeof(buf) - len,
83962306a36Sopenharmony_ci				"  len: %d bufs: %d\n", txq->txq_len, n);
84062306a36Sopenharmony_ci		len += scnprintf(buf + len, sizeof(buf) - len,
84162306a36Sopenharmony_ci				"  stuck: %d\n", txq->txq_stuck);
84262306a36Sopenharmony_ci	}
84362306a36Sopenharmony_ci
84462306a36Sopenharmony_ci	if (len > sizeof(buf))
84562306a36Sopenharmony_ci		len = sizeof(buf);
84662306a36Sopenharmony_ci
84762306a36Sopenharmony_ci	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
84862306a36Sopenharmony_ci}
84962306a36Sopenharmony_ci
85062306a36Sopenharmony_cistatic ssize_t write_file_queue(struct file *file,
85162306a36Sopenharmony_ci				 const char __user *userbuf,
85262306a36Sopenharmony_ci				 size_t count, loff_t *ppos)
85362306a36Sopenharmony_ci{
85462306a36Sopenharmony_ci	struct ath5k_hw *ah = file->private_data;
85562306a36Sopenharmony_ci	char buf[20];
85662306a36Sopenharmony_ci
85762306a36Sopenharmony_ci	count = min_t(size_t, count, sizeof(buf) - 1);
85862306a36Sopenharmony_ci	if (copy_from_user(buf, userbuf, count))
85962306a36Sopenharmony_ci		return -EFAULT;
86062306a36Sopenharmony_ci
86162306a36Sopenharmony_ci	buf[count] = '\0';
86262306a36Sopenharmony_ci	if (strncmp(buf, "start", 5) == 0)
86362306a36Sopenharmony_ci		ieee80211_wake_queues(ah->hw);
86462306a36Sopenharmony_ci	else if (strncmp(buf, "stop", 4) == 0)
86562306a36Sopenharmony_ci		ieee80211_stop_queues(ah->hw);
86662306a36Sopenharmony_ci
86762306a36Sopenharmony_ci	return count;
86862306a36Sopenharmony_ci}
86962306a36Sopenharmony_ci
87062306a36Sopenharmony_ci
87162306a36Sopenharmony_cistatic const struct file_operations fops_queue = {
87262306a36Sopenharmony_ci	.read = read_file_queue,
87362306a36Sopenharmony_ci	.write = write_file_queue,
87462306a36Sopenharmony_ci	.open = simple_open,
87562306a36Sopenharmony_ci	.owner = THIS_MODULE,
87662306a36Sopenharmony_ci	.llseek = default_llseek,
87762306a36Sopenharmony_ci};
87862306a36Sopenharmony_ci
87962306a36Sopenharmony_ci/* debugfs: eeprom */
88062306a36Sopenharmony_ci
88162306a36Sopenharmony_cistruct eeprom_private {
88262306a36Sopenharmony_ci	u16 *buf;
88362306a36Sopenharmony_ci	int len;
88462306a36Sopenharmony_ci};
88562306a36Sopenharmony_ci
88662306a36Sopenharmony_cistatic int open_file_eeprom(struct inode *inode, struct file *file)
88762306a36Sopenharmony_ci{
88862306a36Sopenharmony_ci	struct eeprom_private *ep;
88962306a36Sopenharmony_ci	struct ath5k_hw *ah = inode->i_private;
89062306a36Sopenharmony_ci	bool res;
89162306a36Sopenharmony_ci	int i, ret;
89262306a36Sopenharmony_ci	u32 eesize;	/* NB: in 16-bit words */
89362306a36Sopenharmony_ci	u16 val, *buf;
89462306a36Sopenharmony_ci
89562306a36Sopenharmony_ci	/* Get eeprom size */
89662306a36Sopenharmony_ci
89762306a36Sopenharmony_ci	res = ath5k_hw_nvram_read(ah, AR5K_EEPROM_SIZE_UPPER, &val);
89862306a36Sopenharmony_ci	if (!res)
89962306a36Sopenharmony_ci		return -EACCES;
90062306a36Sopenharmony_ci
90162306a36Sopenharmony_ci	if (val == 0) {
90262306a36Sopenharmony_ci		eesize = AR5K_EEPROM_INFO_MAX + AR5K_EEPROM_INFO_BASE;
90362306a36Sopenharmony_ci	} else {
90462306a36Sopenharmony_ci		eesize = (val & AR5K_EEPROM_SIZE_UPPER_MASK) <<
90562306a36Sopenharmony_ci			AR5K_EEPROM_SIZE_ENDLOC_SHIFT;
90662306a36Sopenharmony_ci		ath5k_hw_nvram_read(ah, AR5K_EEPROM_SIZE_LOWER, &val);
90762306a36Sopenharmony_ci		eesize = eesize | val;
90862306a36Sopenharmony_ci	}
90962306a36Sopenharmony_ci
91062306a36Sopenharmony_ci	if (eesize > 4096)
91162306a36Sopenharmony_ci		return -EINVAL;
91262306a36Sopenharmony_ci
91362306a36Sopenharmony_ci	/* Create buffer and read in eeprom */
91462306a36Sopenharmony_ci
91562306a36Sopenharmony_ci	buf = vmalloc(array_size(eesize, 2));
91662306a36Sopenharmony_ci	if (!buf) {
91762306a36Sopenharmony_ci		ret = -ENOMEM;
91862306a36Sopenharmony_ci		goto err;
91962306a36Sopenharmony_ci	}
92062306a36Sopenharmony_ci
92162306a36Sopenharmony_ci	for (i = 0; i < eesize; ++i) {
92262306a36Sopenharmony_ci		if (!ath5k_hw_nvram_read(ah, i, &val)) {
92362306a36Sopenharmony_ci			ret = -EIO;
92462306a36Sopenharmony_ci			goto freebuf;
92562306a36Sopenharmony_ci		}
92662306a36Sopenharmony_ci		buf[i] = val;
92762306a36Sopenharmony_ci	}
92862306a36Sopenharmony_ci
92962306a36Sopenharmony_ci	/* Create private struct and assign to file */
93062306a36Sopenharmony_ci
93162306a36Sopenharmony_ci	ep = kmalloc(sizeof(*ep), GFP_KERNEL);
93262306a36Sopenharmony_ci	if (!ep) {
93362306a36Sopenharmony_ci		ret = -ENOMEM;
93462306a36Sopenharmony_ci		goto freebuf;
93562306a36Sopenharmony_ci	}
93662306a36Sopenharmony_ci
93762306a36Sopenharmony_ci	ep->buf = buf;
93862306a36Sopenharmony_ci	ep->len = eesize * 2;
93962306a36Sopenharmony_ci
94062306a36Sopenharmony_ci	file->private_data = (void *)ep;
94162306a36Sopenharmony_ci
94262306a36Sopenharmony_ci	return 0;
94362306a36Sopenharmony_ci
94462306a36Sopenharmony_cifreebuf:
94562306a36Sopenharmony_ci	vfree(buf);
94662306a36Sopenharmony_cierr:
94762306a36Sopenharmony_ci	return ret;
94862306a36Sopenharmony_ci
94962306a36Sopenharmony_ci}
95062306a36Sopenharmony_ci
95162306a36Sopenharmony_cistatic ssize_t read_file_eeprom(struct file *file, char __user *user_buf,
95262306a36Sopenharmony_ci				   size_t count, loff_t *ppos)
95362306a36Sopenharmony_ci{
95462306a36Sopenharmony_ci	struct eeprom_private *ep = file->private_data;
95562306a36Sopenharmony_ci
95662306a36Sopenharmony_ci	return simple_read_from_buffer(user_buf, count, ppos, ep->buf, ep->len);
95762306a36Sopenharmony_ci}
95862306a36Sopenharmony_ci
95962306a36Sopenharmony_cistatic int release_file_eeprom(struct inode *inode, struct file *file)
96062306a36Sopenharmony_ci{
96162306a36Sopenharmony_ci	struct eeprom_private *ep = file->private_data;
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_ci	vfree(ep->buf);
96462306a36Sopenharmony_ci	kfree(ep);
96562306a36Sopenharmony_ci
96662306a36Sopenharmony_ci	return 0;
96762306a36Sopenharmony_ci}
96862306a36Sopenharmony_ci
96962306a36Sopenharmony_cistatic const struct file_operations fops_eeprom = {
97062306a36Sopenharmony_ci	.open = open_file_eeprom,
97162306a36Sopenharmony_ci	.read = read_file_eeprom,
97262306a36Sopenharmony_ci	.release = release_file_eeprom,
97362306a36Sopenharmony_ci	.owner = THIS_MODULE,
97462306a36Sopenharmony_ci};
97562306a36Sopenharmony_ci
97662306a36Sopenharmony_ci
97762306a36Sopenharmony_civoid
97862306a36Sopenharmony_ciath5k_debug_init_device(struct ath5k_hw *ah)
97962306a36Sopenharmony_ci{
98062306a36Sopenharmony_ci	struct dentry *phydir;
98162306a36Sopenharmony_ci
98262306a36Sopenharmony_ci	ah->debug.level = ath5k_debug;
98362306a36Sopenharmony_ci
98462306a36Sopenharmony_ci	phydir = debugfs_create_dir("ath5k", ah->hw->wiphy->debugfsdir);
98562306a36Sopenharmony_ci
98662306a36Sopenharmony_ci	debugfs_create_file("debug", 0600, phydir, ah, &fops_debug);
98762306a36Sopenharmony_ci	debugfs_create_file("registers", 0400, phydir, ah, &registers_fops);
98862306a36Sopenharmony_ci	debugfs_create_file("beacon", 0600, phydir, ah, &fops_beacon);
98962306a36Sopenharmony_ci	debugfs_create_file("reset", 0200, phydir, ah, &fops_reset);
99062306a36Sopenharmony_ci	debugfs_create_file("antenna", 0600, phydir, ah, &fops_antenna);
99162306a36Sopenharmony_ci	debugfs_create_file("misc", 0400, phydir, ah, &fops_misc);
99262306a36Sopenharmony_ci	debugfs_create_file("eeprom", 0400, phydir, ah, &fops_eeprom);
99362306a36Sopenharmony_ci	debugfs_create_file("frameerrors", 0600, phydir, ah, &fops_frameerrors);
99462306a36Sopenharmony_ci	debugfs_create_file("ani", 0600, phydir, ah, &fops_ani);
99562306a36Sopenharmony_ci	debugfs_create_file("queue", 0600, phydir, ah, &fops_queue);
99662306a36Sopenharmony_ci	debugfs_create_bool("32khz_clock", 0600, phydir,
99762306a36Sopenharmony_ci			    &ah->ah_use_32khz_clock);
99862306a36Sopenharmony_ci}
99962306a36Sopenharmony_ci
100062306a36Sopenharmony_ci/* functions used in other places */
100162306a36Sopenharmony_ci
100262306a36Sopenharmony_civoid
100362306a36Sopenharmony_ciath5k_debug_dump_bands(struct ath5k_hw *ah)
100462306a36Sopenharmony_ci{
100562306a36Sopenharmony_ci	unsigned int b, i;
100662306a36Sopenharmony_ci
100762306a36Sopenharmony_ci	if (likely(!(ah->debug.level & ATH5K_DEBUG_DUMPBANDS)))
100862306a36Sopenharmony_ci		return;
100962306a36Sopenharmony_ci
101062306a36Sopenharmony_ci	for (b = 0; b < NUM_NL80211_BANDS; b++) {
101162306a36Sopenharmony_ci		struct ieee80211_supported_band *band = &ah->sbands[b];
101262306a36Sopenharmony_ci		char bname[6];
101362306a36Sopenharmony_ci		switch (band->band) {
101462306a36Sopenharmony_ci		case NL80211_BAND_2GHZ:
101562306a36Sopenharmony_ci			strcpy(bname, "2 GHz");
101662306a36Sopenharmony_ci			break;
101762306a36Sopenharmony_ci		case NL80211_BAND_5GHZ:
101862306a36Sopenharmony_ci			strcpy(bname, "5 GHz");
101962306a36Sopenharmony_ci			break;
102062306a36Sopenharmony_ci		default:
102162306a36Sopenharmony_ci			printk(KERN_DEBUG "Band not supported: %d\n",
102262306a36Sopenharmony_ci				band->band);
102362306a36Sopenharmony_ci			return;
102462306a36Sopenharmony_ci		}
102562306a36Sopenharmony_ci		printk(KERN_DEBUG "Band %s: channels %d, rates %d\n", bname,
102662306a36Sopenharmony_ci				band->n_channels, band->n_bitrates);
102762306a36Sopenharmony_ci		printk(KERN_DEBUG " channels:\n");
102862306a36Sopenharmony_ci		for (i = 0; i < band->n_channels; i++)
102962306a36Sopenharmony_ci			printk(KERN_DEBUG "  %3d %d %.4x %.4x\n",
103062306a36Sopenharmony_ci					ieee80211_frequency_to_channel(
103162306a36Sopenharmony_ci						band->channels[i].center_freq),
103262306a36Sopenharmony_ci					band->channels[i].center_freq,
103362306a36Sopenharmony_ci					band->channels[i].hw_value,
103462306a36Sopenharmony_ci					band->channels[i].flags);
103562306a36Sopenharmony_ci		printk(KERN_DEBUG " rates:\n");
103662306a36Sopenharmony_ci		for (i = 0; i < band->n_bitrates; i++)
103762306a36Sopenharmony_ci			printk(KERN_DEBUG "  %4d %.4x %.4x %.4x\n",
103862306a36Sopenharmony_ci					band->bitrates[i].bitrate,
103962306a36Sopenharmony_ci					band->bitrates[i].hw_value,
104062306a36Sopenharmony_ci					band->bitrates[i].flags,
104162306a36Sopenharmony_ci					band->bitrates[i].hw_value_short);
104262306a36Sopenharmony_ci	}
104362306a36Sopenharmony_ci}
104462306a36Sopenharmony_ci
104562306a36Sopenharmony_cistatic inline void
104662306a36Sopenharmony_ciath5k_debug_printrxbuf(struct ath5k_buf *bf, int done,
104762306a36Sopenharmony_ci		       struct ath5k_rx_status *rs)
104862306a36Sopenharmony_ci{
104962306a36Sopenharmony_ci	struct ath5k_desc *ds = bf->desc;
105062306a36Sopenharmony_ci	struct ath5k_hw_all_rx_desc *rd = &ds->ud.ds_rx;
105162306a36Sopenharmony_ci
105262306a36Sopenharmony_ci	printk(KERN_DEBUG "R (%p %llx) %08x %08x %08x %08x %08x %08x %c\n",
105362306a36Sopenharmony_ci		ds, (unsigned long long)bf->daddr,
105462306a36Sopenharmony_ci		ds->ds_link, ds->ds_data,
105562306a36Sopenharmony_ci		rd->rx_ctl.rx_control_0, rd->rx_ctl.rx_control_1,
105662306a36Sopenharmony_ci		rd->rx_stat.rx_status_0, rd->rx_stat.rx_status_1,
105762306a36Sopenharmony_ci		!done ? ' ' : (rs->rs_status == 0) ? '*' : '!');
105862306a36Sopenharmony_ci}
105962306a36Sopenharmony_ci
106062306a36Sopenharmony_civoid
106162306a36Sopenharmony_ciath5k_debug_printrxbuffs(struct ath5k_hw *ah)
106262306a36Sopenharmony_ci{
106362306a36Sopenharmony_ci	struct ath5k_desc *ds;
106462306a36Sopenharmony_ci	struct ath5k_buf *bf;
106562306a36Sopenharmony_ci	struct ath5k_rx_status rs = {};
106662306a36Sopenharmony_ci	int status;
106762306a36Sopenharmony_ci
106862306a36Sopenharmony_ci	if (likely(!(ah->debug.level & ATH5K_DEBUG_DESC)))
106962306a36Sopenharmony_ci		return;
107062306a36Sopenharmony_ci
107162306a36Sopenharmony_ci	printk(KERN_DEBUG "rxdp %x, rxlink %p\n",
107262306a36Sopenharmony_ci		ath5k_hw_get_rxdp(ah), ah->rxlink);
107362306a36Sopenharmony_ci
107462306a36Sopenharmony_ci	spin_lock_bh(&ah->rxbuflock);
107562306a36Sopenharmony_ci	list_for_each_entry(bf, &ah->rxbuf, list) {
107662306a36Sopenharmony_ci		ds = bf->desc;
107762306a36Sopenharmony_ci		status = ah->ah_proc_rx_desc(ah, ds, &rs);
107862306a36Sopenharmony_ci		if (!status)
107962306a36Sopenharmony_ci			ath5k_debug_printrxbuf(bf, status == 0, &rs);
108062306a36Sopenharmony_ci	}
108162306a36Sopenharmony_ci	spin_unlock_bh(&ah->rxbuflock);
108262306a36Sopenharmony_ci}
108362306a36Sopenharmony_ci
108462306a36Sopenharmony_civoid
108562306a36Sopenharmony_ciath5k_debug_printtxbuf(struct ath5k_hw *ah, struct ath5k_buf *bf)
108662306a36Sopenharmony_ci{
108762306a36Sopenharmony_ci	struct ath5k_desc *ds = bf->desc;
108862306a36Sopenharmony_ci	struct ath5k_hw_5212_tx_desc *td = &ds->ud.ds_tx5212;
108962306a36Sopenharmony_ci	struct ath5k_tx_status ts = {};
109062306a36Sopenharmony_ci	int done;
109162306a36Sopenharmony_ci
109262306a36Sopenharmony_ci	if (likely(!(ah->debug.level & ATH5K_DEBUG_DESC)))
109362306a36Sopenharmony_ci		return;
109462306a36Sopenharmony_ci
109562306a36Sopenharmony_ci	done = ah->ah_proc_tx_desc(ah, bf->desc, &ts);
109662306a36Sopenharmony_ci
109762306a36Sopenharmony_ci	printk(KERN_DEBUG "T (%p %llx) %08x %08x %08x %08x %08x %08x %08x "
109862306a36Sopenharmony_ci		"%08x %c\n", ds, (unsigned long long)bf->daddr, ds->ds_link,
109962306a36Sopenharmony_ci		ds->ds_data, td->tx_ctl.tx_control_0, td->tx_ctl.tx_control_1,
110062306a36Sopenharmony_ci		td->tx_ctl.tx_control_2, td->tx_ctl.tx_control_3,
110162306a36Sopenharmony_ci		td->tx_stat.tx_status_0, td->tx_stat.tx_status_1,
110262306a36Sopenharmony_ci		done ? ' ' : (ts.ts_status == 0) ? '*' : '!');
110362306a36Sopenharmony_ci}
1104