18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Copyright (c) 2007-2008 Bruno Randolf <bruno@thinktube.com>
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci *  This file is free software: you may copy, redistribute and/or modify it
58c2ecf20Sopenharmony_ci *  under the terms of the GNU General Public License as published by the
68c2ecf20Sopenharmony_ci *  Free Software Foundation, either version 2 of the License, or (at your
78c2ecf20Sopenharmony_ci *  option) any later version.
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci *  This file is distributed in the hope that it will be useful, but
108c2ecf20Sopenharmony_ci *  WITHOUT ANY WARRANTY; without even the implied warranty of
118c2ecf20Sopenharmony_ci *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
128c2ecf20Sopenharmony_ci *  General Public License for more details.
138c2ecf20Sopenharmony_ci *
148c2ecf20Sopenharmony_ci *  You should have received a copy of the GNU General Public License
158c2ecf20Sopenharmony_ci *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
168c2ecf20Sopenharmony_ci *
178c2ecf20Sopenharmony_ci *
188c2ecf20Sopenharmony_ci * This file incorporates work covered by the following copyright and
198c2ecf20Sopenharmony_ci * permission notice:
208c2ecf20Sopenharmony_ci *
218c2ecf20Sopenharmony_ci * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
228c2ecf20Sopenharmony_ci * Copyright (c) 2004-2005 Atheros Communications, Inc.
238c2ecf20Sopenharmony_ci * Copyright (c) 2006 Devicescape Software, Inc.
248c2ecf20Sopenharmony_ci * Copyright (c) 2007 Jiri Slaby <jirislaby@gmail.com>
258c2ecf20Sopenharmony_ci * Copyright (c) 2007 Luis R. Rodriguez <mcgrof@winlab.rutgers.edu>
268c2ecf20Sopenharmony_ci *
278c2ecf20Sopenharmony_ci * All rights reserved.
288c2ecf20Sopenharmony_ci *
298c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or without
308c2ecf20Sopenharmony_ci * modification, are permitted provided that the following conditions
318c2ecf20Sopenharmony_ci * are met:
328c2ecf20Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright
338c2ecf20Sopenharmony_ci *    notice, this list of conditions and the following disclaimer,
348c2ecf20Sopenharmony_ci *    without modification.
358c2ecf20Sopenharmony_ci * 2. Redistributions in binary form must reproduce at minimum a disclaimer
368c2ecf20Sopenharmony_ci *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
378c2ecf20Sopenharmony_ci *    redistribution must be conditioned upon including a substantially
388c2ecf20Sopenharmony_ci *    similar Disclaimer requirement for further binary redistribution.
398c2ecf20Sopenharmony_ci * 3. Neither the names of the above-listed copyright holders nor the names
408c2ecf20Sopenharmony_ci *    of any contributors may be used to endorse or promote products derived
418c2ecf20Sopenharmony_ci *    from this software without specific prior written permission.
428c2ecf20Sopenharmony_ci *
438c2ecf20Sopenharmony_ci * Alternatively, this software may be distributed under the terms of the
448c2ecf20Sopenharmony_ci * GNU General Public License ("GPL") version 2 as published by the Free
458c2ecf20Sopenharmony_ci * Software Foundation.
468c2ecf20Sopenharmony_ci *
478c2ecf20Sopenharmony_ci * NO WARRANTY
488c2ecf20Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
498c2ecf20Sopenharmony_ci * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
508c2ecf20Sopenharmony_ci * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
518c2ecf20Sopenharmony_ci * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
528c2ecf20Sopenharmony_ci * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
538c2ecf20Sopenharmony_ci * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
548c2ecf20Sopenharmony_ci * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
558c2ecf20Sopenharmony_ci * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
568c2ecf20Sopenharmony_ci * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
578c2ecf20Sopenharmony_ci * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
588c2ecf20Sopenharmony_ci * THE POSSIBILITY OF SUCH DAMAGES.
598c2ecf20Sopenharmony_ci */
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci#include <linux/export.h>
648c2ecf20Sopenharmony_ci#include <linux/moduleparam.h>
658c2ecf20Sopenharmony_ci#include <linux/vmalloc.h>
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci#include <linux/seq_file.h>
688c2ecf20Sopenharmony_ci#include <linux/list.h>
698c2ecf20Sopenharmony_ci#include "debug.h"
708c2ecf20Sopenharmony_ci#include "ath5k.h"
718c2ecf20Sopenharmony_ci#include "reg.h"
728c2ecf20Sopenharmony_ci#include "base.h"
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_cistatic unsigned int ath5k_debug;
758c2ecf20Sopenharmony_cimodule_param_named(debug, ath5k_debug, uint, 0);
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci/* debugfs: registers */
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_cistruct reg {
818c2ecf20Sopenharmony_ci	const char *name;
828c2ecf20Sopenharmony_ci	int addr;
838c2ecf20Sopenharmony_ci};
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci#define REG_STRUCT_INIT(r) { #r, r }
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci/* just a few random registers, might want to add more */
888c2ecf20Sopenharmony_cistatic const struct reg regs[] = {
898c2ecf20Sopenharmony_ci	REG_STRUCT_INIT(AR5K_CR),
908c2ecf20Sopenharmony_ci	REG_STRUCT_INIT(AR5K_RXDP),
918c2ecf20Sopenharmony_ci	REG_STRUCT_INIT(AR5K_CFG),
928c2ecf20Sopenharmony_ci	REG_STRUCT_INIT(AR5K_IER),
938c2ecf20Sopenharmony_ci	REG_STRUCT_INIT(AR5K_BCR),
948c2ecf20Sopenharmony_ci	REG_STRUCT_INIT(AR5K_RTSD0),
958c2ecf20Sopenharmony_ci	REG_STRUCT_INIT(AR5K_RTSD1),
968c2ecf20Sopenharmony_ci	REG_STRUCT_INIT(AR5K_TXCFG),
978c2ecf20Sopenharmony_ci	REG_STRUCT_INIT(AR5K_RXCFG),
988c2ecf20Sopenharmony_ci	REG_STRUCT_INIT(AR5K_RXJLA),
998c2ecf20Sopenharmony_ci	REG_STRUCT_INIT(AR5K_MIBC),
1008c2ecf20Sopenharmony_ci	REG_STRUCT_INIT(AR5K_TOPS),
1018c2ecf20Sopenharmony_ci	REG_STRUCT_INIT(AR5K_RXNOFRM),
1028c2ecf20Sopenharmony_ci	REG_STRUCT_INIT(AR5K_TXNOFRM),
1038c2ecf20Sopenharmony_ci	REG_STRUCT_INIT(AR5K_RPGTO),
1048c2ecf20Sopenharmony_ci	REG_STRUCT_INIT(AR5K_RFCNT),
1058c2ecf20Sopenharmony_ci	REG_STRUCT_INIT(AR5K_MISC),
1068c2ecf20Sopenharmony_ci	REG_STRUCT_INIT(AR5K_QCUDCU_CLKGT),
1078c2ecf20Sopenharmony_ci	REG_STRUCT_INIT(AR5K_ISR),
1088c2ecf20Sopenharmony_ci	REG_STRUCT_INIT(AR5K_PISR),
1098c2ecf20Sopenharmony_ci	REG_STRUCT_INIT(AR5K_SISR0),
1108c2ecf20Sopenharmony_ci	REG_STRUCT_INIT(AR5K_SISR1),
1118c2ecf20Sopenharmony_ci	REG_STRUCT_INIT(AR5K_SISR2),
1128c2ecf20Sopenharmony_ci	REG_STRUCT_INIT(AR5K_SISR3),
1138c2ecf20Sopenharmony_ci	REG_STRUCT_INIT(AR5K_SISR4),
1148c2ecf20Sopenharmony_ci	REG_STRUCT_INIT(AR5K_IMR),
1158c2ecf20Sopenharmony_ci	REG_STRUCT_INIT(AR5K_PIMR),
1168c2ecf20Sopenharmony_ci	REG_STRUCT_INIT(AR5K_SIMR0),
1178c2ecf20Sopenharmony_ci	REG_STRUCT_INIT(AR5K_SIMR1),
1188c2ecf20Sopenharmony_ci	REG_STRUCT_INIT(AR5K_SIMR2),
1198c2ecf20Sopenharmony_ci	REG_STRUCT_INIT(AR5K_SIMR3),
1208c2ecf20Sopenharmony_ci	REG_STRUCT_INIT(AR5K_SIMR4),
1218c2ecf20Sopenharmony_ci	REG_STRUCT_INIT(AR5K_DCM_ADDR),
1228c2ecf20Sopenharmony_ci	REG_STRUCT_INIT(AR5K_DCCFG),
1238c2ecf20Sopenharmony_ci	REG_STRUCT_INIT(AR5K_CCFG),
1248c2ecf20Sopenharmony_ci	REG_STRUCT_INIT(AR5K_CPC0),
1258c2ecf20Sopenharmony_ci	REG_STRUCT_INIT(AR5K_CPC1),
1268c2ecf20Sopenharmony_ci	REG_STRUCT_INIT(AR5K_CPC2),
1278c2ecf20Sopenharmony_ci	REG_STRUCT_INIT(AR5K_CPC3),
1288c2ecf20Sopenharmony_ci	REG_STRUCT_INIT(AR5K_CPCOVF),
1298c2ecf20Sopenharmony_ci	REG_STRUCT_INIT(AR5K_RESET_CTL),
1308c2ecf20Sopenharmony_ci	REG_STRUCT_INIT(AR5K_SLEEP_CTL),
1318c2ecf20Sopenharmony_ci	REG_STRUCT_INIT(AR5K_INTPEND),
1328c2ecf20Sopenharmony_ci	REG_STRUCT_INIT(AR5K_SFR),
1338c2ecf20Sopenharmony_ci	REG_STRUCT_INIT(AR5K_PCICFG),
1348c2ecf20Sopenharmony_ci	REG_STRUCT_INIT(AR5K_GPIOCR),
1358c2ecf20Sopenharmony_ci	REG_STRUCT_INIT(AR5K_GPIODO),
1368c2ecf20Sopenharmony_ci	REG_STRUCT_INIT(AR5K_SREV),
1378c2ecf20Sopenharmony_ci};
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_cistatic void *reg_start(struct seq_file *seq, loff_t *pos)
1408c2ecf20Sopenharmony_ci{
1418c2ecf20Sopenharmony_ci	return *pos < ARRAY_SIZE(regs) ? (void *)&regs[*pos] : NULL;
1428c2ecf20Sopenharmony_ci}
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_cistatic void reg_stop(struct seq_file *seq, void *p)
1458c2ecf20Sopenharmony_ci{
1468c2ecf20Sopenharmony_ci	/* nothing to do */
1478c2ecf20Sopenharmony_ci}
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_cistatic void *reg_next(struct seq_file *seq, void *p, loff_t *pos)
1508c2ecf20Sopenharmony_ci{
1518c2ecf20Sopenharmony_ci	++*pos;
1528c2ecf20Sopenharmony_ci	return *pos < ARRAY_SIZE(regs) ? (void *)&regs[*pos] : NULL;
1538c2ecf20Sopenharmony_ci}
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_cistatic int reg_show(struct seq_file *seq, void *p)
1568c2ecf20Sopenharmony_ci{
1578c2ecf20Sopenharmony_ci	struct ath5k_hw *ah = seq->private;
1588c2ecf20Sopenharmony_ci	struct reg *r = p;
1598c2ecf20Sopenharmony_ci	seq_printf(seq, "%-25s0x%08x\n", r->name,
1608c2ecf20Sopenharmony_ci		ath5k_hw_reg_read(ah, r->addr));
1618c2ecf20Sopenharmony_ci	return 0;
1628c2ecf20Sopenharmony_ci}
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_cistatic const struct seq_operations registers_sops = {
1658c2ecf20Sopenharmony_ci	.start = reg_start,
1668c2ecf20Sopenharmony_ci	.next  = reg_next,
1678c2ecf20Sopenharmony_ci	.stop  = reg_stop,
1688c2ecf20Sopenharmony_ci	.show  = reg_show
1698c2ecf20Sopenharmony_ci};
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ciDEFINE_SEQ_ATTRIBUTE(registers);
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci/* debugfs: beacons */
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_cistatic ssize_t read_file_beacon(struct file *file, char __user *user_buf,
1768c2ecf20Sopenharmony_ci				   size_t count, loff_t *ppos)
1778c2ecf20Sopenharmony_ci{
1788c2ecf20Sopenharmony_ci	struct ath5k_hw *ah = file->private_data;
1798c2ecf20Sopenharmony_ci	char buf[500];
1808c2ecf20Sopenharmony_ci	unsigned int len = 0;
1818c2ecf20Sopenharmony_ci	unsigned int v;
1828c2ecf20Sopenharmony_ci	u64 tsf;
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	v = ath5k_hw_reg_read(ah, AR5K_BEACON);
1858c2ecf20Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len,
1868c2ecf20Sopenharmony_ci		"%-24s0x%08x\tintval: %d\tTIM: 0x%x\n",
1878c2ecf20Sopenharmony_ci		"AR5K_BEACON", v, v & AR5K_BEACON_PERIOD,
1888c2ecf20Sopenharmony_ci		(v & AR5K_BEACON_TIM) >> AR5K_BEACON_TIM_S);
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len, "%-24s0x%08x\n",
1918c2ecf20Sopenharmony_ci		"AR5K_LAST_TSTP", ath5k_hw_reg_read(ah, AR5K_LAST_TSTP));
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len, "%-24s0x%08x\n\n",
1948c2ecf20Sopenharmony_ci		"AR5K_BEACON_CNT", ath5k_hw_reg_read(ah, AR5K_BEACON_CNT));
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci	v = ath5k_hw_reg_read(ah, AR5K_TIMER0);
1978c2ecf20Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len, "%-24s0x%08x\tTU: %08x\n",
1988c2ecf20Sopenharmony_ci		"AR5K_TIMER0 (TBTT)", v, v);
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci	v = ath5k_hw_reg_read(ah, AR5K_TIMER1);
2018c2ecf20Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len, "%-24s0x%08x\tTU: %08x\n",
2028c2ecf20Sopenharmony_ci		"AR5K_TIMER1 (DMA)", v, v >> 3);
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci	v = ath5k_hw_reg_read(ah, AR5K_TIMER2);
2058c2ecf20Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len, "%-24s0x%08x\tTU: %08x\n",
2068c2ecf20Sopenharmony_ci		"AR5K_TIMER2 (SWBA)", v, v >> 3);
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci	v = ath5k_hw_reg_read(ah, AR5K_TIMER3);
2098c2ecf20Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len, "%-24s0x%08x\tTU: %08x\n",
2108c2ecf20Sopenharmony_ci		"AR5K_TIMER3 (ATIM)", v, v);
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci	tsf = ath5k_hw_get_tsf64(ah);
2138c2ecf20Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len,
2148c2ecf20Sopenharmony_ci		"TSF\t\t0x%016llx\tTU: %08x\n",
2158c2ecf20Sopenharmony_ci		(unsigned long long)tsf, TSF_TO_TU(tsf));
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci	if (len > sizeof(buf))
2188c2ecf20Sopenharmony_ci		len = sizeof(buf);
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
2218c2ecf20Sopenharmony_ci}
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_cistatic ssize_t write_file_beacon(struct file *file,
2248c2ecf20Sopenharmony_ci				 const char __user *userbuf,
2258c2ecf20Sopenharmony_ci				 size_t count, loff_t *ppos)
2268c2ecf20Sopenharmony_ci{
2278c2ecf20Sopenharmony_ci	struct ath5k_hw *ah = file->private_data;
2288c2ecf20Sopenharmony_ci	char buf[20];
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci	count = min_t(size_t, count, sizeof(buf) - 1);
2318c2ecf20Sopenharmony_ci	if (copy_from_user(buf, userbuf, count))
2328c2ecf20Sopenharmony_ci		return -EFAULT;
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci	buf[count] = '\0';
2358c2ecf20Sopenharmony_ci	if (strncmp(buf, "disable", 7) == 0) {
2368c2ecf20Sopenharmony_ci		AR5K_REG_DISABLE_BITS(ah, AR5K_BEACON, AR5K_BEACON_ENABLE);
2378c2ecf20Sopenharmony_ci		pr_info("debugfs disable beacons\n");
2388c2ecf20Sopenharmony_ci	} else if (strncmp(buf, "enable", 6) == 0) {
2398c2ecf20Sopenharmony_ci		AR5K_REG_ENABLE_BITS(ah, AR5K_BEACON, AR5K_BEACON_ENABLE);
2408c2ecf20Sopenharmony_ci		pr_info("debugfs enable beacons\n");
2418c2ecf20Sopenharmony_ci	}
2428c2ecf20Sopenharmony_ci	return count;
2438c2ecf20Sopenharmony_ci}
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_cistatic const struct file_operations fops_beacon = {
2468c2ecf20Sopenharmony_ci	.read = read_file_beacon,
2478c2ecf20Sopenharmony_ci	.write = write_file_beacon,
2488c2ecf20Sopenharmony_ci	.open = simple_open,
2498c2ecf20Sopenharmony_ci	.owner = THIS_MODULE,
2508c2ecf20Sopenharmony_ci	.llseek = default_llseek,
2518c2ecf20Sopenharmony_ci};
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci/* debugfs: reset */
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_cistatic ssize_t write_file_reset(struct file *file,
2578c2ecf20Sopenharmony_ci				 const char __user *userbuf,
2588c2ecf20Sopenharmony_ci				 size_t count, loff_t *ppos)
2598c2ecf20Sopenharmony_ci{
2608c2ecf20Sopenharmony_ci	struct ath5k_hw *ah = file->private_data;
2618c2ecf20Sopenharmony_ci	ATH5K_DBG(ah, ATH5K_DEBUG_RESET, "debug file triggered reset\n");
2628c2ecf20Sopenharmony_ci	ieee80211_queue_work(ah->hw, &ah->reset_work);
2638c2ecf20Sopenharmony_ci	return count;
2648c2ecf20Sopenharmony_ci}
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_cistatic const struct file_operations fops_reset = {
2678c2ecf20Sopenharmony_ci	.write = write_file_reset,
2688c2ecf20Sopenharmony_ci	.open = simple_open,
2698c2ecf20Sopenharmony_ci	.owner = THIS_MODULE,
2708c2ecf20Sopenharmony_ci	.llseek = noop_llseek,
2718c2ecf20Sopenharmony_ci};
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci/* debugfs: debug level */
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_cistatic const struct {
2778c2ecf20Sopenharmony_ci	enum ath5k_debug_level level;
2788c2ecf20Sopenharmony_ci	const char *name;
2798c2ecf20Sopenharmony_ci	const char *desc;
2808c2ecf20Sopenharmony_ci} dbg_info[] = {
2818c2ecf20Sopenharmony_ci	{ ATH5K_DEBUG_RESET,	"reset",	"reset and initialization" },
2828c2ecf20Sopenharmony_ci	{ ATH5K_DEBUG_INTR,	"intr",		"interrupt handling" },
2838c2ecf20Sopenharmony_ci	{ ATH5K_DEBUG_MODE,	"mode",		"mode init/setup" },
2848c2ecf20Sopenharmony_ci	{ ATH5K_DEBUG_XMIT,	"xmit",		"basic xmit operation" },
2858c2ecf20Sopenharmony_ci	{ ATH5K_DEBUG_BEACON,	"beacon",	"beacon handling" },
2868c2ecf20Sopenharmony_ci	{ ATH5K_DEBUG_CALIBRATE, "calib",	"periodic calibration" },
2878c2ecf20Sopenharmony_ci	{ ATH5K_DEBUG_TXPOWER,	"txpower",	"transmit power setting" },
2888c2ecf20Sopenharmony_ci	{ ATH5K_DEBUG_LED,	"led",		"LED management" },
2898c2ecf20Sopenharmony_ci	{ ATH5K_DEBUG_DUMPBANDS, "dumpbands",	"dump bands" },
2908c2ecf20Sopenharmony_ci	{ ATH5K_DEBUG_DMA,	"dma",		"dma start/stop" },
2918c2ecf20Sopenharmony_ci	{ ATH5K_DEBUG_ANI,	"ani",		"adaptive noise immunity" },
2928c2ecf20Sopenharmony_ci	{ ATH5K_DEBUG_DESC,	"desc",		"descriptor chains" },
2938c2ecf20Sopenharmony_ci	{ ATH5K_DEBUG_ANY,	"all",		"show all debug levels" },
2948c2ecf20Sopenharmony_ci};
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_cistatic ssize_t read_file_debug(struct file *file, char __user *user_buf,
2978c2ecf20Sopenharmony_ci				   size_t count, loff_t *ppos)
2988c2ecf20Sopenharmony_ci{
2998c2ecf20Sopenharmony_ci	struct ath5k_hw *ah = file->private_data;
3008c2ecf20Sopenharmony_ci	char buf[700];
3018c2ecf20Sopenharmony_ci	unsigned int len = 0;
3028c2ecf20Sopenharmony_ci	unsigned int i;
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len,
3058c2ecf20Sopenharmony_ci		"DEBUG LEVEL: 0x%08x\n\n", ah->debug.level);
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(dbg_info) - 1; i++) {
3088c2ecf20Sopenharmony_ci		len += scnprintf(buf + len, sizeof(buf) - len,
3098c2ecf20Sopenharmony_ci			"%10s %c 0x%08x - %s\n", dbg_info[i].name,
3108c2ecf20Sopenharmony_ci			ah->debug.level & dbg_info[i].level ? '+' : ' ',
3118c2ecf20Sopenharmony_ci			dbg_info[i].level, dbg_info[i].desc);
3128c2ecf20Sopenharmony_ci	}
3138c2ecf20Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len,
3148c2ecf20Sopenharmony_ci		"%10s %c 0x%08x - %s\n", dbg_info[i].name,
3158c2ecf20Sopenharmony_ci		ah->debug.level == dbg_info[i].level ? '+' : ' ',
3168c2ecf20Sopenharmony_ci		dbg_info[i].level, dbg_info[i].desc);
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci	if (len > sizeof(buf))
3198c2ecf20Sopenharmony_ci		len = sizeof(buf);
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
3228c2ecf20Sopenharmony_ci}
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_cistatic ssize_t write_file_debug(struct file *file,
3258c2ecf20Sopenharmony_ci				 const char __user *userbuf,
3268c2ecf20Sopenharmony_ci				 size_t count, loff_t *ppos)
3278c2ecf20Sopenharmony_ci{
3288c2ecf20Sopenharmony_ci	struct ath5k_hw *ah = file->private_data;
3298c2ecf20Sopenharmony_ci	unsigned int i;
3308c2ecf20Sopenharmony_ci	char buf[20];
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_ci	count = min_t(size_t, count, sizeof(buf) - 1);
3338c2ecf20Sopenharmony_ci	if (copy_from_user(buf, userbuf, count))
3348c2ecf20Sopenharmony_ci		return -EFAULT;
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci	buf[count] = '\0';
3378c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(dbg_info); i++) {
3388c2ecf20Sopenharmony_ci		if (strncmp(buf, dbg_info[i].name,
3398c2ecf20Sopenharmony_ci					strlen(dbg_info[i].name)) == 0) {
3408c2ecf20Sopenharmony_ci			ah->debug.level ^= dbg_info[i].level; /* toggle bit */
3418c2ecf20Sopenharmony_ci			break;
3428c2ecf20Sopenharmony_ci		}
3438c2ecf20Sopenharmony_ci	}
3448c2ecf20Sopenharmony_ci	return count;
3458c2ecf20Sopenharmony_ci}
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_cistatic const struct file_operations fops_debug = {
3488c2ecf20Sopenharmony_ci	.read = read_file_debug,
3498c2ecf20Sopenharmony_ci	.write = write_file_debug,
3508c2ecf20Sopenharmony_ci	.open = simple_open,
3518c2ecf20Sopenharmony_ci	.owner = THIS_MODULE,
3528c2ecf20Sopenharmony_ci	.llseek = default_llseek,
3538c2ecf20Sopenharmony_ci};
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci/* debugfs: antenna */
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_cistatic ssize_t read_file_antenna(struct file *file, char __user *user_buf,
3598c2ecf20Sopenharmony_ci				   size_t count, loff_t *ppos)
3608c2ecf20Sopenharmony_ci{
3618c2ecf20Sopenharmony_ci	struct ath5k_hw *ah = file->private_data;
3628c2ecf20Sopenharmony_ci	char buf[700];
3638c2ecf20Sopenharmony_ci	unsigned int len = 0;
3648c2ecf20Sopenharmony_ci	unsigned int i;
3658c2ecf20Sopenharmony_ci	unsigned int v;
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len, "antenna mode\t%d\n",
3688c2ecf20Sopenharmony_ci		ah->ah_ant_mode);
3698c2ecf20Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len, "default antenna\t%d\n",
3708c2ecf20Sopenharmony_ci		ah->ah_def_ant);
3718c2ecf20Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len, "tx antenna\t%d\n",
3728c2ecf20Sopenharmony_ci		ah->ah_tx_ant);
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len, "\nANTENNA\t\tRX\tTX\n");
3758c2ecf20Sopenharmony_ci	for (i = 1; i < ARRAY_SIZE(ah->stats.antenna_rx); i++) {
3768c2ecf20Sopenharmony_ci		len += scnprintf(buf + len, sizeof(buf) - len,
3778c2ecf20Sopenharmony_ci			"[antenna %d]\t%d\t%d\n",
3788c2ecf20Sopenharmony_ci			i, ah->stats.antenna_rx[i], ah->stats.antenna_tx[i]);
3798c2ecf20Sopenharmony_ci	}
3808c2ecf20Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len, "[invalid]\t%d\t%d\n",
3818c2ecf20Sopenharmony_ci			ah->stats.antenna_rx[0], ah->stats.antenna_tx[0]);
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_ci	v = ath5k_hw_reg_read(ah, AR5K_DEFAULT_ANTENNA);
3848c2ecf20Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len,
3858c2ecf20Sopenharmony_ci			"\nAR5K_DEFAULT_ANTENNA\t0x%08x\n", v);
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci	v = ath5k_hw_reg_read(ah, AR5K_STA_ID1);
3888c2ecf20Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len,
3898c2ecf20Sopenharmony_ci		"AR5K_STA_ID1_DEFAULT_ANTENNA\t%d\n",
3908c2ecf20Sopenharmony_ci		(v & AR5K_STA_ID1_DEFAULT_ANTENNA) != 0);
3918c2ecf20Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len,
3928c2ecf20Sopenharmony_ci		"AR5K_STA_ID1_DESC_ANTENNA\t%d\n",
3938c2ecf20Sopenharmony_ci		(v & AR5K_STA_ID1_DESC_ANTENNA) != 0);
3948c2ecf20Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len,
3958c2ecf20Sopenharmony_ci		"AR5K_STA_ID1_RTS_DEF_ANTENNA\t%d\n",
3968c2ecf20Sopenharmony_ci		(v & AR5K_STA_ID1_RTS_DEF_ANTENNA) != 0);
3978c2ecf20Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len,
3988c2ecf20Sopenharmony_ci		"AR5K_STA_ID1_SELFGEN_DEF_ANT\t%d\n",
3998c2ecf20Sopenharmony_ci		(v & AR5K_STA_ID1_SELFGEN_DEF_ANT) != 0);
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ci	v = ath5k_hw_reg_read(ah, AR5K_PHY_AGCCTL);
4028c2ecf20Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len,
4038c2ecf20Sopenharmony_ci		"\nAR5K_PHY_AGCCTL_OFDM_DIV_DIS\t%d\n",
4048c2ecf20Sopenharmony_ci		(v & AR5K_PHY_AGCCTL_OFDM_DIV_DIS) != 0);
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ci	v = ath5k_hw_reg_read(ah, AR5K_PHY_RESTART);
4078c2ecf20Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len,
4088c2ecf20Sopenharmony_ci		"AR5K_PHY_RESTART_DIV_GC\t\t%x\n",
4098c2ecf20Sopenharmony_ci		(v & AR5K_PHY_RESTART_DIV_GC) >> AR5K_PHY_RESTART_DIV_GC_S);
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_ci	v = ath5k_hw_reg_read(ah, AR5K_PHY_FAST_ANT_DIV);
4128c2ecf20Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len,
4138c2ecf20Sopenharmony_ci		"AR5K_PHY_FAST_ANT_DIV_EN\t%d\n",
4148c2ecf20Sopenharmony_ci		(v & AR5K_PHY_FAST_ANT_DIV_EN) != 0);
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_ci	v = ath5k_hw_reg_read(ah, AR5K_PHY_ANT_SWITCH_TABLE_0);
4178c2ecf20Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len,
4188c2ecf20Sopenharmony_ci			"\nAR5K_PHY_ANT_SWITCH_TABLE_0\t0x%08x\n", v);
4198c2ecf20Sopenharmony_ci	v = ath5k_hw_reg_read(ah, AR5K_PHY_ANT_SWITCH_TABLE_1);
4208c2ecf20Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len,
4218c2ecf20Sopenharmony_ci			"AR5K_PHY_ANT_SWITCH_TABLE_1\t0x%08x\n", v);
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_ci	if (len > sizeof(buf))
4248c2ecf20Sopenharmony_ci		len = sizeof(buf);
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_ci	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
4278c2ecf20Sopenharmony_ci}
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_cistatic ssize_t write_file_antenna(struct file *file,
4308c2ecf20Sopenharmony_ci				 const char __user *userbuf,
4318c2ecf20Sopenharmony_ci				 size_t count, loff_t *ppos)
4328c2ecf20Sopenharmony_ci{
4338c2ecf20Sopenharmony_ci	struct ath5k_hw *ah = file->private_data;
4348c2ecf20Sopenharmony_ci	unsigned int i;
4358c2ecf20Sopenharmony_ci	char buf[20];
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ci	count = min_t(size_t, count, sizeof(buf) - 1);
4388c2ecf20Sopenharmony_ci	if (copy_from_user(buf, userbuf, count))
4398c2ecf20Sopenharmony_ci		return -EFAULT;
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_ci	buf[count] = '\0';
4428c2ecf20Sopenharmony_ci	if (strncmp(buf, "diversity", 9) == 0) {
4438c2ecf20Sopenharmony_ci		ath5k_hw_set_antenna_mode(ah, AR5K_ANTMODE_DEFAULT);
4448c2ecf20Sopenharmony_ci		pr_info("debug: enable diversity\n");
4458c2ecf20Sopenharmony_ci	} else if (strncmp(buf, "fixed-a", 7) == 0) {
4468c2ecf20Sopenharmony_ci		ath5k_hw_set_antenna_mode(ah, AR5K_ANTMODE_FIXED_A);
4478c2ecf20Sopenharmony_ci		pr_info("debug: fixed antenna A\n");
4488c2ecf20Sopenharmony_ci	} else if (strncmp(buf, "fixed-b", 7) == 0) {
4498c2ecf20Sopenharmony_ci		ath5k_hw_set_antenna_mode(ah, AR5K_ANTMODE_FIXED_B);
4508c2ecf20Sopenharmony_ci		pr_info("debug: fixed antenna B\n");
4518c2ecf20Sopenharmony_ci	} else if (strncmp(buf, "clear", 5) == 0) {
4528c2ecf20Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(ah->stats.antenna_rx); i++) {
4538c2ecf20Sopenharmony_ci			ah->stats.antenna_rx[i] = 0;
4548c2ecf20Sopenharmony_ci			ah->stats.antenna_tx[i] = 0;
4558c2ecf20Sopenharmony_ci		}
4568c2ecf20Sopenharmony_ci		pr_info("debug: cleared antenna stats\n");
4578c2ecf20Sopenharmony_ci	}
4588c2ecf20Sopenharmony_ci	return count;
4598c2ecf20Sopenharmony_ci}
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_cistatic const struct file_operations fops_antenna = {
4628c2ecf20Sopenharmony_ci	.read = read_file_antenna,
4638c2ecf20Sopenharmony_ci	.write = write_file_antenna,
4648c2ecf20Sopenharmony_ci	.open = simple_open,
4658c2ecf20Sopenharmony_ci	.owner = THIS_MODULE,
4668c2ecf20Sopenharmony_ci	.llseek = default_llseek,
4678c2ecf20Sopenharmony_ci};
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_ci/* debugfs: misc */
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_cistatic ssize_t read_file_misc(struct file *file, char __user *user_buf,
4728c2ecf20Sopenharmony_ci				   size_t count, loff_t *ppos)
4738c2ecf20Sopenharmony_ci{
4748c2ecf20Sopenharmony_ci	struct ath5k_hw *ah = file->private_data;
4758c2ecf20Sopenharmony_ci	char buf[700];
4768c2ecf20Sopenharmony_ci	unsigned int len = 0;
4778c2ecf20Sopenharmony_ci	u32 filt = ath5k_hw_get_rx_filter(ah);
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len, "bssid-mask: %pM\n",
4808c2ecf20Sopenharmony_ci			ah->bssidmask);
4818c2ecf20Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len, "filter-flags: 0x%x ",
4828c2ecf20Sopenharmony_ci			filt);
4838c2ecf20Sopenharmony_ci	if (filt & AR5K_RX_FILTER_UCAST)
4848c2ecf20Sopenharmony_ci		len += scnprintf(buf + len, sizeof(buf) - len, " UCAST");
4858c2ecf20Sopenharmony_ci	if (filt & AR5K_RX_FILTER_MCAST)
4868c2ecf20Sopenharmony_ci		len += scnprintf(buf + len, sizeof(buf) - len, " MCAST");
4878c2ecf20Sopenharmony_ci	if (filt & AR5K_RX_FILTER_BCAST)
4888c2ecf20Sopenharmony_ci		len += scnprintf(buf + len, sizeof(buf) - len, " BCAST");
4898c2ecf20Sopenharmony_ci	if (filt & AR5K_RX_FILTER_CONTROL)
4908c2ecf20Sopenharmony_ci		len += scnprintf(buf + len, sizeof(buf) - len, " CONTROL");
4918c2ecf20Sopenharmony_ci	if (filt & AR5K_RX_FILTER_BEACON)
4928c2ecf20Sopenharmony_ci		len += scnprintf(buf + len, sizeof(buf) - len, " BEACON");
4938c2ecf20Sopenharmony_ci	if (filt & AR5K_RX_FILTER_PROM)
4948c2ecf20Sopenharmony_ci		len += scnprintf(buf + len, sizeof(buf) - len, " PROM");
4958c2ecf20Sopenharmony_ci	if (filt & AR5K_RX_FILTER_XRPOLL)
4968c2ecf20Sopenharmony_ci		len += scnprintf(buf + len, sizeof(buf) - len, " XRPOLL");
4978c2ecf20Sopenharmony_ci	if (filt & AR5K_RX_FILTER_PROBEREQ)
4988c2ecf20Sopenharmony_ci		len += scnprintf(buf + len, sizeof(buf) - len, " PROBEREQ");
4998c2ecf20Sopenharmony_ci	if (filt & AR5K_RX_FILTER_PHYERR_5212)
5008c2ecf20Sopenharmony_ci		len += scnprintf(buf + len, sizeof(buf) - len, " PHYERR-5212");
5018c2ecf20Sopenharmony_ci	if (filt & AR5K_RX_FILTER_RADARERR_5212)
5028c2ecf20Sopenharmony_ci		len += scnprintf(buf + len, sizeof(buf) - len, " RADARERR-5212");
5038c2ecf20Sopenharmony_ci	if (filt & AR5K_RX_FILTER_PHYERR_5211)
5048c2ecf20Sopenharmony_ci		snprintf(buf + len, sizeof(buf) - len, " PHYERR-5211");
5058c2ecf20Sopenharmony_ci	if (filt & AR5K_RX_FILTER_RADARERR_5211)
5068c2ecf20Sopenharmony_ci		len += scnprintf(buf + len, sizeof(buf) - len, " RADARERR-5211");
5078c2ecf20Sopenharmony_ci
5088c2ecf20Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len, "\nopmode: %s (%d)\n",
5098c2ecf20Sopenharmony_ci			ath_opmode_to_string(ah->opmode), ah->opmode);
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_ci	if (len > sizeof(buf))
5128c2ecf20Sopenharmony_ci		len = sizeof(buf);
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_ci	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
5158c2ecf20Sopenharmony_ci}
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_cistatic const struct file_operations fops_misc = {
5188c2ecf20Sopenharmony_ci	.read = read_file_misc,
5198c2ecf20Sopenharmony_ci	.open = simple_open,
5208c2ecf20Sopenharmony_ci	.owner = THIS_MODULE,
5218c2ecf20Sopenharmony_ci};
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_ci
5248c2ecf20Sopenharmony_ci/* debugfs: frameerrors */
5258c2ecf20Sopenharmony_ci
5268c2ecf20Sopenharmony_cistatic ssize_t read_file_frameerrors(struct file *file, char __user *user_buf,
5278c2ecf20Sopenharmony_ci				   size_t count, loff_t *ppos)
5288c2ecf20Sopenharmony_ci{
5298c2ecf20Sopenharmony_ci	struct ath5k_hw *ah = file->private_data;
5308c2ecf20Sopenharmony_ci	struct ath5k_statistics *st = &ah->stats;
5318c2ecf20Sopenharmony_ci	char buf[700];
5328c2ecf20Sopenharmony_ci	unsigned int len = 0;
5338c2ecf20Sopenharmony_ci	int i;
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len,
5368c2ecf20Sopenharmony_ci			"RX\n---------------------\n");
5378c2ecf20Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len, "CRC\t%u\t(%u%%)\n",
5388c2ecf20Sopenharmony_ci			st->rxerr_crc,
5398c2ecf20Sopenharmony_ci			st->rx_all_count > 0 ?
5408c2ecf20Sopenharmony_ci				st->rxerr_crc * 100 / st->rx_all_count : 0);
5418c2ecf20Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len, "PHY\t%u\t(%u%%)\n",
5428c2ecf20Sopenharmony_ci			st->rxerr_phy,
5438c2ecf20Sopenharmony_ci			st->rx_all_count > 0 ?
5448c2ecf20Sopenharmony_ci				st->rxerr_phy * 100 / st->rx_all_count : 0);
5458c2ecf20Sopenharmony_ci	for (i = 0; i < 32; i++) {
5468c2ecf20Sopenharmony_ci		if (st->rxerr_phy_code[i])
5478c2ecf20Sopenharmony_ci			len += scnprintf(buf + len, sizeof(buf) - len,
5488c2ecf20Sopenharmony_ci				" phy_err[%u]\t%u\n",
5498c2ecf20Sopenharmony_ci				i, st->rxerr_phy_code[i]);
5508c2ecf20Sopenharmony_ci	}
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len, "FIFO\t%u\t(%u%%)\n",
5538c2ecf20Sopenharmony_ci			st->rxerr_fifo,
5548c2ecf20Sopenharmony_ci			st->rx_all_count > 0 ?
5558c2ecf20Sopenharmony_ci				st->rxerr_fifo * 100 / st->rx_all_count : 0);
5568c2ecf20Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len, "decrypt\t%u\t(%u%%)\n",
5578c2ecf20Sopenharmony_ci			st->rxerr_decrypt,
5588c2ecf20Sopenharmony_ci			st->rx_all_count > 0 ?
5598c2ecf20Sopenharmony_ci				st->rxerr_decrypt * 100 / st->rx_all_count : 0);
5608c2ecf20Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len, "MIC\t%u\t(%u%%)\n",
5618c2ecf20Sopenharmony_ci			st->rxerr_mic,
5628c2ecf20Sopenharmony_ci			st->rx_all_count > 0 ?
5638c2ecf20Sopenharmony_ci				st->rxerr_mic * 100 / st->rx_all_count : 0);
5648c2ecf20Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len, "process\t%u\t(%u%%)\n",
5658c2ecf20Sopenharmony_ci			st->rxerr_proc,
5668c2ecf20Sopenharmony_ci			st->rx_all_count > 0 ?
5678c2ecf20Sopenharmony_ci				st->rxerr_proc * 100 / st->rx_all_count : 0);
5688c2ecf20Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len, "jumbo\t%u\t(%u%%)\n",
5698c2ecf20Sopenharmony_ci			st->rxerr_jumbo,
5708c2ecf20Sopenharmony_ci			st->rx_all_count > 0 ?
5718c2ecf20Sopenharmony_ci				st->rxerr_jumbo * 100 / st->rx_all_count : 0);
5728c2ecf20Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len, "[RX all\t%u]\n",
5738c2ecf20Sopenharmony_ci			st->rx_all_count);
5748c2ecf20Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len, "RX-all-bytes\t%u\n",
5758c2ecf20Sopenharmony_ci			st->rx_bytes_count);
5768c2ecf20Sopenharmony_ci
5778c2ecf20Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len,
5788c2ecf20Sopenharmony_ci			"\nTX\n---------------------\n");
5798c2ecf20Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len, "retry\t%u\t(%u%%)\n",
5808c2ecf20Sopenharmony_ci			st->txerr_retry,
5818c2ecf20Sopenharmony_ci			st->tx_all_count > 0 ?
5828c2ecf20Sopenharmony_ci				st->txerr_retry * 100 / st->tx_all_count : 0);
5838c2ecf20Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len, "FIFO\t%u\t(%u%%)\n",
5848c2ecf20Sopenharmony_ci			st->txerr_fifo,
5858c2ecf20Sopenharmony_ci			st->tx_all_count > 0 ?
5868c2ecf20Sopenharmony_ci				st->txerr_fifo * 100 / st->tx_all_count : 0);
5878c2ecf20Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len, "filter\t%u\t(%u%%)\n",
5888c2ecf20Sopenharmony_ci			st->txerr_filt,
5898c2ecf20Sopenharmony_ci			st->tx_all_count > 0 ?
5908c2ecf20Sopenharmony_ci				st->txerr_filt * 100 / st->tx_all_count : 0);
5918c2ecf20Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len, "[TX all\t%u]\n",
5928c2ecf20Sopenharmony_ci			st->tx_all_count);
5938c2ecf20Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len, "TX-all-bytes\t%u\n",
5948c2ecf20Sopenharmony_ci			st->tx_bytes_count);
5958c2ecf20Sopenharmony_ci
5968c2ecf20Sopenharmony_ci	if (len > sizeof(buf))
5978c2ecf20Sopenharmony_ci		len = sizeof(buf);
5988c2ecf20Sopenharmony_ci
5998c2ecf20Sopenharmony_ci	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
6008c2ecf20Sopenharmony_ci}
6018c2ecf20Sopenharmony_ci
6028c2ecf20Sopenharmony_cistatic ssize_t write_file_frameerrors(struct file *file,
6038c2ecf20Sopenharmony_ci				 const char __user *userbuf,
6048c2ecf20Sopenharmony_ci				 size_t count, loff_t *ppos)
6058c2ecf20Sopenharmony_ci{
6068c2ecf20Sopenharmony_ci	struct ath5k_hw *ah = file->private_data;
6078c2ecf20Sopenharmony_ci	struct ath5k_statistics *st = &ah->stats;
6088c2ecf20Sopenharmony_ci	char buf[20];
6098c2ecf20Sopenharmony_ci
6108c2ecf20Sopenharmony_ci	count = min_t(size_t, count, sizeof(buf) - 1);
6118c2ecf20Sopenharmony_ci	if (copy_from_user(buf, userbuf, count))
6128c2ecf20Sopenharmony_ci		return -EFAULT;
6138c2ecf20Sopenharmony_ci
6148c2ecf20Sopenharmony_ci	buf[count] = '\0';
6158c2ecf20Sopenharmony_ci	if (strncmp(buf, "clear", 5) == 0) {
6168c2ecf20Sopenharmony_ci		st->rxerr_crc = 0;
6178c2ecf20Sopenharmony_ci		st->rxerr_phy = 0;
6188c2ecf20Sopenharmony_ci		st->rxerr_fifo = 0;
6198c2ecf20Sopenharmony_ci		st->rxerr_decrypt = 0;
6208c2ecf20Sopenharmony_ci		st->rxerr_mic = 0;
6218c2ecf20Sopenharmony_ci		st->rxerr_proc = 0;
6228c2ecf20Sopenharmony_ci		st->rxerr_jumbo = 0;
6238c2ecf20Sopenharmony_ci		st->rx_all_count = 0;
6248c2ecf20Sopenharmony_ci		st->txerr_retry = 0;
6258c2ecf20Sopenharmony_ci		st->txerr_fifo = 0;
6268c2ecf20Sopenharmony_ci		st->txerr_filt = 0;
6278c2ecf20Sopenharmony_ci		st->tx_all_count = 0;
6288c2ecf20Sopenharmony_ci		pr_info("debug: cleared frameerrors stats\n");
6298c2ecf20Sopenharmony_ci	}
6308c2ecf20Sopenharmony_ci	return count;
6318c2ecf20Sopenharmony_ci}
6328c2ecf20Sopenharmony_ci
6338c2ecf20Sopenharmony_cistatic const struct file_operations fops_frameerrors = {
6348c2ecf20Sopenharmony_ci	.read = read_file_frameerrors,
6358c2ecf20Sopenharmony_ci	.write = write_file_frameerrors,
6368c2ecf20Sopenharmony_ci	.open = simple_open,
6378c2ecf20Sopenharmony_ci	.owner = THIS_MODULE,
6388c2ecf20Sopenharmony_ci	.llseek = default_llseek,
6398c2ecf20Sopenharmony_ci};
6408c2ecf20Sopenharmony_ci
6418c2ecf20Sopenharmony_ci
6428c2ecf20Sopenharmony_ci/* debugfs: ani */
6438c2ecf20Sopenharmony_ci
6448c2ecf20Sopenharmony_cistatic ssize_t read_file_ani(struct file *file, char __user *user_buf,
6458c2ecf20Sopenharmony_ci				   size_t count, loff_t *ppos)
6468c2ecf20Sopenharmony_ci{
6478c2ecf20Sopenharmony_ci	struct ath5k_hw *ah = file->private_data;
6488c2ecf20Sopenharmony_ci	struct ath5k_statistics *st = &ah->stats;
6498c2ecf20Sopenharmony_ci	struct ath5k_ani_state *as = &ah->ani_state;
6508c2ecf20Sopenharmony_ci
6518c2ecf20Sopenharmony_ci	char buf[700];
6528c2ecf20Sopenharmony_ci	unsigned int len = 0;
6538c2ecf20Sopenharmony_ci
6548c2ecf20Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len,
6558c2ecf20Sopenharmony_ci			"HW has PHY error counters:\t%s\n",
6568c2ecf20Sopenharmony_ci			ah->ah_capabilities.cap_has_phyerr_counters ?
6578c2ecf20Sopenharmony_ci			"yes" : "no");
6588c2ecf20Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len,
6598c2ecf20Sopenharmony_ci			"HW max spur immunity level:\t%d\n",
6608c2ecf20Sopenharmony_ci			as->max_spur_level);
6618c2ecf20Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len,
6628c2ecf20Sopenharmony_ci		"\nANI state\n--------------------------------------------\n");
6638c2ecf20Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len, "operating mode:\t\t\t");
6648c2ecf20Sopenharmony_ci	switch (as->ani_mode) {
6658c2ecf20Sopenharmony_ci	case ATH5K_ANI_MODE_OFF:
6668c2ecf20Sopenharmony_ci		len += scnprintf(buf + len, sizeof(buf) - len, "OFF\n");
6678c2ecf20Sopenharmony_ci		break;
6688c2ecf20Sopenharmony_ci	case ATH5K_ANI_MODE_MANUAL_LOW:
6698c2ecf20Sopenharmony_ci		len += scnprintf(buf + len, sizeof(buf) - len,
6708c2ecf20Sopenharmony_ci			"MANUAL LOW\n");
6718c2ecf20Sopenharmony_ci		break;
6728c2ecf20Sopenharmony_ci	case ATH5K_ANI_MODE_MANUAL_HIGH:
6738c2ecf20Sopenharmony_ci		len += scnprintf(buf + len, sizeof(buf) - len,
6748c2ecf20Sopenharmony_ci			"MANUAL HIGH\n");
6758c2ecf20Sopenharmony_ci		break;
6768c2ecf20Sopenharmony_ci	case ATH5K_ANI_MODE_AUTO:
6778c2ecf20Sopenharmony_ci		len += scnprintf(buf + len, sizeof(buf) - len, "AUTO\n");
6788c2ecf20Sopenharmony_ci		break;
6798c2ecf20Sopenharmony_ci	default:
6808c2ecf20Sopenharmony_ci		len += scnprintf(buf + len, sizeof(buf) - len,
6818c2ecf20Sopenharmony_ci			"??? (not good)\n");
6828c2ecf20Sopenharmony_ci		break;
6838c2ecf20Sopenharmony_ci	}
6848c2ecf20Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len,
6858c2ecf20Sopenharmony_ci			"noise immunity level:\t\t%d\n",
6868c2ecf20Sopenharmony_ci			as->noise_imm_level);
6878c2ecf20Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len,
6888c2ecf20Sopenharmony_ci			"spur immunity level:\t\t%d\n",
6898c2ecf20Sopenharmony_ci			as->spur_level);
6908c2ecf20Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len,
6918c2ecf20Sopenharmony_ci			"firstep level:\t\t\t%d\n",
6928c2ecf20Sopenharmony_ci			as->firstep_level);
6938c2ecf20Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len,
6948c2ecf20Sopenharmony_ci			"OFDM weak signal detection:\t%s\n",
6958c2ecf20Sopenharmony_ci			as->ofdm_weak_sig ? "on" : "off");
6968c2ecf20Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len,
6978c2ecf20Sopenharmony_ci			"CCK weak signal detection:\t%s\n",
6988c2ecf20Sopenharmony_ci			as->cck_weak_sig ? "on" : "off");
6998c2ecf20Sopenharmony_ci
7008c2ecf20Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len,
7018c2ecf20Sopenharmony_ci			"\nMIB INTERRUPTS:\t\t%u\n",
7028c2ecf20Sopenharmony_ci			st->mib_intr);
7038c2ecf20Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len,
7048c2ecf20Sopenharmony_ci			"beacon RSSI average:\t%d\n",
7058c2ecf20Sopenharmony_ci			(int)ewma_beacon_rssi_read(&ah->ah_beacon_rssi_avg));
7068c2ecf20Sopenharmony_ci
7078c2ecf20Sopenharmony_ci#define CC_PRINT(_struct, _field) \
7088c2ecf20Sopenharmony_ci	_struct._field, \
7098c2ecf20Sopenharmony_ci	_struct.cycles > 0 ? \
7108c2ecf20Sopenharmony_ci	_struct._field * 100 / _struct.cycles : 0
7118c2ecf20Sopenharmony_ci
7128c2ecf20Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len,
7138c2ecf20Sopenharmony_ci			"profcnt tx\t\t%u\t(%d%%)\n",
7148c2ecf20Sopenharmony_ci			CC_PRINT(as->last_cc, tx_frame));
7158c2ecf20Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len,
7168c2ecf20Sopenharmony_ci			"profcnt rx\t\t%u\t(%d%%)\n",
7178c2ecf20Sopenharmony_ci			CC_PRINT(as->last_cc, rx_frame));
7188c2ecf20Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len,
7198c2ecf20Sopenharmony_ci			"profcnt busy\t\t%u\t(%d%%)\n",
7208c2ecf20Sopenharmony_ci			CC_PRINT(as->last_cc, rx_busy));
7218c2ecf20Sopenharmony_ci#undef CC_PRINT
7228c2ecf20Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len, "profcnt cycles\t\t%u\n",
7238c2ecf20Sopenharmony_ci			as->last_cc.cycles);
7248c2ecf20Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len,
7258c2ecf20Sopenharmony_ci			"listen time\t\t%d\tlast: %d\n",
7268c2ecf20Sopenharmony_ci			as->listen_time, as->last_listen);
7278c2ecf20Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len,
7288c2ecf20Sopenharmony_ci			"OFDM errors\t\t%u\tlast: %u\tsum: %u\n",
7298c2ecf20Sopenharmony_ci			as->ofdm_errors, as->last_ofdm_errors,
7308c2ecf20Sopenharmony_ci			as->sum_ofdm_errors);
7318c2ecf20Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len,
7328c2ecf20Sopenharmony_ci			"CCK errors\t\t%u\tlast: %u\tsum: %u\n",
7338c2ecf20Sopenharmony_ci			as->cck_errors, as->last_cck_errors,
7348c2ecf20Sopenharmony_ci			as->sum_cck_errors);
7358c2ecf20Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len,
7368c2ecf20Sopenharmony_ci			"AR5K_PHYERR_CNT1\t%x\t(=%d)\n",
7378c2ecf20Sopenharmony_ci			ath5k_hw_reg_read(ah, AR5K_PHYERR_CNT1),
7388c2ecf20Sopenharmony_ci			ATH5K_ANI_OFDM_TRIG_HIGH - (ATH5K_PHYERR_CNT_MAX -
7398c2ecf20Sopenharmony_ci			ath5k_hw_reg_read(ah, AR5K_PHYERR_CNT1)));
7408c2ecf20Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len,
7418c2ecf20Sopenharmony_ci			"AR5K_PHYERR_CNT2\t%x\t(=%d)\n",
7428c2ecf20Sopenharmony_ci			ath5k_hw_reg_read(ah, AR5K_PHYERR_CNT2),
7438c2ecf20Sopenharmony_ci			ATH5K_ANI_CCK_TRIG_HIGH - (ATH5K_PHYERR_CNT_MAX -
7448c2ecf20Sopenharmony_ci			ath5k_hw_reg_read(ah, AR5K_PHYERR_CNT2)));
7458c2ecf20Sopenharmony_ci
7468c2ecf20Sopenharmony_ci	if (len > sizeof(buf))
7478c2ecf20Sopenharmony_ci		len = sizeof(buf);
7488c2ecf20Sopenharmony_ci
7498c2ecf20Sopenharmony_ci	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
7508c2ecf20Sopenharmony_ci}
7518c2ecf20Sopenharmony_ci
7528c2ecf20Sopenharmony_cistatic ssize_t write_file_ani(struct file *file,
7538c2ecf20Sopenharmony_ci				 const char __user *userbuf,
7548c2ecf20Sopenharmony_ci				 size_t count, loff_t *ppos)
7558c2ecf20Sopenharmony_ci{
7568c2ecf20Sopenharmony_ci	struct ath5k_hw *ah = file->private_data;
7578c2ecf20Sopenharmony_ci	char buf[20];
7588c2ecf20Sopenharmony_ci
7598c2ecf20Sopenharmony_ci	count = min_t(size_t, count, sizeof(buf) - 1);
7608c2ecf20Sopenharmony_ci	if (copy_from_user(buf, userbuf, count))
7618c2ecf20Sopenharmony_ci		return -EFAULT;
7628c2ecf20Sopenharmony_ci
7638c2ecf20Sopenharmony_ci	buf[count] = '\0';
7648c2ecf20Sopenharmony_ci	if (strncmp(buf, "sens-low", 8) == 0) {
7658c2ecf20Sopenharmony_ci		ath5k_ani_init(ah, ATH5K_ANI_MODE_MANUAL_HIGH);
7668c2ecf20Sopenharmony_ci	} else if (strncmp(buf, "sens-high", 9) == 0) {
7678c2ecf20Sopenharmony_ci		ath5k_ani_init(ah, ATH5K_ANI_MODE_MANUAL_LOW);
7688c2ecf20Sopenharmony_ci	} else if (strncmp(buf, "ani-off", 7) == 0) {
7698c2ecf20Sopenharmony_ci		ath5k_ani_init(ah, ATH5K_ANI_MODE_OFF);
7708c2ecf20Sopenharmony_ci	} else if (strncmp(buf, "ani-on", 6) == 0) {
7718c2ecf20Sopenharmony_ci		ath5k_ani_init(ah, ATH5K_ANI_MODE_AUTO);
7728c2ecf20Sopenharmony_ci	} else if (strncmp(buf, "noise-low", 9) == 0) {
7738c2ecf20Sopenharmony_ci		ath5k_ani_set_noise_immunity_level(ah, 0);
7748c2ecf20Sopenharmony_ci	} else if (strncmp(buf, "noise-high", 10) == 0) {
7758c2ecf20Sopenharmony_ci		ath5k_ani_set_noise_immunity_level(ah,
7768c2ecf20Sopenharmony_ci						   ATH5K_ANI_MAX_NOISE_IMM_LVL);
7778c2ecf20Sopenharmony_ci	} else if (strncmp(buf, "spur-low", 8) == 0) {
7788c2ecf20Sopenharmony_ci		ath5k_ani_set_spur_immunity_level(ah, 0);
7798c2ecf20Sopenharmony_ci	} else if (strncmp(buf, "spur-high", 9) == 0) {
7808c2ecf20Sopenharmony_ci		ath5k_ani_set_spur_immunity_level(ah,
7818c2ecf20Sopenharmony_ci						  ah->ani_state.max_spur_level);
7828c2ecf20Sopenharmony_ci	} else if (strncmp(buf, "fir-low", 7) == 0) {
7838c2ecf20Sopenharmony_ci		ath5k_ani_set_firstep_level(ah, 0);
7848c2ecf20Sopenharmony_ci	} else if (strncmp(buf, "fir-high", 8) == 0) {
7858c2ecf20Sopenharmony_ci		ath5k_ani_set_firstep_level(ah, ATH5K_ANI_MAX_FIRSTEP_LVL);
7868c2ecf20Sopenharmony_ci	} else if (strncmp(buf, "ofdm-off", 8) == 0) {
7878c2ecf20Sopenharmony_ci		ath5k_ani_set_ofdm_weak_signal_detection(ah, false);
7888c2ecf20Sopenharmony_ci	} else if (strncmp(buf, "ofdm-on", 7) == 0) {
7898c2ecf20Sopenharmony_ci		ath5k_ani_set_ofdm_weak_signal_detection(ah, true);
7908c2ecf20Sopenharmony_ci	} else if (strncmp(buf, "cck-off", 7) == 0) {
7918c2ecf20Sopenharmony_ci		ath5k_ani_set_cck_weak_signal_detection(ah, false);
7928c2ecf20Sopenharmony_ci	} else if (strncmp(buf, "cck-on", 6) == 0) {
7938c2ecf20Sopenharmony_ci		ath5k_ani_set_cck_weak_signal_detection(ah, true);
7948c2ecf20Sopenharmony_ci	}
7958c2ecf20Sopenharmony_ci	return count;
7968c2ecf20Sopenharmony_ci}
7978c2ecf20Sopenharmony_ci
7988c2ecf20Sopenharmony_cistatic const struct file_operations fops_ani = {
7998c2ecf20Sopenharmony_ci	.read = read_file_ani,
8008c2ecf20Sopenharmony_ci	.write = write_file_ani,
8018c2ecf20Sopenharmony_ci	.open = simple_open,
8028c2ecf20Sopenharmony_ci	.owner = THIS_MODULE,
8038c2ecf20Sopenharmony_ci	.llseek = default_llseek,
8048c2ecf20Sopenharmony_ci};
8058c2ecf20Sopenharmony_ci
8068c2ecf20Sopenharmony_ci
8078c2ecf20Sopenharmony_ci/* debugfs: queues etc */
8088c2ecf20Sopenharmony_ci
8098c2ecf20Sopenharmony_cistatic ssize_t read_file_queue(struct file *file, char __user *user_buf,
8108c2ecf20Sopenharmony_ci				   size_t count, loff_t *ppos)
8118c2ecf20Sopenharmony_ci{
8128c2ecf20Sopenharmony_ci	struct ath5k_hw *ah = file->private_data;
8138c2ecf20Sopenharmony_ci	char buf[700];
8148c2ecf20Sopenharmony_ci	unsigned int len = 0;
8158c2ecf20Sopenharmony_ci
8168c2ecf20Sopenharmony_ci	struct ath5k_txq *txq;
8178c2ecf20Sopenharmony_ci	struct ath5k_buf *bf, *bf0;
8188c2ecf20Sopenharmony_ci	int i, n;
8198c2ecf20Sopenharmony_ci
8208c2ecf20Sopenharmony_ci	len += scnprintf(buf + len, sizeof(buf) - len,
8218c2ecf20Sopenharmony_ci			"available txbuffers: %d\n", ah->txbuf_len);
8228c2ecf20Sopenharmony_ci
8238c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(ah->txqs); i++) {
8248c2ecf20Sopenharmony_ci		txq = &ah->txqs[i];
8258c2ecf20Sopenharmony_ci
8268c2ecf20Sopenharmony_ci		len += scnprintf(buf + len, sizeof(buf) - len,
8278c2ecf20Sopenharmony_ci			"%02d: %ssetup\n", i, txq->setup ? "" : "not ");
8288c2ecf20Sopenharmony_ci
8298c2ecf20Sopenharmony_ci		if (!txq->setup)
8308c2ecf20Sopenharmony_ci			continue;
8318c2ecf20Sopenharmony_ci
8328c2ecf20Sopenharmony_ci		n = 0;
8338c2ecf20Sopenharmony_ci		spin_lock_bh(&txq->lock);
8348c2ecf20Sopenharmony_ci		list_for_each_entry_safe(bf, bf0, &txq->q, list)
8358c2ecf20Sopenharmony_ci			n++;
8368c2ecf20Sopenharmony_ci		spin_unlock_bh(&txq->lock);
8378c2ecf20Sopenharmony_ci
8388c2ecf20Sopenharmony_ci		len += scnprintf(buf + len, sizeof(buf) - len,
8398c2ecf20Sopenharmony_ci				"  len: %d bufs: %d\n", txq->txq_len, n);
8408c2ecf20Sopenharmony_ci		len += scnprintf(buf + len, sizeof(buf) - len,
8418c2ecf20Sopenharmony_ci				"  stuck: %d\n", txq->txq_stuck);
8428c2ecf20Sopenharmony_ci	}
8438c2ecf20Sopenharmony_ci
8448c2ecf20Sopenharmony_ci	if (len > sizeof(buf))
8458c2ecf20Sopenharmony_ci		len = sizeof(buf);
8468c2ecf20Sopenharmony_ci
8478c2ecf20Sopenharmony_ci	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
8488c2ecf20Sopenharmony_ci}
8498c2ecf20Sopenharmony_ci
8508c2ecf20Sopenharmony_cistatic ssize_t write_file_queue(struct file *file,
8518c2ecf20Sopenharmony_ci				 const char __user *userbuf,
8528c2ecf20Sopenharmony_ci				 size_t count, loff_t *ppos)
8538c2ecf20Sopenharmony_ci{
8548c2ecf20Sopenharmony_ci	struct ath5k_hw *ah = file->private_data;
8558c2ecf20Sopenharmony_ci	char buf[20];
8568c2ecf20Sopenharmony_ci
8578c2ecf20Sopenharmony_ci	count = min_t(size_t, count, sizeof(buf) - 1);
8588c2ecf20Sopenharmony_ci	if (copy_from_user(buf, userbuf, count))
8598c2ecf20Sopenharmony_ci		return -EFAULT;
8608c2ecf20Sopenharmony_ci
8618c2ecf20Sopenharmony_ci	buf[count] = '\0';
8628c2ecf20Sopenharmony_ci	if (strncmp(buf, "start", 5) == 0)
8638c2ecf20Sopenharmony_ci		ieee80211_wake_queues(ah->hw);
8648c2ecf20Sopenharmony_ci	else if (strncmp(buf, "stop", 4) == 0)
8658c2ecf20Sopenharmony_ci		ieee80211_stop_queues(ah->hw);
8668c2ecf20Sopenharmony_ci
8678c2ecf20Sopenharmony_ci	return count;
8688c2ecf20Sopenharmony_ci}
8698c2ecf20Sopenharmony_ci
8708c2ecf20Sopenharmony_ci
8718c2ecf20Sopenharmony_cistatic const struct file_operations fops_queue = {
8728c2ecf20Sopenharmony_ci	.read = read_file_queue,
8738c2ecf20Sopenharmony_ci	.write = write_file_queue,
8748c2ecf20Sopenharmony_ci	.open = simple_open,
8758c2ecf20Sopenharmony_ci	.owner = THIS_MODULE,
8768c2ecf20Sopenharmony_ci	.llseek = default_llseek,
8778c2ecf20Sopenharmony_ci};
8788c2ecf20Sopenharmony_ci
8798c2ecf20Sopenharmony_ci/* debugfs: eeprom */
8808c2ecf20Sopenharmony_ci
8818c2ecf20Sopenharmony_cistruct eeprom_private {
8828c2ecf20Sopenharmony_ci	u16 *buf;
8838c2ecf20Sopenharmony_ci	int len;
8848c2ecf20Sopenharmony_ci};
8858c2ecf20Sopenharmony_ci
8868c2ecf20Sopenharmony_cistatic int open_file_eeprom(struct inode *inode, struct file *file)
8878c2ecf20Sopenharmony_ci{
8888c2ecf20Sopenharmony_ci	struct eeprom_private *ep;
8898c2ecf20Sopenharmony_ci	struct ath5k_hw *ah = inode->i_private;
8908c2ecf20Sopenharmony_ci	bool res;
8918c2ecf20Sopenharmony_ci	int i, ret;
8928c2ecf20Sopenharmony_ci	u32 eesize;	/* NB: in 16-bit words */
8938c2ecf20Sopenharmony_ci	u16 val, *buf;
8948c2ecf20Sopenharmony_ci
8958c2ecf20Sopenharmony_ci	/* Get eeprom size */
8968c2ecf20Sopenharmony_ci
8978c2ecf20Sopenharmony_ci	res = ath5k_hw_nvram_read(ah, AR5K_EEPROM_SIZE_UPPER, &val);
8988c2ecf20Sopenharmony_ci	if (!res)
8998c2ecf20Sopenharmony_ci		return -EACCES;
9008c2ecf20Sopenharmony_ci
9018c2ecf20Sopenharmony_ci	if (val == 0) {
9028c2ecf20Sopenharmony_ci		eesize = AR5K_EEPROM_INFO_MAX + AR5K_EEPROM_INFO_BASE;
9038c2ecf20Sopenharmony_ci	} else {
9048c2ecf20Sopenharmony_ci		eesize = (val & AR5K_EEPROM_SIZE_UPPER_MASK) <<
9058c2ecf20Sopenharmony_ci			AR5K_EEPROM_SIZE_ENDLOC_SHIFT;
9068c2ecf20Sopenharmony_ci		ath5k_hw_nvram_read(ah, AR5K_EEPROM_SIZE_LOWER, &val);
9078c2ecf20Sopenharmony_ci		eesize = eesize | val;
9088c2ecf20Sopenharmony_ci	}
9098c2ecf20Sopenharmony_ci
9108c2ecf20Sopenharmony_ci	if (eesize > 4096)
9118c2ecf20Sopenharmony_ci		return -EINVAL;
9128c2ecf20Sopenharmony_ci
9138c2ecf20Sopenharmony_ci	/* Create buffer and read in eeprom */
9148c2ecf20Sopenharmony_ci
9158c2ecf20Sopenharmony_ci	buf = vmalloc(array_size(eesize, 2));
9168c2ecf20Sopenharmony_ci	if (!buf) {
9178c2ecf20Sopenharmony_ci		ret = -ENOMEM;
9188c2ecf20Sopenharmony_ci		goto err;
9198c2ecf20Sopenharmony_ci	}
9208c2ecf20Sopenharmony_ci
9218c2ecf20Sopenharmony_ci	for (i = 0; i < eesize; ++i) {
9228c2ecf20Sopenharmony_ci		if (!ath5k_hw_nvram_read(ah, i, &val)) {
9238c2ecf20Sopenharmony_ci			ret = -EIO;
9248c2ecf20Sopenharmony_ci			goto freebuf;
9258c2ecf20Sopenharmony_ci		}
9268c2ecf20Sopenharmony_ci		buf[i] = val;
9278c2ecf20Sopenharmony_ci	}
9288c2ecf20Sopenharmony_ci
9298c2ecf20Sopenharmony_ci	/* Create private struct and assign to file */
9308c2ecf20Sopenharmony_ci
9318c2ecf20Sopenharmony_ci	ep = kmalloc(sizeof(*ep), GFP_KERNEL);
9328c2ecf20Sopenharmony_ci	if (!ep) {
9338c2ecf20Sopenharmony_ci		ret = -ENOMEM;
9348c2ecf20Sopenharmony_ci		goto freebuf;
9358c2ecf20Sopenharmony_ci	}
9368c2ecf20Sopenharmony_ci
9378c2ecf20Sopenharmony_ci	ep->buf = buf;
9388c2ecf20Sopenharmony_ci	ep->len = eesize * 2;
9398c2ecf20Sopenharmony_ci
9408c2ecf20Sopenharmony_ci	file->private_data = (void *)ep;
9418c2ecf20Sopenharmony_ci
9428c2ecf20Sopenharmony_ci	return 0;
9438c2ecf20Sopenharmony_ci
9448c2ecf20Sopenharmony_cifreebuf:
9458c2ecf20Sopenharmony_ci	vfree(buf);
9468c2ecf20Sopenharmony_cierr:
9478c2ecf20Sopenharmony_ci	return ret;
9488c2ecf20Sopenharmony_ci
9498c2ecf20Sopenharmony_ci}
9508c2ecf20Sopenharmony_ci
9518c2ecf20Sopenharmony_cistatic ssize_t read_file_eeprom(struct file *file, char __user *user_buf,
9528c2ecf20Sopenharmony_ci				   size_t count, loff_t *ppos)
9538c2ecf20Sopenharmony_ci{
9548c2ecf20Sopenharmony_ci	struct eeprom_private *ep = file->private_data;
9558c2ecf20Sopenharmony_ci
9568c2ecf20Sopenharmony_ci	return simple_read_from_buffer(user_buf, count, ppos, ep->buf, ep->len);
9578c2ecf20Sopenharmony_ci}
9588c2ecf20Sopenharmony_ci
9598c2ecf20Sopenharmony_cistatic int release_file_eeprom(struct inode *inode, struct file *file)
9608c2ecf20Sopenharmony_ci{
9618c2ecf20Sopenharmony_ci	struct eeprom_private *ep = file->private_data;
9628c2ecf20Sopenharmony_ci
9638c2ecf20Sopenharmony_ci	vfree(ep->buf);
9648c2ecf20Sopenharmony_ci	kfree(ep);
9658c2ecf20Sopenharmony_ci
9668c2ecf20Sopenharmony_ci	return 0;
9678c2ecf20Sopenharmony_ci}
9688c2ecf20Sopenharmony_ci
9698c2ecf20Sopenharmony_cistatic const struct file_operations fops_eeprom = {
9708c2ecf20Sopenharmony_ci	.open = open_file_eeprom,
9718c2ecf20Sopenharmony_ci	.read = read_file_eeprom,
9728c2ecf20Sopenharmony_ci	.release = release_file_eeprom,
9738c2ecf20Sopenharmony_ci	.owner = THIS_MODULE,
9748c2ecf20Sopenharmony_ci};
9758c2ecf20Sopenharmony_ci
9768c2ecf20Sopenharmony_ci
9778c2ecf20Sopenharmony_civoid
9788c2ecf20Sopenharmony_ciath5k_debug_init_device(struct ath5k_hw *ah)
9798c2ecf20Sopenharmony_ci{
9808c2ecf20Sopenharmony_ci	struct dentry *phydir;
9818c2ecf20Sopenharmony_ci
9828c2ecf20Sopenharmony_ci	ah->debug.level = ath5k_debug;
9838c2ecf20Sopenharmony_ci
9848c2ecf20Sopenharmony_ci	phydir = debugfs_create_dir("ath5k", ah->hw->wiphy->debugfsdir);
9858c2ecf20Sopenharmony_ci	if (!phydir)
9868c2ecf20Sopenharmony_ci		return;
9878c2ecf20Sopenharmony_ci
9888c2ecf20Sopenharmony_ci	debugfs_create_file("debug", 0600, phydir, ah, &fops_debug);
9898c2ecf20Sopenharmony_ci	debugfs_create_file("registers", 0400, phydir, ah, &registers_fops);
9908c2ecf20Sopenharmony_ci	debugfs_create_file("beacon", 0600, phydir, ah, &fops_beacon);
9918c2ecf20Sopenharmony_ci	debugfs_create_file("reset", 0200, phydir, ah, &fops_reset);
9928c2ecf20Sopenharmony_ci	debugfs_create_file("antenna", 0600, phydir, ah, &fops_antenna);
9938c2ecf20Sopenharmony_ci	debugfs_create_file("misc", 0400, phydir, ah, &fops_misc);
9948c2ecf20Sopenharmony_ci	debugfs_create_file("eeprom", 0400, phydir, ah, &fops_eeprom);
9958c2ecf20Sopenharmony_ci	debugfs_create_file("frameerrors", 0600, phydir, ah, &fops_frameerrors);
9968c2ecf20Sopenharmony_ci	debugfs_create_file("ani", 0600, phydir, ah, &fops_ani);
9978c2ecf20Sopenharmony_ci	debugfs_create_file("queue", 0600, phydir, ah, &fops_queue);
9988c2ecf20Sopenharmony_ci	debugfs_create_bool("32khz_clock", 0600, phydir,
9998c2ecf20Sopenharmony_ci			    &ah->ah_use_32khz_clock);
10008c2ecf20Sopenharmony_ci}
10018c2ecf20Sopenharmony_ci
10028c2ecf20Sopenharmony_ci/* functions used in other places */
10038c2ecf20Sopenharmony_ci
10048c2ecf20Sopenharmony_civoid
10058c2ecf20Sopenharmony_ciath5k_debug_dump_bands(struct ath5k_hw *ah)
10068c2ecf20Sopenharmony_ci{
10078c2ecf20Sopenharmony_ci	unsigned int b, i;
10088c2ecf20Sopenharmony_ci
10098c2ecf20Sopenharmony_ci	if (likely(!(ah->debug.level & ATH5K_DEBUG_DUMPBANDS)))
10108c2ecf20Sopenharmony_ci		return;
10118c2ecf20Sopenharmony_ci
10128c2ecf20Sopenharmony_ci	for (b = 0; b < NUM_NL80211_BANDS; b++) {
10138c2ecf20Sopenharmony_ci		struct ieee80211_supported_band *band = &ah->sbands[b];
10148c2ecf20Sopenharmony_ci		char bname[6];
10158c2ecf20Sopenharmony_ci		switch (band->band) {
10168c2ecf20Sopenharmony_ci		case NL80211_BAND_2GHZ:
10178c2ecf20Sopenharmony_ci			strcpy(bname, "2 GHz");
10188c2ecf20Sopenharmony_ci			break;
10198c2ecf20Sopenharmony_ci		case NL80211_BAND_5GHZ:
10208c2ecf20Sopenharmony_ci			strcpy(bname, "5 GHz");
10218c2ecf20Sopenharmony_ci			break;
10228c2ecf20Sopenharmony_ci		default:
10238c2ecf20Sopenharmony_ci			printk(KERN_DEBUG "Band not supported: %d\n",
10248c2ecf20Sopenharmony_ci				band->band);
10258c2ecf20Sopenharmony_ci			return;
10268c2ecf20Sopenharmony_ci		}
10278c2ecf20Sopenharmony_ci		printk(KERN_DEBUG "Band %s: channels %d, rates %d\n", bname,
10288c2ecf20Sopenharmony_ci				band->n_channels, band->n_bitrates);
10298c2ecf20Sopenharmony_ci		printk(KERN_DEBUG " channels:\n");
10308c2ecf20Sopenharmony_ci		for (i = 0; i < band->n_channels; i++)
10318c2ecf20Sopenharmony_ci			printk(KERN_DEBUG "  %3d %d %.4x %.4x\n",
10328c2ecf20Sopenharmony_ci					ieee80211_frequency_to_channel(
10338c2ecf20Sopenharmony_ci						band->channels[i].center_freq),
10348c2ecf20Sopenharmony_ci					band->channels[i].center_freq,
10358c2ecf20Sopenharmony_ci					band->channels[i].hw_value,
10368c2ecf20Sopenharmony_ci					band->channels[i].flags);
10378c2ecf20Sopenharmony_ci		printk(KERN_DEBUG " rates:\n");
10388c2ecf20Sopenharmony_ci		for (i = 0; i < band->n_bitrates; i++)
10398c2ecf20Sopenharmony_ci			printk(KERN_DEBUG "  %4d %.4x %.4x %.4x\n",
10408c2ecf20Sopenharmony_ci					band->bitrates[i].bitrate,
10418c2ecf20Sopenharmony_ci					band->bitrates[i].hw_value,
10428c2ecf20Sopenharmony_ci					band->bitrates[i].flags,
10438c2ecf20Sopenharmony_ci					band->bitrates[i].hw_value_short);
10448c2ecf20Sopenharmony_ci	}
10458c2ecf20Sopenharmony_ci}
10468c2ecf20Sopenharmony_ci
10478c2ecf20Sopenharmony_cistatic inline void
10488c2ecf20Sopenharmony_ciath5k_debug_printrxbuf(struct ath5k_buf *bf, int done,
10498c2ecf20Sopenharmony_ci		       struct ath5k_rx_status *rs)
10508c2ecf20Sopenharmony_ci{
10518c2ecf20Sopenharmony_ci	struct ath5k_desc *ds = bf->desc;
10528c2ecf20Sopenharmony_ci	struct ath5k_hw_all_rx_desc *rd = &ds->ud.ds_rx;
10538c2ecf20Sopenharmony_ci
10548c2ecf20Sopenharmony_ci	printk(KERN_DEBUG "R (%p %llx) %08x %08x %08x %08x %08x %08x %c\n",
10558c2ecf20Sopenharmony_ci		ds, (unsigned long long)bf->daddr,
10568c2ecf20Sopenharmony_ci		ds->ds_link, ds->ds_data,
10578c2ecf20Sopenharmony_ci		rd->rx_ctl.rx_control_0, rd->rx_ctl.rx_control_1,
10588c2ecf20Sopenharmony_ci		rd->rx_stat.rx_status_0, rd->rx_stat.rx_status_1,
10598c2ecf20Sopenharmony_ci		!done ? ' ' : (rs->rs_status == 0) ? '*' : '!');
10608c2ecf20Sopenharmony_ci}
10618c2ecf20Sopenharmony_ci
10628c2ecf20Sopenharmony_civoid
10638c2ecf20Sopenharmony_ciath5k_debug_printrxbuffs(struct ath5k_hw *ah)
10648c2ecf20Sopenharmony_ci{
10658c2ecf20Sopenharmony_ci	struct ath5k_desc *ds;
10668c2ecf20Sopenharmony_ci	struct ath5k_buf *bf;
10678c2ecf20Sopenharmony_ci	struct ath5k_rx_status rs = {};
10688c2ecf20Sopenharmony_ci	int status;
10698c2ecf20Sopenharmony_ci
10708c2ecf20Sopenharmony_ci	if (likely(!(ah->debug.level & ATH5K_DEBUG_DESC)))
10718c2ecf20Sopenharmony_ci		return;
10728c2ecf20Sopenharmony_ci
10738c2ecf20Sopenharmony_ci	printk(KERN_DEBUG "rxdp %x, rxlink %p\n",
10748c2ecf20Sopenharmony_ci		ath5k_hw_get_rxdp(ah), ah->rxlink);
10758c2ecf20Sopenharmony_ci
10768c2ecf20Sopenharmony_ci	spin_lock_bh(&ah->rxbuflock);
10778c2ecf20Sopenharmony_ci	list_for_each_entry(bf, &ah->rxbuf, list) {
10788c2ecf20Sopenharmony_ci		ds = bf->desc;
10798c2ecf20Sopenharmony_ci		status = ah->ah_proc_rx_desc(ah, ds, &rs);
10808c2ecf20Sopenharmony_ci		if (!status)
10818c2ecf20Sopenharmony_ci			ath5k_debug_printrxbuf(bf, status == 0, &rs);
10828c2ecf20Sopenharmony_ci	}
10838c2ecf20Sopenharmony_ci	spin_unlock_bh(&ah->rxbuflock);
10848c2ecf20Sopenharmony_ci}
10858c2ecf20Sopenharmony_ci
10868c2ecf20Sopenharmony_civoid
10878c2ecf20Sopenharmony_ciath5k_debug_printtxbuf(struct ath5k_hw *ah, struct ath5k_buf *bf)
10888c2ecf20Sopenharmony_ci{
10898c2ecf20Sopenharmony_ci	struct ath5k_desc *ds = bf->desc;
10908c2ecf20Sopenharmony_ci	struct ath5k_hw_5212_tx_desc *td = &ds->ud.ds_tx5212;
10918c2ecf20Sopenharmony_ci	struct ath5k_tx_status ts = {};
10928c2ecf20Sopenharmony_ci	int done;
10938c2ecf20Sopenharmony_ci
10948c2ecf20Sopenharmony_ci	if (likely(!(ah->debug.level & ATH5K_DEBUG_DESC)))
10958c2ecf20Sopenharmony_ci		return;
10968c2ecf20Sopenharmony_ci
10978c2ecf20Sopenharmony_ci	done = ah->ah_proc_tx_desc(ah, bf->desc, &ts);
10988c2ecf20Sopenharmony_ci
10998c2ecf20Sopenharmony_ci	printk(KERN_DEBUG "T (%p %llx) %08x %08x %08x %08x %08x %08x %08x "
11008c2ecf20Sopenharmony_ci		"%08x %c\n", ds, (unsigned long long)bf->daddr, ds->ds_link,
11018c2ecf20Sopenharmony_ci		ds->ds_data, td->tx_ctl.tx_control_0, td->tx_ctl.tx_control_1,
11028c2ecf20Sopenharmony_ci		td->tx_ctl.tx_control_2, td->tx_ctl.tx_control_3,
11038c2ecf20Sopenharmony_ci		td->tx_stat.tx_status_0, td->tx_stat.tx_status_1,
11048c2ecf20Sopenharmony_ci		done ? ' ' : (ts.ts_status == 0) ? '*' : '!');
11058c2ecf20Sopenharmony_ci}
1106