xref: /OK3568_Linux_fs/kernel/drivers/net/wireless/ath/ath5k/debug.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * Copyright (c) 2007-2008 Bruno Randolf <bruno@thinktube.com>
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  *  This file is free software: you may copy, redistribute and/or modify it
5*4882a593Smuzhiyun  *  under the terms of the GNU General Public License as published by the
6*4882a593Smuzhiyun  *  Free Software Foundation, either version 2 of the License, or (at your
7*4882a593Smuzhiyun  *  option) any later version.
8*4882a593Smuzhiyun  *
9*4882a593Smuzhiyun  *  This file is distributed in the hope that it will be useful, but
10*4882a593Smuzhiyun  *  WITHOUT ANY WARRANTY; without even the implied warranty of
11*4882a593Smuzhiyun  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12*4882a593Smuzhiyun  *  General Public License for more details.
13*4882a593Smuzhiyun  *
14*4882a593Smuzhiyun  *  You should have received a copy of the GNU General Public License
15*4882a593Smuzhiyun  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
16*4882a593Smuzhiyun  *
17*4882a593Smuzhiyun  *
18*4882a593Smuzhiyun  * This file incorporates work covered by the following copyright and
19*4882a593Smuzhiyun  * permission notice:
20*4882a593Smuzhiyun  *
21*4882a593Smuzhiyun  * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
22*4882a593Smuzhiyun  * Copyright (c) 2004-2005 Atheros Communications, Inc.
23*4882a593Smuzhiyun  * Copyright (c) 2006 Devicescape Software, Inc.
24*4882a593Smuzhiyun  * Copyright (c) 2007 Jiri Slaby <jirislaby@gmail.com>
25*4882a593Smuzhiyun  * Copyright (c) 2007 Luis R. Rodriguez <mcgrof@winlab.rutgers.edu>
26*4882a593Smuzhiyun  *
27*4882a593Smuzhiyun  * All rights reserved.
28*4882a593Smuzhiyun  *
29*4882a593Smuzhiyun  * Redistribution and use in source and binary forms, with or without
30*4882a593Smuzhiyun  * modification, are permitted provided that the following conditions
31*4882a593Smuzhiyun  * are met:
32*4882a593Smuzhiyun  * 1. Redistributions of source code must retain the above copyright
33*4882a593Smuzhiyun  *    notice, this list of conditions and the following disclaimer,
34*4882a593Smuzhiyun  *    without modification.
35*4882a593Smuzhiyun  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
36*4882a593Smuzhiyun  *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
37*4882a593Smuzhiyun  *    redistribution must be conditioned upon including a substantially
38*4882a593Smuzhiyun  *    similar Disclaimer requirement for further binary redistribution.
39*4882a593Smuzhiyun  * 3. Neither the names of the above-listed copyright holders nor the names
40*4882a593Smuzhiyun  *    of any contributors may be used to endorse or promote products derived
41*4882a593Smuzhiyun  *    from this software without specific prior written permission.
42*4882a593Smuzhiyun  *
43*4882a593Smuzhiyun  * Alternatively, this software may be distributed under the terms of the
44*4882a593Smuzhiyun  * GNU General Public License ("GPL") version 2 as published by the Free
45*4882a593Smuzhiyun  * Software Foundation.
46*4882a593Smuzhiyun  *
47*4882a593Smuzhiyun  * NO WARRANTY
48*4882a593Smuzhiyun  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
49*4882a593Smuzhiyun  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
50*4882a593Smuzhiyun  * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
51*4882a593Smuzhiyun  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
52*4882a593Smuzhiyun  * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
53*4882a593Smuzhiyun  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
54*4882a593Smuzhiyun  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
55*4882a593Smuzhiyun  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
56*4882a593Smuzhiyun  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
57*4882a593Smuzhiyun  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
58*4882a593Smuzhiyun  * THE POSSIBILITY OF SUCH DAMAGES.
59*4882a593Smuzhiyun  */
60*4882a593Smuzhiyun 
61*4882a593Smuzhiyun #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
62*4882a593Smuzhiyun 
63*4882a593Smuzhiyun #include <linux/export.h>
64*4882a593Smuzhiyun #include <linux/moduleparam.h>
65*4882a593Smuzhiyun #include <linux/vmalloc.h>
66*4882a593Smuzhiyun 
67*4882a593Smuzhiyun #include <linux/seq_file.h>
68*4882a593Smuzhiyun #include <linux/list.h>
69*4882a593Smuzhiyun #include "debug.h"
70*4882a593Smuzhiyun #include "ath5k.h"
71*4882a593Smuzhiyun #include "reg.h"
72*4882a593Smuzhiyun #include "base.h"
73*4882a593Smuzhiyun 
74*4882a593Smuzhiyun static unsigned int ath5k_debug;
75*4882a593Smuzhiyun module_param_named(debug, ath5k_debug, uint, 0);
76*4882a593Smuzhiyun 
77*4882a593Smuzhiyun 
78*4882a593Smuzhiyun /* debugfs: registers */
79*4882a593Smuzhiyun 
80*4882a593Smuzhiyun struct reg {
81*4882a593Smuzhiyun 	const char *name;
82*4882a593Smuzhiyun 	int addr;
83*4882a593Smuzhiyun };
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun #define REG_STRUCT_INIT(r) { #r, r }
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun /* just a few random registers, might want to add more */
88*4882a593Smuzhiyun static const struct reg regs[] = {
89*4882a593Smuzhiyun 	REG_STRUCT_INIT(AR5K_CR),
90*4882a593Smuzhiyun 	REG_STRUCT_INIT(AR5K_RXDP),
91*4882a593Smuzhiyun 	REG_STRUCT_INIT(AR5K_CFG),
92*4882a593Smuzhiyun 	REG_STRUCT_INIT(AR5K_IER),
93*4882a593Smuzhiyun 	REG_STRUCT_INIT(AR5K_BCR),
94*4882a593Smuzhiyun 	REG_STRUCT_INIT(AR5K_RTSD0),
95*4882a593Smuzhiyun 	REG_STRUCT_INIT(AR5K_RTSD1),
96*4882a593Smuzhiyun 	REG_STRUCT_INIT(AR5K_TXCFG),
97*4882a593Smuzhiyun 	REG_STRUCT_INIT(AR5K_RXCFG),
98*4882a593Smuzhiyun 	REG_STRUCT_INIT(AR5K_RXJLA),
99*4882a593Smuzhiyun 	REG_STRUCT_INIT(AR5K_MIBC),
100*4882a593Smuzhiyun 	REG_STRUCT_INIT(AR5K_TOPS),
101*4882a593Smuzhiyun 	REG_STRUCT_INIT(AR5K_RXNOFRM),
102*4882a593Smuzhiyun 	REG_STRUCT_INIT(AR5K_TXNOFRM),
103*4882a593Smuzhiyun 	REG_STRUCT_INIT(AR5K_RPGTO),
104*4882a593Smuzhiyun 	REG_STRUCT_INIT(AR5K_RFCNT),
105*4882a593Smuzhiyun 	REG_STRUCT_INIT(AR5K_MISC),
106*4882a593Smuzhiyun 	REG_STRUCT_INIT(AR5K_QCUDCU_CLKGT),
107*4882a593Smuzhiyun 	REG_STRUCT_INIT(AR5K_ISR),
108*4882a593Smuzhiyun 	REG_STRUCT_INIT(AR5K_PISR),
109*4882a593Smuzhiyun 	REG_STRUCT_INIT(AR5K_SISR0),
110*4882a593Smuzhiyun 	REG_STRUCT_INIT(AR5K_SISR1),
111*4882a593Smuzhiyun 	REG_STRUCT_INIT(AR5K_SISR2),
112*4882a593Smuzhiyun 	REG_STRUCT_INIT(AR5K_SISR3),
113*4882a593Smuzhiyun 	REG_STRUCT_INIT(AR5K_SISR4),
114*4882a593Smuzhiyun 	REG_STRUCT_INIT(AR5K_IMR),
115*4882a593Smuzhiyun 	REG_STRUCT_INIT(AR5K_PIMR),
116*4882a593Smuzhiyun 	REG_STRUCT_INIT(AR5K_SIMR0),
117*4882a593Smuzhiyun 	REG_STRUCT_INIT(AR5K_SIMR1),
118*4882a593Smuzhiyun 	REG_STRUCT_INIT(AR5K_SIMR2),
119*4882a593Smuzhiyun 	REG_STRUCT_INIT(AR5K_SIMR3),
120*4882a593Smuzhiyun 	REG_STRUCT_INIT(AR5K_SIMR4),
121*4882a593Smuzhiyun 	REG_STRUCT_INIT(AR5K_DCM_ADDR),
122*4882a593Smuzhiyun 	REG_STRUCT_INIT(AR5K_DCCFG),
123*4882a593Smuzhiyun 	REG_STRUCT_INIT(AR5K_CCFG),
124*4882a593Smuzhiyun 	REG_STRUCT_INIT(AR5K_CPC0),
125*4882a593Smuzhiyun 	REG_STRUCT_INIT(AR5K_CPC1),
126*4882a593Smuzhiyun 	REG_STRUCT_INIT(AR5K_CPC2),
127*4882a593Smuzhiyun 	REG_STRUCT_INIT(AR5K_CPC3),
128*4882a593Smuzhiyun 	REG_STRUCT_INIT(AR5K_CPCOVF),
129*4882a593Smuzhiyun 	REG_STRUCT_INIT(AR5K_RESET_CTL),
130*4882a593Smuzhiyun 	REG_STRUCT_INIT(AR5K_SLEEP_CTL),
131*4882a593Smuzhiyun 	REG_STRUCT_INIT(AR5K_INTPEND),
132*4882a593Smuzhiyun 	REG_STRUCT_INIT(AR5K_SFR),
133*4882a593Smuzhiyun 	REG_STRUCT_INIT(AR5K_PCICFG),
134*4882a593Smuzhiyun 	REG_STRUCT_INIT(AR5K_GPIOCR),
135*4882a593Smuzhiyun 	REG_STRUCT_INIT(AR5K_GPIODO),
136*4882a593Smuzhiyun 	REG_STRUCT_INIT(AR5K_SREV),
137*4882a593Smuzhiyun };
138*4882a593Smuzhiyun 
reg_start(struct seq_file * seq,loff_t * pos)139*4882a593Smuzhiyun static void *reg_start(struct seq_file *seq, loff_t *pos)
140*4882a593Smuzhiyun {
141*4882a593Smuzhiyun 	return *pos < ARRAY_SIZE(regs) ? (void *)&regs[*pos] : NULL;
142*4882a593Smuzhiyun }
143*4882a593Smuzhiyun 
reg_stop(struct seq_file * seq,void * p)144*4882a593Smuzhiyun static void reg_stop(struct seq_file *seq, void *p)
145*4882a593Smuzhiyun {
146*4882a593Smuzhiyun 	/* nothing to do */
147*4882a593Smuzhiyun }
148*4882a593Smuzhiyun 
reg_next(struct seq_file * seq,void * p,loff_t * pos)149*4882a593Smuzhiyun static void *reg_next(struct seq_file *seq, void *p, loff_t *pos)
150*4882a593Smuzhiyun {
151*4882a593Smuzhiyun 	++*pos;
152*4882a593Smuzhiyun 	return *pos < ARRAY_SIZE(regs) ? (void *)&regs[*pos] : NULL;
153*4882a593Smuzhiyun }
154*4882a593Smuzhiyun 
reg_show(struct seq_file * seq,void * p)155*4882a593Smuzhiyun static int reg_show(struct seq_file *seq, void *p)
156*4882a593Smuzhiyun {
157*4882a593Smuzhiyun 	struct ath5k_hw *ah = seq->private;
158*4882a593Smuzhiyun 	struct reg *r = p;
159*4882a593Smuzhiyun 	seq_printf(seq, "%-25s0x%08x\n", r->name,
160*4882a593Smuzhiyun 		ath5k_hw_reg_read(ah, r->addr));
161*4882a593Smuzhiyun 	return 0;
162*4882a593Smuzhiyun }
163*4882a593Smuzhiyun 
164*4882a593Smuzhiyun static const struct seq_operations registers_sops = {
165*4882a593Smuzhiyun 	.start = reg_start,
166*4882a593Smuzhiyun 	.next  = reg_next,
167*4882a593Smuzhiyun 	.stop  = reg_stop,
168*4882a593Smuzhiyun 	.show  = reg_show
169*4882a593Smuzhiyun };
170*4882a593Smuzhiyun 
171*4882a593Smuzhiyun DEFINE_SEQ_ATTRIBUTE(registers);
172*4882a593Smuzhiyun 
173*4882a593Smuzhiyun /* debugfs: beacons */
174*4882a593Smuzhiyun 
read_file_beacon(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)175*4882a593Smuzhiyun static ssize_t read_file_beacon(struct file *file, char __user *user_buf,
176*4882a593Smuzhiyun 				   size_t count, loff_t *ppos)
177*4882a593Smuzhiyun {
178*4882a593Smuzhiyun 	struct ath5k_hw *ah = file->private_data;
179*4882a593Smuzhiyun 	char buf[500];
180*4882a593Smuzhiyun 	unsigned int len = 0;
181*4882a593Smuzhiyun 	unsigned int v;
182*4882a593Smuzhiyun 	u64 tsf;
183*4882a593Smuzhiyun 
184*4882a593Smuzhiyun 	v = ath5k_hw_reg_read(ah, AR5K_BEACON);
185*4882a593Smuzhiyun 	len += scnprintf(buf + len, sizeof(buf) - len,
186*4882a593Smuzhiyun 		"%-24s0x%08x\tintval: %d\tTIM: 0x%x\n",
187*4882a593Smuzhiyun 		"AR5K_BEACON", v, v & AR5K_BEACON_PERIOD,
188*4882a593Smuzhiyun 		(v & AR5K_BEACON_TIM) >> AR5K_BEACON_TIM_S);
189*4882a593Smuzhiyun 
190*4882a593Smuzhiyun 	len += scnprintf(buf + len, sizeof(buf) - len, "%-24s0x%08x\n",
191*4882a593Smuzhiyun 		"AR5K_LAST_TSTP", ath5k_hw_reg_read(ah, AR5K_LAST_TSTP));
192*4882a593Smuzhiyun 
193*4882a593Smuzhiyun 	len += scnprintf(buf + len, sizeof(buf) - len, "%-24s0x%08x\n\n",
194*4882a593Smuzhiyun 		"AR5K_BEACON_CNT", ath5k_hw_reg_read(ah, AR5K_BEACON_CNT));
195*4882a593Smuzhiyun 
196*4882a593Smuzhiyun 	v = ath5k_hw_reg_read(ah, AR5K_TIMER0);
197*4882a593Smuzhiyun 	len += scnprintf(buf + len, sizeof(buf) - len, "%-24s0x%08x\tTU: %08x\n",
198*4882a593Smuzhiyun 		"AR5K_TIMER0 (TBTT)", v, v);
199*4882a593Smuzhiyun 
200*4882a593Smuzhiyun 	v = ath5k_hw_reg_read(ah, AR5K_TIMER1);
201*4882a593Smuzhiyun 	len += scnprintf(buf + len, sizeof(buf) - len, "%-24s0x%08x\tTU: %08x\n",
202*4882a593Smuzhiyun 		"AR5K_TIMER1 (DMA)", v, v >> 3);
203*4882a593Smuzhiyun 
204*4882a593Smuzhiyun 	v = ath5k_hw_reg_read(ah, AR5K_TIMER2);
205*4882a593Smuzhiyun 	len += scnprintf(buf + len, sizeof(buf) - len, "%-24s0x%08x\tTU: %08x\n",
206*4882a593Smuzhiyun 		"AR5K_TIMER2 (SWBA)", v, v >> 3);
207*4882a593Smuzhiyun 
208*4882a593Smuzhiyun 	v = ath5k_hw_reg_read(ah, AR5K_TIMER3);
209*4882a593Smuzhiyun 	len += scnprintf(buf + len, sizeof(buf) - len, "%-24s0x%08x\tTU: %08x\n",
210*4882a593Smuzhiyun 		"AR5K_TIMER3 (ATIM)", v, v);
211*4882a593Smuzhiyun 
212*4882a593Smuzhiyun 	tsf = ath5k_hw_get_tsf64(ah);
213*4882a593Smuzhiyun 	len += scnprintf(buf + len, sizeof(buf) - len,
214*4882a593Smuzhiyun 		"TSF\t\t0x%016llx\tTU: %08x\n",
215*4882a593Smuzhiyun 		(unsigned long long)tsf, TSF_TO_TU(tsf));
216*4882a593Smuzhiyun 
217*4882a593Smuzhiyun 	if (len > sizeof(buf))
218*4882a593Smuzhiyun 		len = sizeof(buf);
219*4882a593Smuzhiyun 
220*4882a593Smuzhiyun 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
221*4882a593Smuzhiyun }
222*4882a593Smuzhiyun 
write_file_beacon(struct file * file,const char __user * userbuf,size_t count,loff_t * ppos)223*4882a593Smuzhiyun static ssize_t write_file_beacon(struct file *file,
224*4882a593Smuzhiyun 				 const char __user *userbuf,
225*4882a593Smuzhiyun 				 size_t count, loff_t *ppos)
226*4882a593Smuzhiyun {
227*4882a593Smuzhiyun 	struct ath5k_hw *ah = file->private_data;
228*4882a593Smuzhiyun 	char buf[20];
229*4882a593Smuzhiyun 
230*4882a593Smuzhiyun 	count = min_t(size_t, count, sizeof(buf) - 1);
231*4882a593Smuzhiyun 	if (copy_from_user(buf, userbuf, count))
232*4882a593Smuzhiyun 		return -EFAULT;
233*4882a593Smuzhiyun 
234*4882a593Smuzhiyun 	buf[count] = '\0';
235*4882a593Smuzhiyun 	if (strncmp(buf, "disable", 7) == 0) {
236*4882a593Smuzhiyun 		AR5K_REG_DISABLE_BITS(ah, AR5K_BEACON, AR5K_BEACON_ENABLE);
237*4882a593Smuzhiyun 		pr_info("debugfs disable beacons\n");
238*4882a593Smuzhiyun 	} else if (strncmp(buf, "enable", 6) == 0) {
239*4882a593Smuzhiyun 		AR5K_REG_ENABLE_BITS(ah, AR5K_BEACON, AR5K_BEACON_ENABLE);
240*4882a593Smuzhiyun 		pr_info("debugfs enable beacons\n");
241*4882a593Smuzhiyun 	}
242*4882a593Smuzhiyun 	return count;
243*4882a593Smuzhiyun }
244*4882a593Smuzhiyun 
245*4882a593Smuzhiyun static const struct file_operations fops_beacon = {
246*4882a593Smuzhiyun 	.read = read_file_beacon,
247*4882a593Smuzhiyun 	.write = write_file_beacon,
248*4882a593Smuzhiyun 	.open = simple_open,
249*4882a593Smuzhiyun 	.owner = THIS_MODULE,
250*4882a593Smuzhiyun 	.llseek = default_llseek,
251*4882a593Smuzhiyun };
252*4882a593Smuzhiyun 
253*4882a593Smuzhiyun 
254*4882a593Smuzhiyun /* debugfs: reset */
255*4882a593Smuzhiyun 
write_file_reset(struct file * file,const char __user * userbuf,size_t count,loff_t * ppos)256*4882a593Smuzhiyun static ssize_t write_file_reset(struct file *file,
257*4882a593Smuzhiyun 				 const char __user *userbuf,
258*4882a593Smuzhiyun 				 size_t count, loff_t *ppos)
259*4882a593Smuzhiyun {
260*4882a593Smuzhiyun 	struct ath5k_hw *ah = file->private_data;
261*4882a593Smuzhiyun 	ATH5K_DBG(ah, ATH5K_DEBUG_RESET, "debug file triggered reset\n");
262*4882a593Smuzhiyun 	ieee80211_queue_work(ah->hw, &ah->reset_work);
263*4882a593Smuzhiyun 	return count;
264*4882a593Smuzhiyun }
265*4882a593Smuzhiyun 
266*4882a593Smuzhiyun static const struct file_operations fops_reset = {
267*4882a593Smuzhiyun 	.write = write_file_reset,
268*4882a593Smuzhiyun 	.open = simple_open,
269*4882a593Smuzhiyun 	.owner = THIS_MODULE,
270*4882a593Smuzhiyun 	.llseek = noop_llseek,
271*4882a593Smuzhiyun };
272*4882a593Smuzhiyun 
273*4882a593Smuzhiyun 
274*4882a593Smuzhiyun /* debugfs: debug level */
275*4882a593Smuzhiyun 
276*4882a593Smuzhiyun static const struct {
277*4882a593Smuzhiyun 	enum ath5k_debug_level level;
278*4882a593Smuzhiyun 	const char *name;
279*4882a593Smuzhiyun 	const char *desc;
280*4882a593Smuzhiyun } dbg_info[] = {
281*4882a593Smuzhiyun 	{ ATH5K_DEBUG_RESET,	"reset",	"reset and initialization" },
282*4882a593Smuzhiyun 	{ ATH5K_DEBUG_INTR,	"intr",		"interrupt handling" },
283*4882a593Smuzhiyun 	{ ATH5K_DEBUG_MODE,	"mode",		"mode init/setup" },
284*4882a593Smuzhiyun 	{ ATH5K_DEBUG_XMIT,	"xmit",		"basic xmit operation" },
285*4882a593Smuzhiyun 	{ ATH5K_DEBUG_BEACON,	"beacon",	"beacon handling" },
286*4882a593Smuzhiyun 	{ ATH5K_DEBUG_CALIBRATE, "calib",	"periodic calibration" },
287*4882a593Smuzhiyun 	{ ATH5K_DEBUG_TXPOWER,	"txpower",	"transmit power setting" },
288*4882a593Smuzhiyun 	{ ATH5K_DEBUG_LED,	"led",		"LED management" },
289*4882a593Smuzhiyun 	{ ATH5K_DEBUG_DUMPBANDS, "dumpbands",	"dump bands" },
290*4882a593Smuzhiyun 	{ ATH5K_DEBUG_DMA,	"dma",		"dma start/stop" },
291*4882a593Smuzhiyun 	{ ATH5K_DEBUG_ANI,	"ani",		"adaptive noise immunity" },
292*4882a593Smuzhiyun 	{ ATH5K_DEBUG_DESC,	"desc",		"descriptor chains" },
293*4882a593Smuzhiyun 	{ ATH5K_DEBUG_ANY,	"all",		"show all debug levels" },
294*4882a593Smuzhiyun };
295*4882a593Smuzhiyun 
read_file_debug(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)296*4882a593Smuzhiyun static ssize_t read_file_debug(struct file *file, char __user *user_buf,
297*4882a593Smuzhiyun 				   size_t count, loff_t *ppos)
298*4882a593Smuzhiyun {
299*4882a593Smuzhiyun 	struct ath5k_hw *ah = file->private_data;
300*4882a593Smuzhiyun 	char buf[700];
301*4882a593Smuzhiyun 	unsigned int len = 0;
302*4882a593Smuzhiyun 	unsigned int i;
303*4882a593Smuzhiyun 
304*4882a593Smuzhiyun 	len += scnprintf(buf + len, sizeof(buf) - len,
305*4882a593Smuzhiyun 		"DEBUG LEVEL: 0x%08x\n\n", ah->debug.level);
306*4882a593Smuzhiyun 
307*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(dbg_info) - 1; i++) {
308*4882a593Smuzhiyun 		len += scnprintf(buf + len, sizeof(buf) - len,
309*4882a593Smuzhiyun 			"%10s %c 0x%08x - %s\n", dbg_info[i].name,
310*4882a593Smuzhiyun 			ah->debug.level & dbg_info[i].level ? '+' : ' ',
311*4882a593Smuzhiyun 			dbg_info[i].level, dbg_info[i].desc);
312*4882a593Smuzhiyun 	}
313*4882a593Smuzhiyun 	len += scnprintf(buf + len, sizeof(buf) - len,
314*4882a593Smuzhiyun 		"%10s %c 0x%08x - %s\n", dbg_info[i].name,
315*4882a593Smuzhiyun 		ah->debug.level == dbg_info[i].level ? '+' : ' ',
316*4882a593Smuzhiyun 		dbg_info[i].level, dbg_info[i].desc);
317*4882a593Smuzhiyun 
318*4882a593Smuzhiyun 	if (len > sizeof(buf))
319*4882a593Smuzhiyun 		len = sizeof(buf);
320*4882a593Smuzhiyun 
321*4882a593Smuzhiyun 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
322*4882a593Smuzhiyun }
323*4882a593Smuzhiyun 
write_file_debug(struct file * file,const char __user * userbuf,size_t count,loff_t * ppos)324*4882a593Smuzhiyun static ssize_t write_file_debug(struct file *file,
325*4882a593Smuzhiyun 				 const char __user *userbuf,
326*4882a593Smuzhiyun 				 size_t count, loff_t *ppos)
327*4882a593Smuzhiyun {
328*4882a593Smuzhiyun 	struct ath5k_hw *ah = file->private_data;
329*4882a593Smuzhiyun 	unsigned int i;
330*4882a593Smuzhiyun 	char buf[20];
331*4882a593Smuzhiyun 
332*4882a593Smuzhiyun 	count = min_t(size_t, count, sizeof(buf) - 1);
333*4882a593Smuzhiyun 	if (copy_from_user(buf, userbuf, count))
334*4882a593Smuzhiyun 		return -EFAULT;
335*4882a593Smuzhiyun 
336*4882a593Smuzhiyun 	buf[count] = '\0';
337*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(dbg_info); i++) {
338*4882a593Smuzhiyun 		if (strncmp(buf, dbg_info[i].name,
339*4882a593Smuzhiyun 					strlen(dbg_info[i].name)) == 0) {
340*4882a593Smuzhiyun 			ah->debug.level ^= dbg_info[i].level; /* toggle bit */
341*4882a593Smuzhiyun 			break;
342*4882a593Smuzhiyun 		}
343*4882a593Smuzhiyun 	}
344*4882a593Smuzhiyun 	return count;
345*4882a593Smuzhiyun }
346*4882a593Smuzhiyun 
347*4882a593Smuzhiyun static const struct file_operations fops_debug = {
348*4882a593Smuzhiyun 	.read = read_file_debug,
349*4882a593Smuzhiyun 	.write = write_file_debug,
350*4882a593Smuzhiyun 	.open = simple_open,
351*4882a593Smuzhiyun 	.owner = THIS_MODULE,
352*4882a593Smuzhiyun 	.llseek = default_llseek,
353*4882a593Smuzhiyun };
354*4882a593Smuzhiyun 
355*4882a593Smuzhiyun 
356*4882a593Smuzhiyun /* debugfs: antenna */
357*4882a593Smuzhiyun 
read_file_antenna(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)358*4882a593Smuzhiyun static ssize_t read_file_antenna(struct file *file, char __user *user_buf,
359*4882a593Smuzhiyun 				   size_t count, loff_t *ppos)
360*4882a593Smuzhiyun {
361*4882a593Smuzhiyun 	struct ath5k_hw *ah = file->private_data;
362*4882a593Smuzhiyun 	char buf[700];
363*4882a593Smuzhiyun 	unsigned int len = 0;
364*4882a593Smuzhiyun 	unsigned int i;
365*4882a593Smuzhiyun 	unsigned int v;
366*4882a593Smuzhiyun 
367*4882a593Smuzhiyun 	len += scnprintf(buf + len, sizeof(buf) - len, "antenna mode\t%d\n",
368*4882a593Smuzhiyun 		ah->ah_ant_mode);
369*4882a593Smuzhiyun 	len += scnprintf(buf + len, sizeof(buf) - len, "default antenna\t%d\n",
370*4882a593Smuzhiyun 		ah->ah_def_ant);
371*4882a593Smuzhiyun 	len += scnprintf(buf + len, sizeof(buf) - len, "tx antenna\t%d\n",
372*4882a593Smuzhiyun 		ah->ah_tx_ant);
373*4882a593Smuzhiyun 
374*4882a593Smuzhiyun 	len += scnprintf(buf + len, sizeof(buf) - len, "\nANTENNA\t\tRX\tTX\n");
375*4882a593Smuzhiyun 	for (i = 1; i < ARRAY_SIZE(ah->stats.antenna_rx); i++) {
376*4882a593Smuzhiyun 		len += scnprintf(buf + len, sizeof(buf) - len,
377*4882a593Smuzhiyun 			"[antenna %d]\t%d\t%d\n",
378*4882a593Smuzhiyun 			i, ah->stats.antenna_rx[i], ah->stats.antenna_tx[i]);
379*4882a593Smuzhiyun 	}
380*4882a593Smuzhiyun 	len += scnprintf(buf + len, sizeof(buf) - len, "[invalid]\t%d\t%d\n",
381*4882a593Smuzhiyun 			ah->stats.antenna_rx[0], ah->stats.antenna_tx[0]);
382*4882a593Smuzhiyun 
383*4882a593Smuzhiyun 	v = ath5k_hw_reg_read(ah, AR5K_DEFAULT_ANTENNA);
384*4882a593Smuzhiyun 	len += scnprintf(buf + len, sizeof(buf) - len,
385*4882a593Smuzhiyun 			"\nAR5K_DEFAULT_ANTENNA\t0x%08x\n", v);
386*4882a593Smuzhiyun 
387*4882a593Smuzhiyun 	v = ath5k_hw_reg_read(ah, AR5K_STA_ID1);
388*4882a593Smuzhiyun 	len += scnprintf(buf + len, sizeof(buf) - len,
389*4882a593Smuzhiyun 		"AR5K_STA_ID1_DEFAULT_ANTENNA\t%d\n",
390*4882a593Smuzhiyun 		(v & AR5K_STA_ID1_DEFAULT_ANTENNA) != 0);
391*4882a593Smuzhiyun 	len += scnprintf(buf + len, sizeof(buf) - len,
392*4882a593Smuzhiyun 		"AR5K_STA_ID1_DESC_ANTENNA\t%d\n",
393*4882a593Smuzhiyun 		(v & AR5K_STA_ID1_DESC_ANTENNA) != 0);
394*4882a593Smuzhiyun 	len += scnprintf(buf + len, sizeof(buf) - len,
395*4882a593Smuzhiyun 		"AR5K_STA_ID1_RTS_DEF_ANTENNA\t%d\n",
396*4882a593Smuzhiyun 		(v & AR5K_STA_ID1_RTS_DEF_ANTENNA) != 0);
397*4882a593Smuzhiyun 	len += scnprintf(buf + len, sizeof(buf) - len,
398*4882a593Smuzhiyun 		"AR5K_STA_ID1_SELFGEN_DEF_ANT\t%d\n",
399*4882a593Smuzhiyun 		(v & AR5K_STA_ID1_SELFGEN_DEF_ANT) != 0);
400*4882a593Smuzhiyun 
401*4882a593Smuzhiyun 	v = ath5k_hw_reg_read(ah, AR5K_PHY_AGCCTL);
402*4882a593Smuzhiyun 	len += scnprintf(buf + len, sizeof(buf) - len,
403*4882a593Smuzhiyun 		"\nAR5K_PHY_AGCCTL_OFDM_DIV_DIS\t%d\n",
404*4882a593Smuzhiyun 		(v & AR5K_PHY_AGCCTL_OFDM_DIV_DIS) != 0);
405*4882a593Smuzhiyun 
406*4882a593Smuzhiyun 	v = ath5k_hw_reg_read(ah, AR5K_PHY_RESTART);
407*4882a593Smuzhiyun 	len += scnprintf(buf + len, sizeof(buf) - len,
408*4882a593Smuzhiyun 		"AR5K_PHY_RESTART_DIV_GC\t\t%x\n",
409*4882a593Smuzhiyun 		(v & AR5K_PHY_RESTART_DIV_GC) >> AR5K_PHY_RESTART_DIV_GC_S);
410*4882a593Smuzhiyun 
411*4882a593Smuzhiyun 	v = ath5k_hw_reg_read(ah, AR5K_PHY_FAST_ANT_DIV);
412*4882a593Smuzhiyun 	len += scnprintf(buf + len, sizeof(buf) - len,
413*4882a593Smuzhiyun 		"AR5K_PHY_FAST_ANT_DIV_EN\t%d\n",
414*4882a593Smuzhiyun 		(v & AR5K_PHY_FAST_ANT_DIV_EN) != 0);
415*4882a593Smuzhiyun 
416*4882a593Smuzhiyun 	v = ath5k_hw_reg_read(ah, AR5K_PHY_ANT_SWITCH_TABLE_0);
417*4882a593Smuzhiyun 	len += scnprintf(buf + len, sizeof(buf) - len,
418*4882a593Smuzhiyun 			"\nAR5K_PHY_ANT_SWITCH_TABLE_0\t0x%08x\n", v);
419*4882a593Smuzhiyun 	v = ath5k_hw_reg_read(ah, AR5K_PHY_ANT_SWITCH_TABLE_1);
420*4882a593Smuzhiyun 	len += scnprintf(buf + len, sizeof(buf) - len,
421*4882a593Smuzhiyun 			"AR5K_PHY_ANT_SWITCH_TABLE_1\t0x%08x\n", v);
422*4882a593Smuzhiyun 
423*4882a593Smuzhiyun 	if (len > sizeof(buf))
424*4882a593Smuzhiyun 		len = sizeof(buf);
425*4882a593Smuzhiyun 
426*4882a593Smuzhiyun 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
427*4882a593Smuzhiyun }
428*4882a593Smuzhiyun 
write_file_antenna(struct file * file,const char __user * userbuf,size_t count,loff_t * ppos)429*4882a593Smuzhiyun static ssize_t write_file_antenna(struct file *file,
430*4882a593Smuzhiyun 				 const char __user *userbuf,
431*4882a593Smuzhiyun 				 size_t count, loff_t *ppos)
432*4882a593Smuzhiyun {
433*4882a593Smuzhiyun 	struct ath5k_hw *ah = file->private_data;
434*4882a593Smuzhiyun 	unsigned int i;
435*4882a593Smuzhiyun 	char buf[20];
436*4882a593Smuzhiyun 
437*4882a593Smuzhiyun 	count = min_t(size_t, count, sizeof(buf) - 1);
438*4882a593Smuzhiyun 	if (copy_from_user(buf, userbuf, count))
439*4882a593Smuzhiyun 		return -EFAULT;
440*4882a593Smuzhiyun 
441*4882a593Smuzhiyun 	buf[count] = '\0';
442*4882a593Smuzhiyun 	if (strncmp(buf, "diversity", 9) == 0) {
443*4882a593Smuzhiyun 		ath5k_hw_set_antenna_mode(ah, AR5K_ANTMODE_DEFAULT);
444*4882a593Smuzhiyun 		pr_info("debug: enable diversity\n");
445*4882a593Smuzhiyun 	} else if (strncmp(buf, "fixed-a", 7) == 0) {
446*4882a593Smuzhiyun 		ath5k_hw_set_antenna_mode(ah, AR5K_ANTMODE_FIXED_A);
447*4882a593Smuzhiyun 		pr_info("debug: fixed antenna A\n");
448*4882a593Smuzhiyun 	} else if (strncmp(buf, "fixed-b", 7) == 0) {
449*4882a593Smuzhiyun 		ath5k_hw_set_antenna_mode(ah, AR5K_ANTMODE_FIXED_B);
450*4882a593Smuzhiyun 		pr_info("debug: fixed antenna B\n");
451*4882a593Smuzhiyun 	} else if (strncmp(buf, "clear", 5) == 0) {
452*4882a593Smuzhiyun 		for (i = 0; i < ARRAY_SIZE(ah->stats.antenna_rx); i++) {
453*4882a593Smuzhiyun 			ah->stats.antenna_rx[i] = 0;
454*4882a593Smuzhiyun 			ah->stats.antenna_tx[i] = 0;
455*4882a593Smuzhiyun 		}
456*4882a593Smuzhiyun 		pr_info("debug: cleared antenna stats\n");
457*4882a593Smuzhiyun 	}
458*4882a593Smuzhiyun 	return count;
459*4882a593Smuzhiyun }
460*4882a593Smuzhiyun 
461*4882a593Smuzhiyun static const struct file_operations fops_antenna = {
462*4882a593Smuzhiyun 	.read = read_file_antenna,
463*4882a593Smuzhiyun 	.write = write_file_antenna,
464*4882a593Smuzhiyun 	.open = simple_open,
465*4882a593Smuzhiyun 	.owner = THIS_MODULE,
466*4882a593Smuzhiyun 	.llseek = default_llseek,
467*4882a593Smuzhiyun };
468*4882a593Smuzhiyun 
469*4882a593Smuzhiyun /* debugfs: misc */
470*4882a593Smuzhiyun 
read_file_misc(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)471*4882a593Smuzhiyun static ssize_t read_file_misc(struct file *file, char __user *user_buf,
472*4882a593Smuzhiyun 				   size_t count, loff_t *ppos)
473*4882a593Smuzhiyun {
474*4882a593Smuzhiyun 	struct ath5k_hw *ah = file->private_data;
475*4882a593Smuzhiyun 	char buf[700];
476*4882a593Smuzhiyun 	unsigned int len = 0;
477*4882a593Smuzhiyun 	u32 filt = ath5k_hw_get_rx_filter(ah);
478*4882a593Smuzhiyun 
479*4882a593Smuzhiyun 	len += scnprintf(buf + len, sizeof(buf) - len, "bssid-mask: %pM\n",
480*4882a593Smuzhiyun 			ah->bssidmask);
481*4882a593Smuzhiyun 	len += scnprintf(buf + len, sizeof(buf) - len, "filter-flags: 0x%x ",
482*4882a593Smuzhiyun 			filt);
483*4882a593Smuzhiyun 	if (filt & AR5K_RX_FILTER_UCAST)
484*4882a593Smuzhiyun 		len += scnprintf(buf + len, sizeof(buf) - len, " UCAST");
485*4882a593Smuzhiyun 	if (filt & AR5K_RX_FILTER_MCAST)
486*4882a593Smuzhiyun 		len += scnprintf(buf + len, sizeof(buf) - len, " MCAST");
487*4882a593Smuzhiyun 	if (filt & AR5K_RX_FILTER_BCAST)
488*4882a593Smuzhiyun 		len += scnprintf(buf + len, sizeof(buf) - len, " BCAST");
489*4882a593Smuzhiyun 	if (filt & AR5K_RX_FILTER_CONTROL)
490*4882a593Smuzhiyun 		len += scnprintf(buf + len, sizeof(buf) - len, " CONTROL");
491*4882a593Smuzhiyun 	if (filt & AR5K_RX_FILTER_BEACON)
492*4882a593Smuzhiyun 		len += scnprintf(buf + len, sizeof(buf) - len, " BEACON");
493*4882a593Smuzhiyun 	if (filt & AR5K_RX_FILTER_PROM)
494*4882a593Smuzhiyun 		len += scnprintf(buf + len, sizeof(buf) - len, " PROM");
495*4882a593Smuzhiyun 	if (filt & AR5K_RX_FILTER_XRPOLL)
496*4882a593Smuzhiyun 		len += scnprintf(buf + len, sizeof(buf) - len, " XRPOLL");
497*4882a593Smuzhiyun 	if (filt & AR5K_RX_FILTER_PROBEREQ)
498*4882a593Smuzhiyun 		len += scnprintf(buf + len, sizeof(buf) - len, " PROBEREQ");
499*4882a593Smuzhiyun 	if (filt & AR5K_RX_FILTER_PHYERR_5212)
500*4882a593Smuzhiyun 		len += scnprintf(buf + len, sizeof(buf) - len, " PHYERR-5212");
501*4882a593Smuzhiyun 	if (filt & AR5K_RX_FILTER_RADARERR_5212)
502*4882a593Smuzhiyun 		len += scnprintf(buf + len, sizeof(buf) - len, " RADARERR-5212");
503*4882a593Smuzhiyun 	if (filt & AR5K_RX_FILTER_PHYERR_5211)
504*4882a593Smuzhiyun 		snprintf(buf + len, sizeof(buf) - len, " PHYERR-5211");
505*4882a593Smuzhiyun 	if (filt & AR5K_RX_FILTER_RADARERR_5211)
506*4882a593Smuzhiyun 		len += scnprintf(buf + len, sizeof(buf) - len, " RADARERR-5211");
507*4882a593Smuzhiyun 
508*4882a593Smuzhiyun 	len += scnprintf(buf + len, sizeof(buf) - len, "\nopmode: %s (%d)\n",
509*4882a593Smuzhiyun 			ath_opmode_to_string(ah->opmode), ah->opmode);
510*4882a593Smuzhiyun 
511*4882a593Smuzhiyun 	if (len > sizeof(buf))
512*4882a593Smuzhiyun 		len = sizeof(buf);
513*4882a593Smuzhiyun 
514*4882a593Smuzhiyun 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
515*4882a593Smuzhiyun }
516*4882a593Smuzhiyun 
517*4882a593Smuzhiyun static const struct file_operations fops_misc = {
518*4882a593Smuzhiyun 	.read = read_file_misc,
519*4882a593Smuzhiyun 	.open = simple_open,
520*4882a593Smuzhiyun 	.owner = THIS_MODULE,
521*4882a593Smuzhiyun };
522*4882a593Smuzhiyun 
523*4882a593Smuzhiyun 
524*4882a593Smuzhiyun /* debugfs: frameerrors */
525*4882a593Smuzhiyun 
read_file_frameerrors(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)526*4882a593Smuzhiyun static ssize_t read_file_frameerrors(struct file *file, char __user *user_buf,
527*4882a593Smuzhiyun 				   size_t count, loff_t *ppos)
528*4882a593Smuzhiyun {
529*4882a593Smuzhiyun 	struct ath5k_hw *ah = file->private_data;
530*4882a593Smuzhiyun 	struct ath5k_statistics *st = &ah->stats;
531*4882a593Smuzhiyun 	char buf[700];
532*4882a593Smuzhiyun 	unsigned int len = 0;
533*4882a593Smuzhiyun 	int i;
534*4882a593Smuzhiyun 
535*4882a593Smuzhiyun 	len += scnprintf(buf + len, sizeof(buf) - len,
536*4882a593Smuzhiyun 			"RX\n---------------------\n");
537*4882a593Smuzhiyun 	len += scnprintf(buf + len, sizeof(buf) - len, "CRC\t%u\t(%u%%)\n",
538*4882a593Smuzhiyun 			st->rxerr_crc,
539*4882a593Smuzhiyun 			st->rx_all_count > 0 ?
540*4882a593Smuzhiyun 				st->rxerr_crc * 100 / st->rx_all_count : 0);
541*4882a593Smuzhiyun 	len += scnprintf(buf + len, sizeof(buf) - len, "PHY\t%u\t(%u%%)\n",
542*4882a593Smuzhiyun 			st->rxerr_phy,
543*4882a593Smuzhiyun 			st->rx_all_count > 0 ?
544*4882a593Smuzhiyun 				st->rxerr_phy * 100 / st->rx_all_count : 0);
545*4882a593Smuzhiyun 	for (i = 0; i < 32; i++) {
546*4882a593Smuzhiyun 		if (st->rxerr_phy_code[i])
547*4882a593Smuzhiyun 			len += scnprintf(buf + len, sizeof(buf) - len,
548*4882a593Smuzhiyun 				" phy_err[%u]\t%u\n",
549*4882a593Smuzhiyun 				i, st->rxerr_phy_code[i]);
550*4882a593Smuzhiyun 	}
551*4882a593Smuzhiyun 
552*4882a593Smuzhiyun 	len += scnprintf(buf + len, sizeof(buf) - len, "FIFO\t%u\t(%u%%)\n",
553*4882a593Smuzhiyun 			st->rxerr_fifo,
554*4882a593Smuzhiyun 			st->rx_all_count > 0 ?
555*4882a593Smuzhiyun 				st->rxerr_fifo * 100 / st->rx_all_count : 0);
556*4882a593Smuzhiyun 	len += scnprintf(buf + len, sizeof(buf) - len, "decrypt\t%u\t(%u%%)\n",
557*4882a593Smuzhiyun 			st->rxerr_decrypt,
558*4882a593Smuzhiyun 			st->rx_all_count > 0 ?
559*4882a593Smuzhiyun 				st->rxerr_decrypt * 100 / st->rx_all_count : 0);
560*4882a593Smuzhiyun 	len += scnprintf(buf + len, sizeof(buf) - len, "MIC\t%u\t(%u%%)\n",
561*4882a593Smuzhiyun 			st->rxerr_mic,
562*4882a593Smuzhiyun 			st->rx_all_count > 0 ?
563*4882a593Smuzhiyun 				st->rxerr_mic * 100 / st->rx_all_count : 0);
564*4882a593Smuzhiyun 	len += scnprintf(buf + len, sizeof(buf) - len, "process\t%u\t(%u%%)\n",
565*4882a593Smuzhiyun 			st->rxerr_proc,
566*4882a593Smuzhiyun 			st->rx_all_count > 0 ?
567*4882a593Smuzhiyun 				st->rxerr_proc * 100 / st->rx_all_count : 0);
568*4882a593Smuzhiyun 	len += scnprintf(buf + len, sizeof(buf) - len, "jumbo\t%u\t(%u%%)\n",
569*4882a593Smuzhiyun 			st->rxerr_jumbo,
570*4882a593Smuzhiyun 			st->rx_all_count > 0 ?
571*4882a593Smuzhiyun 				st->rxerr_jumbo * 100 / st->rx_all_count : 0);
572*4882a593Smuzhiyun 	len += scnprintf(buf + len, sizeof(buf) - len, "[RX all\t%u]\n",
573*4882a593Smuzhiyun 			st->rx_all_count);
574*4882a593Smuzhiyun 	len += scnprintf(buf + len, sizeof(buf) - len, "RX-all-bytes\t%u\n",
575*4882a593Smuzhiyun 			st->rx_bytes_count);
576*4882a593Smuzhiyun 
577*4882a593Smuzhiyun 	len += scnprintf(buf + len, sizeof(buf) - len,
578*4882a593Smuzhiyun 			"\nTX\n---------------------\n");
579*4882a593Smuzhiyun 	len += scnprintf(buf + len, sizeof(buf) - len, "retry\t%u\t(%u%%)\n",
580*4882a593Smuzhiyun 			st->txerr_retry,
581*4882a593Smuzhiyun 			st->tx_all_count > 0 ?
582*4882a593Smuzhiyun 				st->txerr_retry * 100 / st->tx_all_count : 0);
583*4882a593Smuzhiyun 	len += scnprintf(buf + len, sizeof(buf) - len, "FIFO\t%u\t(%u%%)\n",
584*4882a593Smuzhiyun 			st->txerr_fifo,
585*4882a593Smuzhiyun 			st->tx_all_count > 0 ?
586*4882a593Smuzhiyun 				st->txerr_fifo * 100 / st->tx_all_count : 0);
587*4882a593Smuzhiyun 	len += scnprintf(buf + len, sizeof(buf) - len, "filter\t%u\t(%u%%)\n",
588*4882a593Smuzhiyun 			st->txerr_filt,
589*4882a593Smuzhiyun 			st->tx_all_count > 0 ?
590*4882a593Smuzhiyun 				st->txerr_filt * 100 / st->tx_all_count : 0);
591*4882a593Smuzhiyun 	len += scnprintf(buf + len, sizeof(buf) - len, "[TX all\t%u]\n",
592*4882a593Smuzhiyun 			st->tx_all_count);
593*4882a593Smuzhiyun 	len += scnprintf(buf + len, sizeof(buf) - len, "TX-all-bytes\t%u\n",
594*4882a593Smuzhiyun 			st->tx_bytes_count);
595*4882a593Smuzhiyun 
596*4882a593Smuzhiyun 	if (len > sizeof(buf))
597*4882a593Smuzhiyun 		len = sizeof(buf);
598*4882a593Smuzhiyun 
599*4882a593Smuzhiyun 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
600*4882a593Smuzhiyun }
601*4882a593Smuzhiyun 
write_file_frameerrors(struct file * file,const char __user * userbuf,size_t count,loff_t * ppos)602*4882a593Smuzhiyun static ssize_t write_file_frameerrors(struct file *file,
603*4882a593Smuzhiyun 				 const char __user *userbuf,
604*4882a593Smuzhiyun 				 size_t count, loff_t *ppos)
605*4882a593Smuzhiyun {
606*4882a593Smuzhiyun 	struct ath5k_hw *ah = file->private_data;
607*4882a593Smuzhiyun 	struct ath5k_statistics *st = &ah->stats;
608*4882a593Smuzhiyun 	char buf[20];
609*4882a593Smuzhiyun 
610*4882a593Smuzhiyun 	count = min_t(size_t, count, sizeof(buf) - 1);
611*4882a593Smuzhiyun 	if (copy_from_user(buf, userbuf, count))
612*4882a593Smuzhiyun 		return -EFAULT;
613*4882a593Smuzhiyun 
614*4882a593Smuzhiyun 	buf[count] = '\0';
615*4882a593Smuzhiyun 	if (strncmp(buf, "clear", 5) == 0) {
616*4882a593Smuzhiyun 		st->rxerr_crc = 0;
617*4882a593Smuzhiyun 		st->rxerr_phy = 0;
618*4882a593Smuzhiyun 		st->rxerr_fifo = 0;
619*4882a593Smuzhiyun 		st->rxerr_decrypt = 0;
620*4882a593Smuzhiyun 		st->rxerr_mic = 0;
621*4882a593Smuzhiyun 		st->rxerr_proc = 0;
622*4882a593Smuzhiyun 		st->rxerr_jumbo = 0;
623*4882a593Smuzhiyun 		st->rx_all_count = 0;
624*4882a593Smuzhiyun 		st->txerr_retry = 0;
625*4882a593Smuzhiyun 		st->txerr_fifo = 0;
626*4882a593Smuzhiyun 		st->txerr_filt = 0;
627*4882a593Smuzhiyun 		st->tx_all_count = 0;
628*4882a593Smuzhiyun 		pr_info("debug: cleared frameerrors stats\n");
629*4882a593Smuzhiyun 	}
630*4882a593Smuzhiyun 	return count;
631*4882a593Smuzhiyun }
632*4882a593Smuzhiyun 
633*4882a593Smuzhiyun static const struct file_operations fops_frameerrors = {
634*4882a593Smuzhiyun 	.read = read_file_frameerrors,
635*4882a593Smuzhiyun 	.write = write_file_frameerrors,
636*4882a593Smuzhiyun 	.open = simple_open,
637*4882a593Smuzhiyun 	.owner = THIS_MODULE,
638*4882a593Smuzhiyun 	.llseek = default_llseek,
639*4882a593Smuzhiyun };
640*4882a593Smuzhiyun 
641*4882a593Smuzhiyun 
642*4882a593Smuzhiyun /* debugfs: ani */
643*4882a593Smuzhiyun 
read_file_ani(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)644*4882a593Smuzhiyun static ssize_t read_file_ani(struct file *file, char __user *user_buf,
645*4882a593Smuzhiyun 				   size_t count, loff_t *ppos)
646*4882a593Smuzhiyun {
647*4882a593Smuzhiyun 	struct ath5k_hw *ah = file->private_data;
648*4882a593Smuzhiyun 	struct ath5k_statistics *st = &ah->stats;
649*4882a593Smuzhiyun 	struct ath5k_ani_state *as = &ah->ani_state;
650*4882a593Smuzhiyun 
651*4882a593Smuzhiyun 	char buf[700];
652*4882a593Smuzhiyun 	unsigned int len = 0;
653*4882a593Smuzhiyun 
654*4882a593Smuzhiyun 	len += scnprintf(buf + len, sizeof(buf) - len,
655*4882a593Smuzhiyun 			"HW has PHY error counters:\t%s\n",
656*4882a593Smuzhiyun 			ah->ah_capabilities.cap_has_phyerr_counters ?
657*4882a593Smuzhiyun 			"yes" : "no");
658*4882a593Smuzhiyun 	len += scnprintf(buf + len, sizeof(buf) - len,
659*4882a593Smuzhiyun 			"HW max spur immunity level:\t%d\n",
660*4882a593Smuzhiyun 			as->max_spur_level);
661*4882a593Smuzhiyun 	len += scnprintf(buf + len, sizeof(buf) - len,
662*4882a593Smuzhiyun 		"\nANI state\n--------------------------------------------\n");
663*4882a593Smuzhiyun 	len += scnprintf(buf + len, sizeof(buf) - len, "operating mode:\t\t\t");
664*4882a593Smuzhiyun 	switch (as->ani_mode) {
665*4882a593Smuzhiyun 	case ATH5K_ANI_MODE_OFF:
666*4882a593Smuzhiyun 		len += scnprintf(buf + len, sizeof(buf) - len, "OFF\n");
667*4882a593Smuzhiyun 		break;
668*4882a593Smuzhiyun 	case ATH5K_ANI_MODE_MANUAL_LOW:
669*4882a593Smuzhiyun 		len += scnprintf(buf + len, sizeof(buf) - len,
670*4882a593Smuzhiyun 			"MANUAL LOW\n");
671*4882a593Smuzhiyun 		break;
672*4882a593Smuzhiyun 	case ATH5K_ANI_MODE_MANUAL_HIGH:
673*4882a593Smuzhiyun 		len += scnprintf(buf + len, sizeof(buf) - len,
674*4882a593Smuzhiyun 			"MANUAL HIGH\n");
675*4882a593Smuzhiyun 		break;
676*4882a593Smuzhiyun 	case ATH5K_ANI_MODE_AUTO:
677*4882a593Smuzhiyun 		len += scnprintf(buf + len, sizeof(buf) - len, "AUTO\n");
678*4882a593Smuzhiyun 		break;
679*4882a593Smuzhiyun 	default:
680*4882a593Smuzhiyun 		len += scnprintf(buf + len, sizeof(buf) - len,
681*4882a593Smuzhiyun 			"??? (not good)\n");
682*4882a593Smuzhiyun 		break;
683*4882a593Smuzhiyun 	}
684*4882a593Smuzhiyun 	len += scnprintf(buf + len, sizeof(buf) - len,
685*4882a593Smuzhiyun 			"noise immunity level:\t\t%d\n",
686*4882a593Smuzhiyun 			as->noise_imm_level);
687*4882a593Smuzhiyun 	len += scnprintf(buf + len, sizeof(buf) - len,
688*4882a593Smuzhiyun 			"spur immunity level:\t\t%d\n",
689*4882a593Smuzhiyun 			as->spur_level);
690*4882a593Smuzhiyun 	len += scnprintf(buf + len, sizeof(buf) - len,
691*4882a593Smuzhiyun 			"firstep level:\t\t\t%d\n",
692*4882a593Smuzhiyun 			as->firstep_level);
693*4882a593Smuzhiyun 	len += scnprintf(buf + len, sizeof(buf) - len,
694*4882a593Smuzhiyun 			"OFDM weak signal detection:\t%s\n",
695*4882a593Smuzhiyun 			as->ofdm_weak_sig ? "on" : "off");
696*4882a593Smuzhiyun 	len += scnprintf(buf + len, sizeof(buf) - len,
697*4882a593Smuzhiyun 			"CCK weak signal detection:\t%s\n",
698*4882a593Smuzhiyun 			as->cck_weak_sig ? "on" : "off");
699*4882a593Smuzhiyun 
700*4882a593Smuzhiyun 	len += scnprintf(buf + len, sizeof(buf) - len,
701*4882a593Smuzhiyun 			"\nMIB INTERRUPTS:\t\t%u\n",
702*4882a593Smuzhiyun 			st->mib_intr);
703*4882a593Smuzhiyun 	len += scnprintf(buf + len, sizeof(buf) - len,
704*4882a593Smuzhiyun 			"beacon RSSI average:\t%d\n",
705*4882a593Smuzhiyun 			(int)ewma_beacon_rssi_read(&ah->ah_beacon_rssi_avg));
706*4882a593Smuzhiyun 
707*4882a593Smuzhiyun #define CC_PRINT(_struct, _field) \
708*4882a593Smuzhiyun 	_struct._field, \
709*4882a593Smuzhiyun 	_struct.cycles > 0 ? \
710*4882a593Smuzhiyun 	_struct._field * 100 / _struct.cycles : 0
711*4882a593Smuzhiyun 
712*4882a593Smuzhiyun 	len += scnprintf(buf + len, sizeof(buf) - len,
713*4882a593Smuzhiyun 			"profcnt tx\t\t%u\t(%d%%)\n",
714*4882a593Smuzhiyun 			CC_PRINT(as->last_cc, tx_frame));
715*4882a593Smuzhiyun 	len += scnprintf(buf + len, sizeof(buf) - len,
716*4882a593Smuzhiyun 			"profcnt rx\t\t%u\t(%d%%)\n",
717*4882a593Smuzhiyun 			CC_PRINT(as->last_cc, rx_frame));
718*4882a593Smuzhiyun 	len += scnprintf(buf + len, sizeof(buf) - len,
719*4882a593Smuzhiyun 			"profcnt busy\t\t%u\t(%d%%)\n",
720*4882a593Smuzhiyun 			CC_PRINT(as->last_cc, rx_busy));
721*4882a593Smuzhiyun #undef CC_PRINT
722*4882a593Smuzhiyun 	len += scnprintf(buf + len, sizeof(buf) - len, "profcnt cycles\t\t%u\n",
723*4882a593Smuzhiyun 			as->last_cc.cycles);
724*4882a593Smuzhiyun 	len += scnprintf(buf + len, sizeof(buf) - len,
725*4882a593Smuzhiyun 			"listen time\t\t%d\tlast: %d\n",
726*4882a593Smuzhiyun 			as->listen_time, as->last_listen);
727*4882a593Smuzhiyun 	len += scnprintf(buf + len, sizeof(buf) - len,
728*4882a593Smuzhiyun 			"OFDM errors\t\t%u\tlast: %u\tsum: %u\n",
729*4882a593Smuzhiyun 			as->ofdm_errors, as->last_ofdm_errors,
730*4882a593Smuzhiyun 			as->sum_ofdm_errors);
731*4882a593Smuzhiyun 	len += scnprintf(buf + len, sizeof(buf) - len,
732*4882a593Smuzhiyun 			"CCK errors\t\t%u\tlast: %u\tsum: %u\n",
733*4882a593Smuzhiyun 			as->cck_errors, as->last_cck_errors,
734*4882a593Smuzhiyun 			as->sum_cck_errors);
735*4882a593Smuzhiyun 	len += scnprintf(buf + len, sizeof(buf) - len,
736*4882a593Smuzhiyun 			"AR5K_PHYERR_CNT1\t%x\t(=%d)\n",
737*4882a593Smuzhiyun 			ath5k_hw_reg_read(ah, AR5K_PHYERR_CNT1),
738*4882a593Smuzhiyun 			ATH5K_ANI_OFDM_TRIG_HIGH - (ATH5K_PHYERR_CNT_MAX -
739*4882a593Smuzhiyun 			ath5k_hw_reg_read(ah, AR5K_PHYERR_CNT1)));
740*4882a593Smuzhiyun 	len += scnprintf(buf + len, sizeof(buf) - len,
741*4882a593Smuzhiyun 			"AR5K_PHYERR_CNT2\t%x\t(=%d)\n",
742*4882a593Smuzhiyun 			ath5k_hw_reg_read(ah, AR5K_PHYERR_CNT2),
743*4882a593Smuzhiyun 			ATH5K_ANI_CCK_TRIG_HIGH - (ATH5K_PHYERR_CNT_MAX -
744*4882a593Smuzhiyun 			ath5k_hw_reg_read(ah, AR5K_PHYERR_CNT2)));
745*4882a593Smuzhiyun 
746*4882a593Smuzhiyun 	if (len > sizeof(buf))
747*4882a593Smuzhiyun 		len = sizeof(buf);
748*4882a593Smuzhiyun 
749*4882a593Smuzhiyun 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
750*4882a593Smuzhiyun }
751*4882a593Smuzhiyun 
write_file_ani(struct file * file,const char __user * userbuf,size_t count,loff_t * ppos)752*4882a593Smuzhiyun static ssize_t write_file_ani(struct file *file,
753*4882a593Smuzhiyun 				 const char __user *userbuf,
754*4882a593Smuzhiyun 				 size_t count, loff_t *ppos)
755*4882a593Smuzhiyun {
756*4882a593Smuzhiyun 	struct ath5k_hw *ah = file->private_data;
757*4882a593Smuzhiyun 	char buf[20];
758*4882a593Smuzhiyun 
759*4882a593Smuzhiyun 	count = min_t(size_t, count, sizeof(buf) - 1);
760*4882a593Smuzhiyun 	if (copy_from_user(buf, userbuf, count))
761*4882a593Smuzhiyun 		return -EFAULT;
762*4882a593Smuzhiyun 
763*4882a593Smuzhiyun 	buf[count] = '\0';
764*4882a593Smuzhiyun 	if (strncmp(buf, "sens-low", 8) == 0) {
765*4882a593Smuzhiyun 		ath5k_ani_init(ah, ATH5K_ANI_MODE_MANUAL_HIGH);
766*4882a593Smuzhiyun 	} else if (strncmp(buf, "sens-high", 9) == 0) {
767*4882a593Smuzhiyun 		ath5k_ani_init(ah, ATH5K_ANI_MODE_MANUAL_LOW);
768*4882a593Smuzhiyun 	} else if (strncmp(buf, "ani-off", 7) == 0) {
769*4882a593Smuzhiyun 		ath5k_ani_init(ah, ATH5K_ANI_MODE_OFF);
770*4882a593Smuzhiyun 	} else if (strncmp(buf, "ani-on", 6) == 0) {
771*4882a593Smuzhiyun 		ath5k_ani_init(ah, ATH5K_ANI_MODE_AUTO);
772*4882a593Smuzhiyun 	} else if (strncmp(buf, "noise-low", 9) == 0) {
773*4882a593Smuzhiyun 		ath5k_ani_set_noise_immunity_level(ah, 0);
774*4882a593Smuzhiyun 	} else if (strncmp(buf, "noise-high", 10) == 0) {
775*4882a593Smuzhiyun 		ath5k_ani_set_noise_immunity_level(ah,
776*4882a593Smuzhiyun 						   ATH5K_ANI_MAX_NOISE_IMM_LVL);
777*4882a593Smuzhiyun 	} else if (strncmp(buf, "spur-low", 8) == 0) {
778*4882a593Smuzhiyun 		ath5k_ani_set_spur_immunity_level(ah, 0);
779*4882a593Smuzhiyun 	} else if (strncmp(buf, "spur-high", 9) == 0) {
780*4882a593Smuzhiyun 		ath5k_ani_set_spur_immunity_level(ah,
781*4882a593Smuzhiyun 						  ah->ani_state.max_spur_level);
782*4882a593Smuzhiyun 	} else if (strncmp(buf, "fir-low", 7) == 0) {
783*4882a593Smuzhiyun 		ath5k_ani_set_firstep_level(ah, 0);
784*4882a593Smuzhiyun 	} else if (strncmp(buf, "fir-high", 8) == 0) {
785*4882a593Smuzhiyun 		ath5k_ani_set_firstep_level(ah, ATH5K_ANI_MAX_FIRSTEP_LVL);
786*4882a593Smuzhiyun 	} else if (strncmp(buf, "ofdm-off", 8) == 0) {
787*4882a593Smuzhiyun 		ath5k_ani_set_ofdm_weak_signal_detection(ah, false);
788*4882a593Smuzhiyun 	} else if (strncmp(buf, "ofdm-on", 7) == 0) {
789*4882a593Smuzhiyun 		ath5k_ani_set_ofdm_weak_signal_detection(ah, true);
790*4882a593Smuzhiyun 	} else if (strncmp(buf, "cck-off", 7) == 0) {
791*4882a593Smuzhiyun 		ath5k_ani_set_cck_weak_signal_detection(ah, false);
792*4882a593Smuzhiyun 	} else if (strncmp(buf, "cck-on", 6) == 0) {
793*4882a593Smuzhiyun 		ath5k_ani_set_cck_weak_signal_detection(ah, true);
794*4882a593Smuzhiyun 	}
795*4882a593Smuzhiyun 	return count;
796*4882a593Smuzhiyun }
797*4882a593Smuzhiyun 
798*4882a593Smuzhiyun static const struct file_operations fops_ani = {
799*4882a593Smuzhiyun 	.read = read_file_ani,
800*4882a593Smuzhiyun 	.write = write_file_ani,
801*4882a593Smuzhiyun 	.open = simple_open,
802*4882a593Smuzhiyun 	.owner = THIS_MODULE,
803*4882a593Smuzhiyun 	.llseek = default_llseek,
804*4882a593Smuzhiyun };
805*4882a593Smuzhiyun 
806*4882a593Smuzhiyun 
807*4882a593Smuzhiyun /* debugfs: queues etc */
808*4882a593Smuzhiyun 
read_file_queue(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)809*4882a593Smuzhiyun static ssize_t read_file_queue(struct file *file, char __user *user_buf,
810*4882a593Smuzhiyun 				   size_t count, loff_t *ppos)
811*4882a593Smuzhiyun {
812*4882a593Smuzhiyun 	struct ath5k_hw *ah = file->private_data;
813*4882a593Smuzhiyun 	char buf[700];
814*4882a593Smuzhiyun 	unsigned int len = 0;
815*4882a593Smuzhiyun 
816*4882a593Smuzhiyun 	struct ath5k_txq *txq;
817*4882a593Smuzhiyun 	struct ath5k_buf *bf, *bf0;
818*4882a593Smuzhiyun 	int i, n;
819*4882a593Smuzhiyun 
820*4882a593Smuzhiyun 	len += scnprintf(buf + len, sizeof(buf) - len,
821*4882a593Smuzhiyun 			"available txbuffers: %d\n", ah->txbuf_len);
822*4882a593Smuzhiyun 
823*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(ah->txqs); i++) {
824*4882a593Smuzhiyun 		txq = &ah->txqs[i];
825*4882a593Smuzhiyun 
826*4882a593Smuzhiyun 		len += scnprintf(buf + len, sizeof(buf) - len,
827*4882a593Smuzhiyun 			"%02d: %ssetup\n", i, txq->setup ? "" : "not ");
828*4882a593Smuzhiyun 
829*4882a593Smuzhiyun 		if (!txq->setup)
830*4882a593Smuzhiyun 			continue;
831*4882a593Smuzhiyun 
832*4882a593Smuzhiyun 		n = 0;
833*4882a593Smuzhiyun 		spin_lock_bh(&txq->lock);
834*4882a593Smuzhiyun 		list_for_each_entry_safe(bf, bf0, &txq->q, list)
835*4882a593Smuzhiyun 			n++;
836*4882a593Smuzhiyun 		spin_unlock_bh(&txq->lock);
837*4882a593Smuzhiyun 
838*4882a593Smuzhiyun 		len += scnprintf(buf + len, sizeof(buf) - len,
839*4882a593Smuzhiyun 				"  len: %d bufs: %d\n", txq->txq_len, n);
840*4882a593Smuzhiyun 		len += scnprintf(buf + len, sizeof(buf) - len,
841*4882a593Smuzhiyun 				"  stuck: %d\n", txq->txq_stuck);
842*4882a593Smuzhiyun 	}
843*4882a593Smuzhiyun 
844*4882a593Smuzhiyun 	if (len > sizeof(buf))
845*4882a593Smuzhiyun 		len = sizeof(buf);
846*4882a593Smuzhiyun 
847*4882a593Smuzhiyun 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
848*4882a593Smuzhiyun }
849*4882a593Smuzhiyun 
write_file_queue(struct file * file,const char __user * userbuf,size_t count,loff_t * ppos)850*4882a593Smuzhiyun static ssize_t write_file_queue(struct file *file,
851*4882a593Smuzhiyun 				 const char __user *userbuf,
852*4882a593Smuzhiyun 				 size_t count, loff_t *ppos)
853*4882a593Smuzhiyun {
854*4882a593Smuzhiyun 	struct ath5k_hw *ah = file->private_data;
855*4882a593Smuzhiyun 	char buf[20];
856*4882a593Smuzhiyun 
857*4882a593Smuzhiyun 	count = min_t(size_t, count, sizeof(buf) - 1);
858*4882a593Smuzhiyun 	if (copy_from_user(buf, userbuf, count))
859*4882a593Smuzhiyun 		return -EFAULT;
860*4882a593Smuzhiyun 
861*4882a593Smuzhiyun 	buf[count] = '\0';
862*4882a593Smuzhiyun 	if (strncmp(buf, "start", 5) == 0)
863*4882a593Smuzhiyun 		ieee80211_wake_queues(ah->hw);
864*4882a593Smuzhiyun 	else if (strncmp(buf, "stop", 4) == 0)
865*4882a593Smuzhiyun 		ieee80211_stop_queues(ah->hw);
866*4882a593Smuzhiyun 
867*4882a593Smuzhiyun 	return count;
868*4882a593Smuzhiyun }
869*4882a593Smuzhiyun 
870*4882a593Smuzhiyun 
871*4882a593Smuzhiyun static const struct file_operations fops_queue = {
872*4882a593Smuzhiyun 	.read = read_file_queue,
873*4882a593Smuzhiyun 	.write = write_file_queue,
874*4882a593Smuzhiyun 	.open = simple_open,
875*4882a593Smuzhiyun 	.owner = THIS_MODULE,
876*4882a593Smuzhiyun 	.llseek = default_llseek,
877*4882a593Smuzhiyun };
878*4882a593Smuzhiyun 
879*4882a593Smuzhiyun /* debugfs: eeprom */
880*4882a593Smuzhiyun 
881*4882a593Smuzhiyun struct eeprom_private {
882*4882a593Smuzhiyun 	u16 *buf;
883*4882a593Smuzhiyun 	int len;
884*4882a593Smuzhiyun };
885*4882a593Smuzhiyun 
open_file_eeprom(struct inode * inode,struct file * file)886*4882a593Smuzhiyun static int open_file_eeprom(struct inode *inode, struct file *file)
887*4882a593Smuzhiyun {
888*4882a593Smuzhiyun 	struct eeprom_private *ep;
889*4882a593Smuzhiyun 	struct ath5k_hw *ah = inode->i_private;
890*4882a593Smuzhiyun 	bool res;
891*4882a593Smuzhiyun 	int i, ret;
892*4882a593Smuzhiyun 	u32 eesize;	/* NB: in 16-bit words */
893*4882a593Smuzhiyun 	u16 val, *buf;
894*4882a593Smuzhiyun 
895*4882a593Smuzhiyun 	/* Get eeprom size */
896*4882a593Smuzhiyun 
897*4882a593Smuzhiyun 	res = ath5k_hw_nvram_read(ah, AR5K_EEPROM_SIZE_UPPER, &val);
898*4882a593Smuzhiyun 	if (!res)
899*4882a593Smuzhiyun 		return -EACCES;
900*4882a593Smuzhiyun 
901*4882a593Smuzhiyun 	if (val == 0) {
902*4882a593Smuzhiyun 		eesize = AR5K_EEPROM_INFO_MAX + AR5K_EEPROM_INFO_BASE;
903*4882a593Smuzhiyun 	} else {
904*4882a593Smuzhiyun 		eesize = (val & AR5K_EEPROM_SIZE_UPPER_MASK) <<
905*4882a593Smuzhiyun 			AR5K_EEPROM_SIZE_ENDLOC_SHIFT;
906*4882a593Smuzhiyun 		ath5k_hw_nvram_read(ah, AR5K_EEPROM_SIZE_LOWER, &val);
907*4882a593Smuzhiyun 		eesize = eesize | val;
908*4882a593Smuzhiyun 	}
909*4882a593Smuzhiyun 
910*4882a593Smuzhiyun 	if (eesize > 4096)
911*4882a593Smuzhiyun 		return -EINVAL;
912*4882a593Smuzhiyun 
913*4882a593Smuzhiyun 	/* Create buffer and read in eeprom */
914*4882a593Smuzhiyun 
915*4882a593Smuzhiyun 	buf = vmalloc(array_size(eesize, 2));
916*4882a593Smuzhiyun 	if (!buf) {
917*4882a593Smuzhiyun 		ret = -ENOMEM;
918*4882a593Smuzhiyun 		goto err;
919*4882a593Smuzhiyun 	}
920*4882a593Smuzhiyun 
921*4882a593Smuzhiyun 	for (i = 0; i < eesize; ++i) {
922*4882a593Smuzhiyun 		if (!ath5k_hw_nvram_read(ah, i, &val)) {
923*4882a593Smuzhiyun 			ret = -EIO;
924*4882a593Smuzhiyun 			goto freebuf;
925*4882a593Smuzhiyun 		}
926*4882a593Smuzhiyun 		buf[i] = val;
927*4882a593Smuzhiyun 	}
928*4882a593Smuzhiyun 
929*4882a593Smuzhiyun 	/* Create private struct and assign to file */
930*4882a593Smuzhiyun 
931*4882a593Smuzhiyun 	ep = kmalloc(sizeof(*ep), GFP_KERNEL);
932*4882a593Smuzhiyun 	if (!ep) {
933*4882a593Smuzhiyun 		ret = -ENOMEM;
934*4882a593Smuzhiyun 		goto freebuf;
935*4882a593Smuzhiyun 	}
936*4882a593Smuzhiyun 
937*4882a593Smuzhiyun 	ep->buf = buf;
938*4882a593Smuzhiyun 	ep->len = eesize * 2;
939*4882a593Smuzhiyun 
940*4882a593Smuzhiyun 	file->private_data = (void *)ep;
941*4882a593Smuzhiyun 
942*4882a593Smuzhiyun 	return 0;
943*4882a593Smuzhiyun 
944*4882a593Smuzhiyun freebuf:
945*4882a593Smuzhiyun 	vfree(buf);
946*4882a593Smuzhiyun err:
947*4882a593Smuzhiyun 	return ret;
948*4882a593Smuzhiyun 
949*4882a593Smuzhiyun }
950*4882a593Smuzhiyun 
read_file_eeprom(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)951*4882a593Smuzhiyun static ssize_t read_file_eeprom(struct file *file, char __user *user_buf,
952*4882a593Smuzhiyun 				   size_t count, loff_t *ppos)
953*4882a593Smuzhiyun {
954*4882a593Smuzhiyun 	struct eeprom_private *ep = file->private_data;
955*4882a593Smuzhiyun 
956*4882a593Smuzhiyun 	return simple_read_from_buffer(user_buf, count, ppos, ep->buf, ep->len);
957*4882a593Smuzhiyun }
958*4882a593Smuzhiyun 
release_file_eeprom(struct inode * inode,struct file * file)959*4882a593Smuzhiyun static int release_file_eeprom(struct inode *inode, struct file *file)
960*4882a593Smuzhiyun {
961*4882a593Smuzhiyun 	struct eeprom_private *ep = file->private_data;
962*4882a593Smuzhiyun 
963*4882a593Smuzhiyun 	vfree(ep->buf);
964*4882a593Smuzhiyun 	kfree(ep);
965*4882a593Smuzhiyun 
966*4882a593Smuzhiyun 	return 0;
967*4882a593Smuzhiyun }
968*4882a593Smuzhiyun 
969*4882a593Smuzhiyun static const struct file_operations fops_eeprom = {
970*4882a593Smuzhiyun 	.open = open_file_eeprom,
971*4882a593Smuzhiyun 	.read = read_file_eeprom,
972*4882a593Smuzhiyun 	.release = release_file_eeprom,
973*4882a593Smuzhiyun 	.owner = THIS_MODULE,
974*4882a593Smuzhiyun };
975*4882a593Smuzhiyun 
976*4882a593Smuzhiyun 
977*4882a593Smuzhiyun void
ath5k_debug_init_device(struct ath5k_hw * ah)978*4882a593Smuzhiyun ath5k_debug_init_device(struct ath5k_hw *ah)
979*4882a593Smuzhiyun {
980*4882a593Smuzhiyun 	struct dentry *phydir;
981*4882a593Smuzhiyun 
982*4882a593Smuzhiyun 	ah->debug.level = ath5k_debug;
983*4882a593Smuzhiyun 
984*4882a593Smuzhiyun 	phydir = debugfs_create_dir("ath5k", ah->hw->wiphy->debugfsdir);
985*4882a593Smuzhiyun 	if (!phydir)
986*4882a593Smuzhiyun 		return;
987*4882a593Smuzhiyun 
988*4882a593Smuzhiyun 	debugfs_create_file("debug", 0600, phydir, ah, &fops_debug);
989*4882a593Smuzhiyun 	debugfs_create_file("registers", 0400, phydir, ah, &registers_fops);
990*4882a593Smuzhiyun 	debugfs_create_file("beacon", 0600, phydir, ah, &fops_beacon);
991*4882a593Smuzhiyun 	debugfs_create_file("reset", 0200, phydir, ah, &fops_reset);
992*4882a593Smuzhiyun 	debugfs_create_file("antenna", 0600, phydir, ah, &fops_antenna);
993*4882a593Smuzhiyun 	debugfs_create_file("misc", 0400, phydir, ah, &fops_misc);
994*4882a593Smuzhiyun 	debugfs_create_file("eeprom", 0400, phydir, ah, &fops_eeprom);
995*4882a593Smuzhiyun 	debugfs_create_file("frameerrors", 0600, phydir, ah, &fops_frameerrors);
996*4882a593Smuzhiyun 	debugfs_create_file("ani", 0600, phydir, ah, &fops_ani);
997*4882a593Smuzhiyun 	debugfs_create_file("queue", 0600, phydir, ah, &fops_queue);
998*4882a593Smuzhiyun 	debugfs_create_bool("32khz_clock", 0600, phydir,
999*4882a593Smuzhiyun 			    &ah->ah_use_32khz_clock);
1000*4882a593Smuzhiyun }
1001*4882a593Smuzhiyun 
1002*4882a593Smuzhiyun /* functions used in other places */
1003*4882a593Smuzhiyun 
1004*4882a593Smuzhiyun void
ath5k_debug_dump_bands(struct ath5k_hw * ah)1005*4882a593Smuzhiyun ath5k_debug_dump_bands(struct ath5k_hw *ah)
1006*4882a593Smuzhiyun {
1007*4882a593Smuzhiyun 	unsigned int b, i;
1008*4882a593Smuzhiyun 
1009*4882a593Smuzhiyun 	if (likely(!(ah->debug.level & ATH5K_DEBUG_DUMPBANDS)))
1010*4882a593Smuzhiyun 		return;
1011*4882a593Smuzhiyun 
1012*4882a593Smuzhiyun 	for (b = 0; b < NUM_NL80211_BANDS; b++) {
1013*4882a593Smuzhiyun 		struct ieee80211_supported_band *band = &ah->sbands[b];
1014*4882a593Smuzhiyun 		char bname[6];
1015*4882a593Smuzhiyun 		switch (band->band) {
1016*4882a593Smuzhiyun 		case NL80211_BAND_2GHZ:
1017*4882a593Smuzhiyun 			strcpy(bname, "2 GHz");
1018*4882a593Smuzhiyun 			break;
1019*4882a593Smuzhiyun 		case NL80211_BAND_5GHZ:
1020*4882a593Smuzhiyun 			strcpy(bname, "5 GHz");
1021*4882a593Smuzhiyun 			break;
1022*4882a593Smuzhiyun 		default:
1023*4882a593Smuzhiyun 			printk(KERN_DEBUG "Band not supported: %d\n",
1024*4882a593Smuzhiyun 				band->band);
1025*4882a593Smuzhiyun 			return;
1026*4882a593Smuzhiyun 		}
1027*4882a593Smuzhiyun 		printk(KERN_DEBUG "Band %s: channels %d, rates %d\n", bname,
1028*4882a593Smuzhiyun 				band->n_channels, band->n_bitrates);
1029*4882a593Smuzhiyun 		printk(KERN_DEBUG " channels:\n");
1030*4882a593Smuzhiyun 		for (i = 0; i < band->n_channels; i++)
1031*4882a593Smuzhiyun 			printk(KERN_DEBUG "  %3d %d %.4x %.4x\n",
1032*4882a593Smuzhiyun 					ieee80211_frequency_to_channel(
1033*4882a593Smuzhiyun 						band->channels[i].center_freq),
1034*4882a593Smuzhiyun 					band->channels[i].center_freq,
1035*4882a593Smuzhiyun 					band->channels[i].hw_value,
1036*4882a593Smuzhiyun 					band->channels[i].flags);
1037*4882a593Smuzhiyun 		printk(KERN_DEBUG " rates:\n");
1038*4882a593Smuzhiyun 		for (i = 0; i < band->n_bitrates; i++)
1039*4882a593Smuzhiyun 			printk(KERN_DEBUG "  %4d %.4x %.4x %.4x\n",
1040*4882a593Smuzhiyun 					band->bitrates[i].bitrate,
1041*4882a593Smuzhiyun 					band->bitrates[i].hw_value,
1042*4882a593Smuzhiyun 					band->bitrates[i].flags,
1043*4882a593Smuzhiyun 					band->bitrates[i].hw_value_short);
1044*4882a593Smuzhiyun 	}
1045*4882a593Smuzhiyun }
1046*4882a593Smuzhiyun 
1047*4882a593Smuzhiyun static inline void
ath5k_debug_printrxbuf(struct ath5k_buf * bf,int done,struct ath5k_rx_status * rs)1048*4882a593Smuzhiyun ath5k_debug_printrxbuf(struct ath5k_buf *bf, int done,
1049*4882a593Smuzhiyun 		       struct ath5k_rx_status *rs)
1050*4882a593Smuzhiyun {
1051*4882a593Smuzhiyun 	struct ath5k_desc *ds = bf->desc;
1052*4882a593Smuzhiyun 	struct ath5k_hw_all_rx_desc *rd = &ds->ud.ds_rx;
1053*4882a593Smuzhiyun 
1054*4882a593Smuzhiyun 	printk(KERN_DEBUG "R (%p %llx) %08x %08x %08x %08x %08x %08x %c\n",
1055*4882a593Smuzhiyun 		ds, (unsigned long long)bf->daddr,
1056*4882a593Smuzhiyun 		ds->ds_link, ds->ds_data,
1057*4882a593Smuzhiyun 		rd->rx_ctl.rx_control_0, rd->rx_ctl.rx_control_1,
1058*4882a593Smuzhiyun 		rd->rx_stat.rx_status_0, rd->rx_stat.rx_status_1,
1059*4882a593Smuzhiyun 		!done ? ' ' : (rs->rs_status == 0) ? '*' : '!');
1060*4882a593Smuzhiyun }
1061*4882a593Smuzhiyun 
1062*4882a593Smuzhiyun void
ath5k_debug_printrxbuffs(struct ath5k_hw * ah)1063*4882a593Smuzhiyun ath5k_debug_printrxbuffs(struct ath5k_hw *ah)
1064*4882a593Smuzhiyun {
1065*4882a593Smuzhiyun 	struct ath5k_desc *ds;
1066*4882a593Smuzhiyun 	struct ath5k_buf *bf;
1067*4882a593Smuzhiyun 	struct ath5k_rx_status rs = {};
1068*4882a593Smuzhiyun 	int status;
1069*4882a593Smuzhiyun 
1070*4882a593Smuzhiyun 	if (likely(!(ah->debug.level & ATH5K_DEBUG_DESC)))
1071*4882a593Smuzhiyun 		return;
1072*4882a593Smuzhiyun 
1073*4882a593Smuzhiyun 	printk(KERN_DEBUG "rxdp %x, rxlink %p\n",
1074*4882a593Smuzhiyun 		ath5k_hw_get_rxdp(ah), ah->rxlink);
1075*4882a593Smuzhiyun 
1076*4882a593Smuzhiyun 	spin_lock_bh(&ah->rxbuflock);
1077*4882a593Smuzhiyun 	list_for_each_entry(bf, &ah->rxbuf, list) {
1078*4882a593Smuzhiyun 		ds = bf->desc;
1079*4882a593Smuzhiyun 		status = ah->ah_proc_rx_desc(ah, ds, &rs);
1080*4882a593Smuzhiyun 		if (!status)
1081*4882a593Smuzhiyun 			ath5k_debug_printrxbuf(bf, status == 0, &rs);
1082*4882a593Smuzhiyun 	}
1083*4882a593Smuzhiyun 	spin_unlock_bh(&ah->rxbuflock);
1084*4882a593Smuzhiyun }
1085*4882a593Smuzhiyun 
1086*4882a593Smuzhiyun void
ath5k_debug_printtxbuf(struct ath5k_hw * ah,struct ath5k_buf * bf)1087*4882a593Smuzhiyun ath5k_debug_printtxbuf(struct ath5k_hw *ah, struct ath5k_buf *bf)
1088*4882a593Smuzhiyun {
1089*4882a593Smuzhiyun 	struct ath5k_desc *ds = bf->desc;
1090*4882a593Smuzhiyun 	struct ath5k_hw_5212_tx_desc *td = &ds->ud.ds_tx5212;
1091*4882a593Smuzhiyun 	struct ath5k_tx_status ts = {};
1092*4882a593Smuzhiyun 	int done;
1093*4882a593Smuzhiyun 
1094*4882a593Smuzhiyun 	if (likely(!(ah->debug.level & ATH5K_DEBUG_DESC)))
1095*4882a593Smuzhiyun 		return;
1096*4882a593Smuzhiyun 
1097*4882a593Smuzhiyun 	done = ah->ah_proc_tx_desc(ah, bf->desc, &ts);
1098*4882a593Smuzhiyun 
1099*4882a593Smuzhiyun 	printk(KERN_DEBUG "T (%p %llx) %08x %08x %08x %08x %08x %08x %08x "
1100*4882a593Smuzhiyun 		"%08x %c\n", ds, (unsigned long long)bf->daddr, ds->ds_link,
1101*4882a593Smuzhiyun 		ds->ds_data, td->tx_ctl.tx_control_0, td->tx_ctl.tx_control_1,
1102*4882a593Smuzhiyun 		td->tx_ctl.tx_control_2, td->tx_ctl.tx_control_3,
1103*4882a593Smuzhiyun 		td->tx_stat.tx_status_0, td->tx_stat.tx_status_1,
1104*4882a593Smuzhiyun 		done ? ' ' : (ts.ts_status == 0) ? '*' : '!');
1105*4882a593Smuzhiyun }
1106