1203c4805SLuis R. Rodriguez /*
2203c4805SLuis R. Rodriguez  * Copyright (c) 2007-2008 Bruno Randolf <bruno@thinktube.com>
3203c4805SLuis R. Rodriguez  *
4203c4805SLuis R. Rodriguez  *  This file is free software: you may copy, redistribute and/or modify it
5203c4805SLuis R. Rodriguez  *  under the terms of the GNU General Public License as published by the
6203c4805SLuis R. Rodriguez  *  Free Software Foundation, either version 2 of the License, or (at your
7203c4805SLuis R. Rodriguez  *  option) any later version.
8203c4805SLuis R. Rodriguez  *
9203c4805SLuis R. Rodriguez  *  This file is distributed in the hope that it will be useful, but
10203c4805SLuis R. Rodriguez  *  WITHOUT ANY WARRANTY; without even the implied warranty of
11203c4805SLuis R. Rodriguez  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12203c4805SLuis R. Rodriguez  *  General Public License for more details.
13203c4805SLuis R. Rodriguez  *
14203c4805SLuis R. Rodriguez  *  You should have received a copy of the GNU General Public License
15203c4805SLuis R. Rodriguez  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
16203c4805SLuis R. Rodriguez  *
17203c4805SLuis R. Rodriguez  *
18203c4805SLuis R. Rodriguez  * This file incorporates work covered by the following copyright and
19203c4805SLuis R. Rodriguez  * permission notice:
20203c4805SLuis R. Rodriguez  *
21203c4805SLuis R. Rodriguez  * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
22203c4805SLuis R. Rodriguez  * Copyright (c) 2004-2005 Atheros Communications, Inc.
23203c4805SLuis R. Rodriguez  * Copyright (c) 2006 Devicescape Software, Inc.
24203c4805SLuis R. Rodriguez  * Copyright (c) 2007 Jiri Slaby <jirislaby@gmail.com>
25203c4805SLuis R. Rodriguez  * Copyright (c) 2007 Luis R. Rodriguez <mcgrof@winlab.rutgers.edu>
26203c4805SLuis R. Rodriguez  *
27203c4805SLuis R. Rodriguez  * All rights reserved.
28203c4805SLuis R. Rodriguez  *
29203c4805SLuis R. Rodriguez  * Redistribution and use in source and binary forms, with or without
30203c4805SLuis R. Rodriguez  * modification, are permitted provided that the following conditions
31203c4805SLuis R. Rodriguez  * are met:
32203c4805SLuis R. Rodriguez  * 1. Redistributions of source code must retain the above copyright
33203c4805SLuis R. Rodriguez  *    notice, this list of conditions and the following disclaimer,
34203c4805SLuis R. Rodriguez  *    without modification.
35203c4805SLuis R. Rodriguez  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
36203c4805SLuis R. Rodriguez  *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
37203c4805SLuis R. Rodriguez  *    redistribution must be conditioned upon including a substantially
38203c4805SLuis R. Rodriguez  *    similar Disclaimer requirement for further binary redistribution.
39203c4805SLuis R. Rodriguez  * 3. Neither the names of the above-listed copyright holders nor the names
40203c4805SLuis R. Rodriguez  *    of any contributors may be used to endorse or promote products derived
41203c4805SLuis R. Rodriguez  *    from this software without specific prior written permission.
42203c4805SLuis R. Rodriguez  *
43203c4805SLuis R. Rodriguez  * Alternatively, this software may be distributed under the terms of the
44203c4805SLuis R. Rodriguez  * GNU General Public License ("GPL") version 2 as published by the Free
45203c4805SLuis R. Rodriguez  * Software Foundation.
46203c4805SLuis R. Rodriguez  *
47203c4805SLuis R. Rodriguez  * NO WARRANTY
48203c4805SLuis R. Rodriguez  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
49203c4805SLuis R. Rodriguez  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
50203c4805SLuis R. Rodriguez  * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
51203c4805SLuis R. Rodriguez  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
52203c4805SLuis R. Rodriguez  * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
53203c4805SLuis R. Rodriguez  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
54203c4805SLuis R. Rodriguez  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
55203c4805SLuis R. Rodriguez  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
56203c4805SLuis R. Rodriguez  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
57203c4805SLuis R. Rodriguez  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
58203c4805SLuis R. Rodriguez  * THE POSSIBILITY OF SUCH DAMAGES.
59203c4805SLuis R. Rodriguez  */
60516304b0SJoe Perches 
61516304b0SJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
62516304b0SJoe Perches 
63ee40fa06SPaul Gortmaker #include <linux/export.h>
646eb07cafSPaul Gortmaker #include <linux/moduleparam.h>
6532bc6d1aSStephen Rothwell #include <linux/vmalloc.h>
66203c4805SLuis R. Rodriguez 
67931be260SPavel Roskin #include <linux/seq_file.h>
68931be260SPavel Roskin #include <linux/list.h>
69203c4805SLuis R. Rodriguez #include "debug.h"
70931be260SPavel Roskin #include "ath5k.h"
71931be260SPavel Roskin #include "reg.h"
72931be260SPavel Roskin #include "base.h"
73203c4805SLuis R. Rodriguez 
74203c4805SLuis R. Rodriguez static unsigned int ath5k_debug;
75203c4805SLuis R. Rodriguez module_param_named(debug, ath5k_debug, uint, 0);
76203c4805SLuis R. Rodriguez 
77203c4805SLuis R. Rodriguez 
78203c4805SLuis R. Rodriguez /* debugfs: registers */
79203c4805SLuis R. Rodriguez 
80203c4805SLuis R. Rodriguez struct reg {
81203c4805SLuis R. Rodriguez 	const char *name;
82203c4805SLuis R. Rodriguez 	int addr;
83203c4805SLuis R. Rodriguez };
84203c4805SLuis R. Rodriguez 
85203c4805SLuis R. Rodriguez #define REG_STRUCT_INIT(r) { #r, r }
86203c4805SLuis R. Rodriguez 
87203c4805SLuis R. Rodriguez /* just a few random registers, might want to add more */
88203c4805SLuis R. Rodriguez static const struct reg regs[] = {
89203c4805SLuis R. Rodriguez 	REG_STRUCT_INIT(AR5K_CR),
90203c4805SLuis R. Rodriguez 	REG_STRUCT_INIT(AR5K_RXDP),
91203c4805SLuis R. Rodriguez 	REG_STRUCT_INIT(AR5K_CFG),
92203c4805SLuis R. Rodriguez 	REG_STRUCT_INIT(AR5K_IER),
93203c4805SLuis R. Rodriguez 	REG_STRUCT_INIT(AR5K_BCR),
94203c4805SLuis R. Rodriguez 	REG_STRUCT_INIT(AR5K_RTSD0),
95203c4805SLuis R. Rodriguez 	REG_STRUCT_INIT(AR5K_RTSD1),
96203c4805SLuis R. Rodriguez 	REG_STRUCT_INIT(AR5K_TXCFG),
97203c4805SLuis R. Rodriguez 	REG_STRUCT_INIT(AR5K_RXCFG),
98203c4805SLuis R. Rodriguez 	REG_STRUCT_INIT(AR5K_RXJLA),
99203c4805SLuis R. Rodriguez 	REG_STRUCT_INIT(AR5K_MIBC),
100203c4805SLuis R. Rodriguez 	REG_STRUCT_INIT(AR5K_TOPS),
101203c4805SLuis R. Rodriguez 	REG_STRUCT_INIT(AR5K_RXNOFRM),
102203c4805SLuis R. Rodriguez 	REG_STRUCT_INIT(AR5K_TXNOFRM),
103203c4805SLuis R. Rodriguez 	REG_STRUCT_INIT(AR5K_RPGTO),
104203c4805SLuis R. Rodriguez 	REG_STRUCT_INIT(AR5K_RFCNT),
105203c4805SLuis R. Rodriguez 	REG_STRUCT_INIT(AR5K_MISC),
106203c4805SLuis R. Rodriguez 	REG_STRUCT_INIT(AR5K_QCUDCU_CLKGT),
107203c4805SLuis R. Rodriguez 	REG_STRUCT_INIT(AR5K_ISR),
108203c4805SLuis R. Rodriguez 	REG_STRUCT_INIT(AR5K_PISR),
109203c4805SLuis R. Rodriguez 	REG_STRUCT_INIT(AR5K_SISR0),
110203c4805SLuis R. Rodriguez 	REG_STRUCT_INIT(AR5K_SISR1),
111203c4805SLuis R. Rodriguez 	REG_STRUCT_INIT(AR5K_SISR2),
112203c4805SLuis R. Rodriguez 	REG_STRUCT_INIT(AR5K_SISR3),
113203c4805SLuis R. Rodriguez 	REG_STRUCT_INIT(AR5K_SISR4),
114203c4805SLuis R. Rodriguez 	REG_STRUCT_INIT(AR5K_IMR),
115203c4805SLuis R. Rodriguez 	REG_STRUCT_INIT(AR5K_PIMR),
116203c4805SLuis R. Rodriguez 	REG_STRUCT_INIT(AR5K_SIMR0),
117203c4805SLuis R. Rodriguez 	REG_STRUCT_INIT(AR5K_SIMR1),
118203c4805SLuis R. Rodriguez 	REG_STRUCT_INIT(AR5K_SIMR2),
119203c4805SLuis R. Rodriguez 	REG_STRUCT_INIT(AR5K_SIMR3),
120203c4805SLuis R. Rodriguez 	REG_STRUCT_INIT(AR5K_SIMR4),
121203c4805SLuis R. Rodriguez 	REG_STRUCT_INIT(AR5K_DCM_ADDR),
122203c4805SLuis R. Rodriguez 	REG_STRUCT_INIT(AR5K_DCCFG),
123203c4805SLuis R. Rodriguez 	REG_STRUCT_INIT(AR5K_CCFG),
124203c4805SLuis R. Rodriguez 	REG_STRUCT_INIT(AR5K_CPC0),
125203c4805SLuis R. Rodriguez 	REG_STRUCT_INIT(AR5K_CPC1),
126203c4805SLuis R. Rodriguez 	REG_STRUCT_INIT(AR5K_CPC2),
127203c4805SLuis R. Rodriguez 	REG_STRUCT_INIT(AR5K_CPC3),
128203c4805SLuis R. Rodriguez 	REG_STRUCT_INIT(AR5K_CPCOVF),
129203c4805SLuis R. Rodriguez 	REG_STRUCT_INIT(AR5K_RESET_CTL),
130203c4805SLuis R. Rodriguez 	REG_STRUCT_INIT(AR5K_SLEEP_CTL),
131203c4805SLuis R. Rodriguez 	REG_STRUCT_INIT(AR5K_INTPEND),
132203c4805SLuis R. Rodriguez 	REG_STRUCT_INIT(AR5K_SFR),
133203c4805SLuis R. Rodriguez 	REG_STRUCT_INIT(AR5K_PCICFG),
134203c4805SLuis R. Rodriguez 	REG_STRUCT_INIT(AR5K_GPIOCR),
135203c4805SLuis R. Rodriguez 	REG_STRUCT_INIT(AR5K_GPIODO),
136203c4805SLuis R. Rodriguez 	REG_STRUCT_INIT(AR5K_SREV),
137203c4805SLuis R. Rodriguez };
138203c4805SLuis R. Rodriguez 
reg_start(struct seq_file * seq,loff_t * pos)139203c4805SLuis R. Rodriguez static void *reg_start(struct seq_file *seq, loff_t *pos)
140203c4805SLuis R. Rodriguez {
141203c4805SLuis R. Rodriguez 	return *pos < ARRAY_SIZE(regs) ? (void *)&regs[*pos] : NULL;
142203c4805SLuis R. Rodriguez }
143203c4805SLuis R. Rodriguez 
reg_stop(struct seq_file * seq,void * p)144203c4805SLuis R. Rodriguez static void reg_stop(struct seq_file *seq, void *p)
145203c4805SLuis R. Rodriguez {
146203c4805SLuis R. Rodriguez 	/* nothing to do */
147203c4805SLuis R. Rodriguez }
148203c4805SLuis R. Rodriguez 
reg_next(struct seq_file * seq,void * p,loff_t * pos)149203c4805SLuis R. Rodriguez static void *reg_next(struct seq_file *seq, void *p, loff_t *pos)
150203c4805SLuis R. Rodriguez {
151203c4805SLuis R. Rodriguez 	++*pos;
152203c4805SLuis R. Rodriguez 	return *pos < ARRAY_SIZE(regs) ? (void *)&regs[*pos] : NULL;
153203c4805SLuis R. Rodriguez }
154203c4805SLuis R. Rodriguez 
reg_show(struct seq_file * seq,void * p)155203c4805SLuis R. Rodriguez static int reg_show(struct seq_file *seq, void *p)
156203c4805SLuis R. Rodriguez {
157e0d687bdSPavel Roskin 	struct ath5k_hw *ah = seq->private;
158203c4805SLuis R. Rodriguez 	struct reg *r = p;
159203c4805SLuis R. Rodriguez 	seq_printf(seq, "%-25s0x%08x\n", r->name,
160e0d687bdSPavel Roskin 		ath5k_hw_reg_read(ah, r->addr));
161203c4805SLuis R. Rodriguez 	return 0;
162203c4805SLuis R. Rodriguez }
163203c4805SLuis R. Rodriguez 
164aac352d6SLiu Shixin static const struct seq_operations registers_sops = {
165203c4805SLuis R. Rodriguez 	.start = reg_start,
166203c4805SLuis R. Rodriguez 	.next  = reg_next,
167203c4805SLuis R. Rodriguez 	.stop  = reg_stop,
168203c4805SLuis R. Rodriguez 	.show  = reg_show
169203c4805SLuis R. Rodriguez };
170203c4805SLuis R. Rodriguez 
171aac352d6SLiu Shixin DEFINE_SEQ_ATTRIBUTE(registers);
172203c4805SLuis R. Rodriguez 
173203c4805SLuis R. Rodriguez /* debugfs: beacons */
174203c4805SLuis R. Rodriguez 
read_file_beacon(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)175203c4805SLuis R. Rodriguez static ssize_t read_file_beacon(struct file *file, char __user *user_buf,
176203c4805SLuis R. Rodriguez 				   size_t count, loff_t *ppos)
177203c4805SLuis R. Rodriguez {
178e0d687bdSPavel Roskin 	struct ath5k_hw *ah = file->private_data;
179203c4805SLuis R. Rodriguez 	char buf[500];
180203c4805SLuis R. Rodriguez 	unsigned int len = 0;
181203c4805SLuis R. Rodriguez 	unsigned int v;
182203c4805SLuis R. Rodriguez 	u64 tsf;
183203c4805SLuis R. Rodriguez 
184e0d687bdSPavel Roskin 	v = ath5k_hw_reg_read(ah, AR5K_BEACON);
185dfb252c7STakashi Iwai 	len += scnprintf(buf + len, sizeof(buf) - len,
186203c4805SLuis R. Rodriguez 		"%-24s0x%08x\tintval: %d\tTIM: 0x%x\n",
187203c4805SLuis R. Rodriguez 		"AR5K_BEACON", v, v & AR5K_BEACON_PERIOD,
188203c4805SLuis R. Rodriguez 		(v & AR5K_BEACON_TIM) >> AR5K_BEACON_TIM_S);
189203c4805SLuis R. Rodriguez 
190dfb252c7STakashi Iwai 	len += scnprintf(buf + len, sizeof(buf) - len, "%-24s0x%08x\n",
191e0d687bdSPavel Roskin 		"AR5K_LAST_TSTP", ath5k_hw_reg_read(ah, AR5K_LAST_TSTP));
192203c4805SLuis R. Rodriguez 
193dfb252c7STakashi Iwai 	len += scnprintf(buf + len, sizeof(buf) - len, "%-24s0x%08x\n\n",
194e0d687bdSPavel Roskin 		"AR5K_BEACON_CNT", ath5k_hw_reg_read(ah, AR5K_BEACON_CNT));
195203c4805SLuis R. Rodriguez 
196e0d687bdSPavel Roskin 	v = ath5k_hw_reg_read(ah, AR5K_TIMER0);
197dfb252c7STakashi Iwai 	len += scnprintf(buf + len, sizeof(buf) - len, "%-24s0x%08x\tTU: %08x\n",
198203c4805SLuis R. Rodriguez 		"AR5K_TIMER0 (TBTT)", v, v);
199203c4805SLuis R. Rodriguez 
200e0d687bdSPavel Roskin 	v = ath5k_hw_reg_read(ah, AR5K_TIMER1);
201dfb252c7STakashi Iwai 	len += scnprintf(buf + len, sizeof(buf) - len, "%-24s0x%08x\tTU: %08x\n",
202203c4805SLuis R. Rodriguez 		"AR5K_TIMER1 (DMA)", v, v >> 3);
203203c4805SLuis R. Rodriguez 
204e0d687bdSPavel Roskin 	v = ath5k_hw_reg_read(ah, AR5K_TIMER2);
205dfb252c7STakashi Iwai 	len += scnprintf(buf + len, sizeof(buf) - len, "%-24s0x%08x\tTU: %08x\n",
206203c4805SLuis R. Rodriguez 		"AR5K_TIMER2 (SWBA)", v, v >> 3);
207203c4805SLuis R. Rodriguez 
208e0d687bdSPavel Roskin 	v = ath5k_hw_reg_read(ah, AR5K_TIMER3);
209dfb252c7STakashi Iwai 	len += scnprintf(buf + len, sizeof(buf) - len, "%-24s0x%08x\tTU: %08x\n",
210203c4805SLuis R. Rodriguez 		"AR5K_TIMER3 (ATIM)", v, v);
211203c4805SLuis R. Rodriguez 
212e0d687bdSPavel Roskin 	tsf = ath5k_hw_get_tsf64(ah);
213dfb252c7STakashi Iwai 	len += scnprintf(buf + len, sizeof(buf) - len,
214203c4805SLuis R. Rodriguez 		"TSF\t\t0x%016llx\tTU: %08x\n",
215203c4805SLuis R. Rodriguez 		(unsigned long long)tsf, TSF_TO_TU(tsf));
216203c4805SLuis R. Rodriguez 
2172189d13fSDan Carpenter 	if (len > sizeof(buf))
2182189d13fSDan Carpenter 		len = sizeof(buf);
2192189d13fSDan Carpenter 
220203c4805SLuis R. Rodriguez 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
221203c4805SLuis R. Rodriguez }
222203c4805SLuis R. Rodriguez 
write_file_beacon(struct file * file,const char __user * userbuf,size_t count,loff_t * ppos)223203c4805SLuis R. Rodriguez static ssize_t write_file_beacon(struct file *file,
224203c4805SLuis R. Rodriguez 				 const char __user *userbuf,
225203c4805SLuis R. Rodriguez 				 size_t count, loff_t *ppos)
226203c4805SLuis R. Rodriguez {
227e0d687bdSPavel Roskin 	struct ath5k_hw *ah = file->private_data;
228203c4805SLuis R. Rodriguez 	char buf[20];
229203c4805SLuis R. Rodriguez 
2308aada63cSDjalal Harouni 	count = min_t(size_t, count, sizeof(buf) - 1);
2318aada63cSDjalal Harouni 	if (copy_from_user(buf, userbuf, count))
232203c4805SLuis R. Rodriguez 		return -EFAULT;
233203c4805SLuis R. Rodriguez 
2348aada63cSDjalal Harouni 	buf[count] = '\0';
235203c4805SLuis R. Rodriguez 	if (strncmp(buf, "disable", 7) == 0) {
236203c4805SLuis R. Rodriguez 		AR5K_REG_DISABLE_BITS(ah, AR5K_BEACON, AR5K_BEACON_ENABLE);
237516304b0SJoe Perches 		pr_info("debugfs disable beacons\n");
238203c4805SLuis R. Rodriguez 	} else if (strncmp(buf, "enable", 6) == 0) {
239203c4805SLuis R. Rodriguez 		AR5K_REG_ENABLE_BITS(ah, AR5K_BEACON, AR5K_BEACON_ENABLE);
240516304b0SJoe Perches 		pr_info("debugfs enable beacons\n");
241203c4805SLuis R. Rodriguez 	}
242203c4805SLuis R. Rodriguez 	return count;
243203c4805SLuis R. Rodriguez }
244203c4805SLuis R. Rodriguez 
245203c4805SLuis R. Rodriguez static const struct file_operations fops_beacon = {
246203c4805SLuis R. Rodriguez 	.read = read_file_beacon,
247203c4805SLuis R. Rodriguez 	.write = write_file_beacon,
248234e3405SStephen Boyd 	.open = simple_open,
249203c4805SLuis R. Rodriguez 	.owner = THIS_MODULE,
2506038f373SArnd Bergmann 	.llseek = default_llseek,
251203c4805SLuis R. Rodriguez };
252203c4805SLuis R. Rodriguez 
253203c4805SLuis R. Rodriguez 
254203c4805SLuis R. Rodriguez /* debugfs: reset */
255203c4805SLuis R. Rodriguez 
write_file_reset(struct file * file,const char __user * userbuf,size_t count,loff_t * ppos)256203c4805SLuis R. Rodriguez static ssize_t write_file_reset(struct file *file,
257203c4805SLuis R. Rodriguez 				 const char __user *userbuf,
258203c4805SLuis R. Rodriguez 				 size_t count, loff_t *ppos)
259203c4805SLuis R. Rodriguez {
260e0d687bdSPavel Roskin 	struct ath5k_hw *ah = file->private_data;
261e0d687bdSPavel Roskin 	ATH5K_DBG(ah, ATH5K_DEBUG_RESET, "debug file triggered reset\n");
262e0d687bdSPavel Roskin 	ieee80211_queue_work(ah->hw, &ah->reset_work);
263203c4805SLuis R. Rodriguez 	return count;
264203c4805SLuis R. Rodriguez }
265203c4805SLuis R. Rodriguez 
266203c4805SLuis R. Rodriguez static const struct file_operations fops_reset = {
267203c4805SLuis R. Rodriguez 	.write = write_file_reset,
268234e3405SStephen Boyd 	.open = simple_open,
269203c4805SLuis R. Rodriguez 	.owner = THIS_MODULE,
2706038f373SArnd Bergmann 	.llseek = noop_llseek,
271203c4805SLuis R. Rodriguez };
272203c4805SLuis R. Rodriguez 
273203c4805SLuis R. Rodriguez 
274203c4805SLuis R. Rodriguez /* debugfs: debug level */
275203c4805SLuis R. Rodriguez 
276203c4805SLuis R. Rodriguez static const struct {
277203c4805SLuis R. Rodriguez 	enum ath5k_debug_level level;
278203c4805SLuis R. Rodriguez 	const char *name;
279203c4805SLuis R. Rodriguez 	const char *desc;
280203c4805SLuis R. Rodriguez } dbg_info[] = {
281203c4805SLuis R. Rodriguez 	{ ATH5K_DEBUG_RESET,	"reset",	"reset and initialization" },
282203c4805SLuis R. Rodriguez 	{ ATH5K_DEBUG_INTR,	"intr",		"interrupt handling" },
283203c4805SLuis R. Rodriguez 	{ ATH5K_DEBUG_MODE,	"mode",		"mode init/setup" },
284203c4805SLuis R. Rodriguez 	{ ATH5K_DEBUG_XMIT,	"xmit",		"basic xmit operation" },
285203c4805SLuis R. Rodriguez 	{ ATH5K_DEBUG_BEACON,	"beacon",	"beacon handling" },
286203c4805SLuis R. Rodriguez 	{ ATH5K_DEBUG_CALIBRATE, "calib",	"periodic calibration" },
287203c4805SLuis R. Rodriguez 	{ ATH5K_DEBUG_TXPOWER,	"txpower",	"transmit power setting" },
288203c4805SLuis R. Rodriguez 	{ ATH5K_DEBUG_LED,	"led",		"LED management" },
289203c4805SLuis R. Rodriguez 	{ ATH5K_DEBUG_DUMPBANDS, "dumpbands",	"dump bands" },
290b3a28e68SNick Kossifidis 	{ ATH5K_DEBUG_DMA,	"dma",		"dma start/stop" },
2912111ac0dSBruno Randolf 	{ ATH5K_DEBUG_ANI,	"ani",		"adaptive noise immunity" },
292b4c52612SBob Copeland 	{ ATH5K_DEBUG_DESC,	"desc",		"descriptor chains" },
293203c4805SLuis R. Rodriguez 	{ ATH5K_DEBUG_ANY,	"all",		"show all debug levels" },
294203c4805SLuis R. Rodriguez };
295203c4805SLuis R. Rodriguez 
read_file_debug(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)296203c4805SLuis R. Rodriguez static ssize_t read_file_debug(struct file *file, char __user *user_buf,
297203c4805SLuis R. Rodriguez 				   size_t count, loff_t *ppos)
298203c4805SLuis R. Rodriguez {
299e0d687bdSPavel Roskin 	struct ath5k_hw *ah = file->private_data;
300203c4805SLuis R. Rodriguez 	char buf[700];
301203c4805SLuis R. Rodriguez 	unsigned int len = 0;
302203c4805SLuis R. Rodriguez 	unsigned int i;
303203c4805SLuis R. Rodriguez 
304dfb252c7STakashi Iwai 	len += scnprintf(buf + len, sizeof(buf) - len,
305e0d687bdSPavel Roskin 		"DEBUG LEVEL: 0x%08x\n\n", ah->debug.level);
306203c4805SLuis R. Rodriguez 
307203c4805SLuis R. Rodriguez 	for (i = 0; i < ARRAY_SIZE(dbg_info) - 1; i++) {
308dfb252c7STakashi Iwai 		len += scnprintf(buf + len, sizeof(buf) - len,
309203c4805SLuis R. Rodriguez 			"%10s %c 0x%08x - %s\n", dbg_info[i].name,
310e0d687bdSPavel Roskin 			ah->debug.level & dbg_info[i].level ? '+' : ' ',
311203c4805SLuis R. Rodriguez 			dbg_info[i].level, dbg_info[i].desc);
312203c4805SLuis R. Rodriguez 	}
313dfb252c7STakashi Iwai 	len += scnprintf(buf + len, sizeof(buf) - len,
314203c4805SLuis R. Rodriguez 		"%10s %c 0x%08x - %s\n", dbg_info[i].name,
315e0d687bdSPavel Roskin 		ah->debug.level == dbg_info[i].level ? '+' : ' ',
316203c4805SLuis R. Rodriguez 		dbg_info[i].level, dbg_info[i].desc);
317203c4805SLuis R. Rodriguez 
3182189d13fSDan Carpenter 	if (len > sizeof(buf))
3192189d13fSDan Carpenter 		len = sizeof(buf);
3202189d13fSDan Carpenter 
321203c4805SLuis R. Rodriguez 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
322203c4805SLuis R. Rodriguez }
323203c4805SLuis R. Rodriguez 
write_file_debug(struct file * file,const char __user * userbuf,size_t count,loff_t * ppos)324203c4805SLuis R. Rodriguez static ssize_t write_file_debug(struct file *file,
325203c4805SLuis R. Rodriguez 				 const char __user *userbuf,
326203c4805SLuis R. Rodriguez 				 size_t count, loff_t *ppos)
327203c4805SLuis R. Rodriguez {
328e0d687bdSPavel Roskin 	struct ath5k_hw *ah = file->private_data;
329203c4805SLuis R. Rodriguez 	unsigned int i;
330203c4805SLuis R. Rodriguez 	char buf[20];
331203c4805SLuis R. Rodriguez 
3328aada63cSDjalal Harouni 	count = min_t(size_t, count, sizeof(buf) - 1);
3338aada63cSDjalal Harouni 	if (copy_from_user(buf, userbuf, count))
334203c4805SLuis R. Rodriguez 		return -EFAULT;
335203c4805SLuis R. Rodriguez 
3368aada63cSDjalal Harouni 	buf[count] = '\0';
337203c4805SLuis R. Rodriguez 	for (i = 0; i < ARRAY_SIZE(dbg_info); i++) {
338203c4805SLuis R. Rodriguez 		if (strncmp(buf, dbg_info[i].name,
339203c4805SLuis R. Rodriguez 					strlen(dbg_info[i].name)) == 0) {
340e0d687bdSPavel Roskin 			ah->debug.level ^= dbg_info[i].level; /* toggle bit */
341203c4805SLuis R. Rodriguez 			break;
342203c4805SLuis R. Rodriguez 		}
343203c4805SLuis R. Rodriguez 	}
344203c4805SLuis R. Rodriguez 	return count;
345203c4805SLuis R. Rodriguez }
346203c4805SLuis R. Rodriguez 
347203c4805SLuis R. Rodriguez static const struct file_operations fops_debug = {
348203c4805SLuis R. Rodriguez 	.read = read_file_debug,
349203c4805SLuis R. Rodriguez 	.write = write_file_debug,
350234e3405SStephen Boyd 	.open = simple_open,
351203c4805SLuis R. Rodriguez 	.owner = THIS_MODULE,
3526038f373SArnd Bergmann 	.llseek = default_llseek,
353203c4805SLuis R. Rodriguez };
354203c4805SLuis R. Rodriguez 
355203c4805SLuis R. Rodriguez 
356604eeaddSBruno Randolf /* debugfs: antenna */
357604eeaddSBruno Randolf 
read_file_antenna(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)358604eeaddSBruno Randolf static ssize_t read_file_antenna(struct file *file, char __user *user_buf,
359604eeaddSBruno Randolf 				   size_t count, loff_t *ppos)
360604eeaddSBruno Randolf {
361e0d687bdSPavel Roskin 	struct ath5k_hw *ah = file->private_data;
362604eeaddSBruno Randolf 	char buf[700];
363604eeaddSBruno Randolf 	unsigned int len = 0;
364604eeaddSBruno Randolf 	unsigned int i;
365604eeaddSBruno Randolf 	unsigned int v;
366604eeaddSBruno Randolf 
367dfb252c7STakashi Iwai 	len += scnprintf(buf + len, sizeof(buf) - len, "antenna mode\t%d\n",
368e0d687bdSPavel Roskin 		ah->ah_ant_mode);
369dfb252c7STakashi Iwai 	len += scnprintf(buf + len, sizeof(buf) - len, "default antenna\t%d\n",
370e0d687bdSPavel Roskin 		ah->ah_def_ant);
371dfb252c7STakashi Iwai 	len += scnprintf(buf + len, sizeof(buf) - len, "tx antenna\t%d\n",
372e0d687bdSPavel Roskin 		ah->ah_tx_ant);
373604eeaddSBruno Randolf 
374dfb252c7STakashi Iwai 	len += scnprintf(buf + len, sizeof(buf) - len, "\nANTENNA\t\tRX\tTX\n");
375e0d687bdSPavel Roskin 	for (i = 1; i < ARRAY_SIZE(ah->stats.antenna_rx); i++) {
376dfb252c7STakashi Iwai 		len += scnprintf(buf + len, sizeof(buf) - len,
377604eeaddSBruno Randolf 			"[antenna %d]\t%d\t%d\n",
378e0d687bdSPavel Roskin 			i, ah->stats.antenna_rx[i], ah->stats.antenna_tx[i]);
379604eeaddSBruno Randolf 	}
380dfb252c7STakashi Iwai 	len += scnprintf(buf + len, sizeof(buf) - len, "[invalid]\t%d\t%d\n",
381e0d687bdSPavel Roskin 			ah->stats.antenna_rx[0], ah->stats.antenna_tx[0]);
382604eeaddSBruno Randolf 
383e0d687bdSPavel Roskin 	v = ath5k_hw_reg_read(ah, AR5K_DEFAULT_ANTENNA);
384dfb252c7STakashi Iwai 	len += scnprintf(buf + len, sizeof(buf) - len,
385604eeaddSBruno Randolf 			"\nAR5K_DEFAULT_ANTENNA\t0x%08x\n", v);
386604eeaddSBruno Randolf 
387e0d687bdSPavel Roskin 	v = ath5k_hw_reg_read(ah, AR5K_STA_ID1);
388dfb252c7STakashi Iwai 	len += scnprintf(buf + len, sizeof(buf) - len,
389604eeaddSBruno Randolf 		"AR5K_STA_ID1_DEFAULT_ANTENNA\t%d\n",
390604eeaddSBruno Randolf 		(v & AR5K_STA_ID1_DEFAULT_ANTENNA) != 0);
391dfb252c7STakashi Iwai 	len += scnprintf(buf + len, sizeof(buf) - len,
392604eeaddSBruno Randolf 		"AR5K_STA_ID1_DESC_ANTENNA\t%d\n",
393604eeaddSBruno Randolf 		(v & AR5K_STA_ID1_DESC_ANTENNA) != 0);
394dfb252c7STakashi Iwai 	len += scnprintf(buf + len, sizeof(buf) - len,
395604eeaddSBruno Randolf 		"AR5K_STA_ID1_RTS_DEF_ANTENNA\t%d\n",
396604eeaddSBruno Randolf 		(v & AR5K_STA_ID1_RTS_DEF_ANTENNA) != 0);
397dfb252c7STakashi Iwai 	len += scnprintf(buf + len, sizeof(buf) - len,
398604eeaddSBruno Randolf 		"AR5K_STA_ID1_SELFGEN_DEF_ANT\t%d\n",
399604eeaddSBruno Randolf 		(v & AR5K_STA_ID1_SELFGEN_DEF_ANT) != 0);
400604eeaddSBruno Randolf 
401e0d687bdSPavel Roskin 	v = ath5k_hw_reg_read(ah, AR5K_PHY_AGCCTL);
402dfb252c7STakashi Iwai 	len += scnprintf(buf + len, sizeof(buf) - len,
403604eeaddSBruno Randolf 		"\nAR5K_PHY_AGCCTL_OFDM_DIV_DIS\t%d\n",
404604eeaddSBruno Randolf 		(v & AR5K_PHY_AGCCTL_OFDM_DIV_DIS) != 0);
405604eeaddSBruno Randolf 
406e0d687bdSPavel Roskin 	v = ath5k_hw_reg_read(ah, AR5K_PHY_RESTART);
407dfb252c7STakashi Iwai 	len += scnprintf(buf + len, sizeof(buf) - len,
408604eeaddSBruno Randolf 		"AR5K_PHY_RESTART_DIV_GC\t\t%x\n",
409604eeaddSBruno Randolf 		(v & AR5K_PHY_RESTART_DIV_GC) >> AR5K_PHY_RESTART_DIV_GC_S);
410604eeaddSBruno Randolf 
411e0d687bdSPavel Roskin 	v = ath5k_hw_reg_read(ah, AR5K_PHY_FAST_ANT_DIV);
412dfb252c7STakashi Iwai 	len += scnprintf(buf + len, sizeof(buf) - len,
413604eeaddSBruno Randolf 		"AR5K_PHY_FAST_ANT_DIV_EN\t%d\n",
414604eeaddSBruno Randolf 		(v & AR5K_PHY_FAST_ANT_DIV_EN) != 0);
415604eeaddSBruno Randolf 
416e0d687bdSPavel Roskin 	v = ath5k_hw_reg_read(ah, AR5K_PHY_ANT_SWITCH_TABLE_0);
417dfb252c7STakashi Iwai 	len += scnprintf(buf + len, sizeof(buf) - len,
4180ca74027SBruno Randolf 			"\nAR5K_PHY_ANT_SWITCH_TABLE_0\t0x%08x\n", v);
419e0d687bdSPavel Roskin 	v = ath5k_hw_reg_read(ah, AR5K_PHY_ANT_SWITCH_TABLE_1);
420dfb252c7STakashi Iwai 	len += scnprintf(buf + len, sizeof(buf) - len,
4210ca74027SBruno Randolf 			"AR5K_PHY_ANT_SWITCH_TABLE_1\t0x%08x\n", v);
4220ca74027SBruno Randolf 
4232189d13fSDan Carpenter 	if (len > sizeof(buf))
4242189d13fSDan Carpenter 		len = sizeof(buf);
4252189d13fSDan Carpenter 
426604eeaddSBruno Randolf 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
427604eeaddSBruno Randolf }
428604eeaddSBruno Randolf 
write_file_antenna(struct file * file,const char __user * userbuf,size_t count,loff_t * ppos)429604eeaddSBruno Randolf static ssize_t write_file_antenna(struct file *file,
430604eeaddSBruno Randolf 				 const char __user *userbuf,
431604eeaddSBruno Randolf 				 size_t count, loff_t *ppos)
432604eeaddSBruno Randolf {
433e0d687bdSPavel Roskin 	struct ath5k_hw *ah = file->private_data;
434604eeaddSBruno Randolf 	unsigned int i;
435604eeaddSBruno Randolf 	char buf[20];
436604eeaddSBruno Randolf 
4378aada63cSDjalal Harouni 	count = min_t(size_t, count, sizeof(buf) - 1);
4388aada63cSDjalal Harouni 	if (copy_from_user(buf, userbuf, count))
439604eeaddSBruno Randolf 		return -EFAULT;
440604eeaddSBruno Randolf 
4418aada63cSDjalal Harouni 	buf[count] = '\0';
442604eeaddSBruno Randolf 	if (strncmp(buf, "diversity", 9) == 0) {
443e0d687bdSPavel Roskin 		ath5k_hw_set_antenna_mode(ah, AR5K_ANTMODE_DEFAULT);
444516304b0SJoe Perches 		pr_info("debug: enable diversity\n");
445604eeaddSBruno Randolf 	} else if (strncmp(buf, "fixed-a", 7) == 0) {
446e0d687bdSPavel Roskin 		ath5k_hw_set_antenna_mode(ah, AR5K_ANTMODE_FIXED_A);
447516304b0SJoe Perches 		pr_info("debug: fixed antenna A\n");
448604eeaddSBruno Randolf 	} else if (strncmp(buf, "fixed-b", 7) == 0) {
449e0d687bdSPavel Roskin 		ath5k_hw_set_antenna_mode(ah, AR5K_ANTMODE_FIXED_B);
450516304b0SJoe Perches 		pr_info("debug: fixed antenna B\n");
451604eeaddSBruno Randolf 	} else if (strncmp(buf, "clear", 5) == 0) {
452e0d687bdSPavel Roskin 		for (i = 0; i < ARRAY_SIZE(ah->stats.antenna_rx); i++) {
453e0d687bdSPavel Roskin 			ah->stats.antenna_rx[i] = 0;
454e0d687bdSPavel Roskin 			ah->stats.antenna_tx[i] = 0;
455604eeaddSBruno Randolf 		}
456516304b0SJoe Perches 		pr_info("debug: cleared antenna stats\n");
457604eeaddSBruno Randolf 	}
458604eeaddSBruno Randolf 	return count;
459604eeaddSBruno Randolf }
460604eeaddSBruno Randolf 
461604eeaddSBruno Randolf static const struct file_operations fops_antenna = {
462604eeaddSBruno Randolf 	.read = read_file_antenna,
463604eeaddSBruno Randolf 	.write = write_file_antenna,
464234e3405SStephen Boyd 	.open = simple_open,
465604eeaddSBruno Randolf 	.owner = THIS_MODULE,
4666038f373SArnd Bergmann 	.llseek = default_llseek,
467604eeaddSBruno Randolf };
468604eeaddSBruno Randolf 
46987fd2e6cSBen Greear /* debugfs: misc */
47087fd2e6cSBen Greear 
read_file_misc(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)47187fd2e6cSBen Greear static ssize_t read_file_misc(struct file *file, char __user *user_buf,
47287fd2e6cSBen Greear 				   size_t count, loff_t *ppos)
47387fd2e6cSBen Greear {
474e0d687bdSPavel Roskin 	struct ath5k_hw *ah = file->private_data;
47587fd2e6cSBen Greear 	char buf[700];
47687fd2e6cSBen Greear 	unsigned int len = 0;
477e0d687bdSPavel Roskin 	u32 filt = ath5k_hw_get_rx_filter(ah);
47887fd2e6cSBen Greear 
479dfb252c7STakashi Iwai 	len += scnprintf(buf + len, sizeof(buf) - len, "bssid-mask: %pM\n",
480e0d687bdSPavel Roskin 			ah->bssidmask);
481dfb252c7STakashi Iwai 	len += scnprintf(buf + len, sizeof(buf) - len, "filter-flags: 0x%x ",
48287fd2e6cSBen Greear 			filt);
48387fd2e6cSBen Greear 	if (filt & AR5K_RX_FILTER_UCAST)
484dfb252c7STakashi Iwai 		len += scnprintf(buf + len, sizeof(buf) - len, " UCAST");
48587fd2e6cSBen Greear 	if (filt & AR5K_RX_FILTER_MCAST)
486dfb252c7STakashi Iwai 		len += scnprintf(buf + len, sizeof(buf) - len, " MCAST");
48787fd2e6cSBen Greear 	if (filt & AR5K_RX_FILTER_BCAST)
488dfb252c7STakashi Iwai 		len += scnprintf(buf + len, sizeof(buf) - len, " BCAST");
48987fd2e6cSBen Greear 	if (filt & AR5K_RX_FILTER_CONTROL)
490dfb252c7STakashi Iwai 		len += scnprintf(buf + len, sizeof(buf) - len, " CONTROL");
49187fd2e6cSBen Greear 	if (filt & AR5K_RX_FILTER_BEACON)
492dfb252c7STakashi Iwai 		len += scnprintf(buf + len, sizeof(buf) - len, " BEACON");
49387fd2e6cSBen Greear 	if (filt & AR5K_RX_FILTER_PROM)
494dfb252c7STakashi Iwai 		len += scnprintf(buf + len, sizeof(buf) - len, " PROM");
49587fd2e6cSBen Greear 	if (filt & AR5K_RX_FILTER_XRPOLL)
496dfb252c7STakashi Iwai 		len += scnprintf(buf + len, sizeof(buf) - len, " XRPOLL");
49787fd2e6cSBen Greear 	if (filt & AR5K_RX_FILTER_PROBEREQ)
498dfb252c7STakashi Iwai 		len += scnprintf(buf + len, sizeof(buf) - len, " PROBEREQ");
49987fd2e6cSBen Greear 	if (filt & AR5K_RX_FILTER_PHYERR_5212)
500dfb252c7STakashi Iwai 		len += scnprintf(buf + len, sizeof(buf) - len, " PHYERR-5212");
50187fd2e6cSBen Greear 	if (filt & AR5K_RX_FILTER_RADARERR_5212)
502dfb252c7STakashi Iwai 		len += scnprintf(buf + len, sizeof(buf) - len, " RADARERR-5212");
50387fd2e6cSBen Greear 	if (filt & AR5K_RX_FILTER_PHYERR_5211)
50487fd2e6cSBen Greear 		snprintf(buf + len, sizeof(buf) - len, " PHYERR-5211");
50587fd2e6cSBen Greear 	if (filt & AR5K_RX_FILTER_RADARERR_5211)
506dfb252c7STakashi Iwai 		len += scnprintf(buf + len, sizeof(buf) - len, " RADARERR-5211");
50787fd2e6cSBen Greear 
508dfb252c7STakashi Iwai 	len += scnprintf(buf + len, sizeof(buf) - len, "\nopmode: %s (%d)\n",
509e0d687bdSPavel Roskin 			ath_opmode_to_string(ah->opmode), ah->opmode);
51092c68a66SBen Greear 
51187fd2e6cSBen Greear 	if (len > sizeof(buf))
51287fd2e6cSBen Greear 		len = sizeof(buf);
51387fd2e6cSBen Greear 
51487fd2e6cSBen Greear 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
51587fd2e6cSBen Greear }
51687fd2e6cSBen Greear 
51787fd2e6cSBen Greear static const struct file_operations fops_misc = {
51887fd2e6cSBen Greear 	.read = read_file_misc,
519234e3405SStephen Boyd 	.open = simple_open,
52087fd2e6cSBen Greear 	.owner = THIS_MODULE,
52187fd2e6cSBen Greear };
52287fd2e6cSBen Greear 
523604eeaddSBruno Randolf 
5247644395fSBruno Randolf /* debugfs: frameerrors */
5257644395fSBruno Randolf 
read_file_frameerrors(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)5267644395fSBruno Randolf static ssize_t read_file_frameerrors(struct file *file, char __user *user_buf,
5277644395fSBruno Randolf 				   size_t count, loff_t *ppos)
5287644395fSBruno Randolf {
529e0d687bdSPavel Roskin 	struct ath5k_hw *ah = file->private_data;
530e0d687bdSPavel Roskin 	struct ath5k_statistics *st = &ah->stats;
5317644395fSBruno Randolf 	char buf[700];
5327644395fSBruno Randolf 	unsigned int len = 0;
533da35111aSBruno Randolf 	int i;
5347644395fSBruno Randolf 
535dfb252c7STakashi Iwai 	len += scnprintf(buf + len, sizeof(buf) - len,
5367644395fSBruno Randolf 			"RX\n---------------------\n");
537dfb252c7STakashi Iwai 	len += scnprintf(buf + len, sizeof(buf) - len, "CRC\t%u\t(%u%%)\n",
5387644395fSBruno Randolf 			st->rxerr_crc,
5397644395fSBruno Randolf 			st->rx_all_count > 0 ?
5407644395fSBruno Randolf 				st->rxerr_crc * 100 / st->rx_all_count : 0);
541dfb252c7STakashi Iwai 	len += scnprintf(buf + len, sizeof(buf) - len, "PHY\t%u\t(%u%%)\n",
5427644395fSBruno Randolf 			st->rxerr_phy,
5437644395fSBruno Randolf 			st->rx_all_count > 0 ?
5447644395fSBruno Randolf 				st->rxerr_phy * 100 / st->rx_all_count : 0);
545da35111aSBruno Randolf 	for (i = 0; i < 32; i++) {
546da35111aSBruno Randolf 		if (st->rxerr_phy_code[i])
547dfb252c7STakashi Iwai 			len += scnprintf(buf + len, sizeof(buf) - len,
5485d882c97SBen Greear 				" phy_err[%u]\t%u\n",
549da35111aSBruno Randolf 				i, st->rxerr_phy_code[i]);
550da35111aSBruno Randolf 	}
551da35111aSBruno Randolf 
552dfb252c7STakashi Iwai 	len += scnprintf(buf + len, sizeof(buf) - len, "FIFO\t%u\t(%u%%)\n",
5537644395fSBruno Randolf 			st->rxerr_fifo,
5547644395fSBruno Randolf 			st->rx_all_count > 0 ?
5557644395fSBruno Randolf 				st->rxerr_fifo * 100 / st->rx_all_count : 0);
556dfb252c7STakashi Iwai 	len += scnprintf(buf + len, sizeof(buf) - len, "decrypt\t%u\t(%u%%)\n",
5577644395fSBruno Randolf 			st->rxerr_decrypt,
5587644395fSBruno Randolf 			st->rx_all_count > 0 ?
5597644395fSBruno Randolf 				st->rxerr_decrypt * 100 / st->rx_all_count : 0);
560dfb252c7STakashi Iwai 	len += scnprintf(buf + len, sizeof(buf) - len, "MIC\t%u\t(%u%%)\n",
5617644395fSBruno Randolf 			st->rxerr_mic,
5627644395fSBruno Randolf 			st->rx_all_count > 0 ?
5637644395fSBruno Randolf 				st->rxerr_mic * 100 / st->rx_all_count : 0);
564dfb252c7STakashi Iwai 	len += scnprintf(buf + len, sizeof(buf) - len, "process\t%u\t(%u%%)\n",
5657644395fSBruno Randolf 			st->rxerr_proc,
5667644395fSBruno Randolf 			st->rx_all_count > 0 ?
5677644395fSBruno Randolf 				st->rxerr_proc * 100 / st->rx_all_count : 0);
568dfb252c7STakashi Iwai 	len += scnprintf(buf + len, sizeof(buf) - len, "jumbo\t%u\t(%u%%)\n",
5697644395fSBruno Randolf 			st->rxerr_jumbo,
5707644395fSBruno Randolf 			st->rx_all_count > 0 ?
5717644395fSBruno Randolf 				st->rxerr_jumbo * 100 / st->rx_all_count : 0);
572dfb252c7STakashi Iwai 	len += scnprintf(buf + len, sizeof(buf) - len, "[RX all\t%u]\n",
5737644395fSBruno Randolf 			st->rx_all_count);
574dfb252c7STakashi Iwai 	len += scnprintf(buf + len, sizeof(buf) - len, "RX-all-bytes\t%u\n",
575b72acddbSBen Greear 			st->rx_bytes_count);
5767644395fSBruno Randolf 
577dfb252c7STakashi Iwai 	len += scnprintf(buf + len, sizeof(buf) - len,
5787644395fSBruno Randolf 			"\nTX\n---------------------\n");
579dfb252c7STakashi Iwai 	len += scnprintf(buf + len, sizeof(buf) - len, "retry\t%u\t(%u%%)\n",
5807644395fSBruno Randolf 			st->txerr_retry,
5817644395fSBruno Randolf 			st->tx_all_count > 0 ?
5827644395fSBruno Randolf 				st->txerr_retry * 100 / st->tx_all_count : 0);
583dfb252c7STakashi Iwai 	len += scnprintf(buf + len, sizeof(buf) - len, "FIFO\t%u\t(%u%%)\n",
5847644395fSBruno Randolf 			st->txerr_fifo,
5857644395fSBruno Randolf 			st->tx_all_count > 0 ?
5867644395fSBruno Randolf 				st->txerr_fifo * 100 / st->tx_all_count : 0);
587dfb252c7STakashi Iwai 	len += scnprintf(buf + len, sizeof(buf) - len, "filter\t%u\t(%u%%)\n",
5887644395fSBruno Randolf 			st->txerr_filt,
5897644395fSBruno Randolf 			st->tx_all_count > 0 ?
5907644395fSBruno Randolf 				st->txerr_filt * 100 / st->tx_all_count : 0);
591dfb252c7STakashi Iwai 	len += scnprintf(buf + len, sizeof(buf) - len, "[TX all\t%u]\n",
5927644395fSBruno Randolf 			st->tx_all_count);
593dfb252c7STakashi Iwai 	len += scnprintf(buf + len, sizeof(buf) - len, "TX-all-bytes\t%u\n",
594b72acddbSBen Greear 			st->tx_bytes_count);
5957644395fSBruno Randolf 
5962189d13fSDan Carpenter 	if (len > sizeof(buf))
5972189d13fSDan Carpenter 		len = sizeof(buf);
5982189d13fSDan Carpenter 
5997644395fSBruno Randolf 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
6007644395fSBruno Randolf }
6017644395fSBruno Randolf 
write_file_frameerrors(struct file * file,const char __user * userbuf,size_t count,loff_t * ppos)6027644395fSBruno Randolf static ssize_t write_file_frameerrors(struct file *file,
6037644395fSBruno Randolf 				 const char __user *userbuf,
6047644395fSBruno Randolf 				 size_t count, loff_t *ppos)
6057644395fSBruno Randolf {
606e0d687bdSPavel Roskin 	struct ath5k_hw *ah = file->private_data;
607e0d687bdSPavel Roskin 	struct ath5k_statistics *st = &ah->stats;
6087644395fSBruno Randolf 	char buf[20];
6097644395fSBruno Randolf 
6108aada63cSDjalal Harouni 	count = min_t(size_t, count, sizeof(buf) - 1);
6118aada63cSDjalal Harouni 	if (copy_from_user(buf, userbuf, count))
6127644395fSBruno Randolf 		return -EFAULT;
6137644395fSBruno Randolf 
6148aada63cSDjalal Harouni 	buf[count] = '\0';
6157644395fSBruno Randolf 	if (strncmp(buf, "clear", 5) == 0) {
6167644395fSBruno Randolf 		st->rxerr_crc = 0;
6177644395fSBruno Randolf 		st->rxerr_phy = 0;
6187644395fSBruno Randolf 		st->rxerr_fifo = 0;
6197644395fSBruno Randolf 		st->rxerr_decrypt = 0;
6207644395fSBruno Randolf 		st->rxerr_mic = 0;
6217644395fSBruno Randolf 		st->rxerr_proc = 0;
6227644395fSBruno Randolf 		st->rxerr_jumbo = 0;
6237644395fSBruno Randolf 		st->rx_all_count = 0;
6247644395fSBruno Randolf 		st->txerr_retry = 0;
6257644395fSBruno Randolf 		st->txerr_fifo = 0;
6267644395fSBruno Randolf 		st->txerr_filt = 0;
6277644395fSBruno Randolf 		st->tx_all_count = 0;
628516304b0SJoe Perches 		pr_info("debug: cleared frameerrors stats\n");
6297644395fSBruno Randolf 	}
6307644395fSBruno Randolf 	return count;
6317644395fSBruno Randolf }
6327644395fSBruno Randolf 
6337644395fSBruno Randolf static const struct file_operations fops_frameerrors = {
6347644395fSBruno Randolf 	.read = read_file_frameerrors,
6357644395fSBruno Randolf 	.write = write_file_frameerrors,
636234e3405SStephen Boyd 	.open = simple_open,
6377644395fSBruno Randolf 	.owner = THIS_MODULE,
6386038f373SArnd Bergmann 	.llseek = default_llseek,
6397644395fSBruno Randolf };
6407644395fSBruno Randolf 
6417644395fSBruno Randolf 
6422111ac0dSBruno Randolf /* debugfs: ani */
6432111ac0dSBruno Randolf 
read_file_ani(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)6442111ac0dSBruno Randolf static ssize_t read_file_ani(struct file *file, char __user *user_buf,
6452111ac0dSBruno Randolf 				   size_t count, loff_t *ppos)
6462111ac0dSBruno Randolf {
647e0d687bdSPavel Roskin 	struct ath5k_hw *ah = file->private_data;
648e0d687bdSPavel Roskin 	struct ath5k_statistics *st = &ah->stats;
649e0d687bdSPavel Roskin 	struct ath5k_ani_state *as = &ah->ani_state;
6502111ac0dSBruno Randolf 
6512111ac0dSBruno Randolf 	char buf[700];
6522111ac0dSBruno Randolf 	unsigned int len = 0;
6532111ac0dSBruno Randolf 
654dfb252c7STakashi Iwai 	len += scnprintf(buf + len, sizeof(buf) - len,
6552111ac0dSBruno Randolf 			"HW has PHY error counters:\t%s\n",
656e0d687bdSPavel Roskin 			ah->ah_capabilities.cap_has_phyerr_counters ?
6572111ac0dSBruno Randolf 			"yes" : "no");
658dfb252c7STakashi Iwai 	len += scnprintf(buf + len, sizeof(buf) - len,
6592111ac0dSBruno Randolf 			"HW max spur immunity level:\t%d\n",
6602111ac0dSBruno Randolf 			as->max_spur_level);
661dfb252c7STakashi Iwai 	len += scnprintf(buf + len, sizeof(buf) - len,
6622111ac0dSBruno Randolf 		"\nANI state\n--------------------------------------------\n");
663dfb252c7STakashi Iwai 	len += scnprintf(buf + len, sizeof(buf) - len, "operating mode:\t\t\t");
6642111ac0dSBruno Randolf 	switch (as->ani_mode) {
6652111ac0dSBruno Randolf 	case ATH5K_ANI_MODE_OFF:
666dfb252c7STakashi Iwai 		len += scnprintf(buf + len, sizeof(buf) - len, "OFF\n");
6672111ac0dSBruno Randolf 		break;
6682111ac0dSBruno Randolf 	case ATH5K_ANI_MODE_MANUAL_LOW:
669dfb252c7STakashi Iwai 		len += scnprintf(buf + len, sizeof(buf) - len,
6702111ac0dSBruno Randolf 			"MANUAL LOW\n");
6712111ac0dSBruno Randolf 		break;
6722111ac0dSBruno Randolf 	case ATH5K_ANI_MODE_MANUAL_HIGH:
673dfb252c7STakashi Iwai 		len += scnprintf(buf + len, sizeof(buf) - len,
6742111ac0dSBruno Randolf 			"MANUAL HIGH\n");
6752111ac0dSBruno Randolf 		break;
6762111ac0dSBruno Randolf 	case ATH5K_ANI_MODE_AUTO:
677dfb252c7STakashi Iwai 		len += scnprintf(buf + len, sizeof(buf) - len, "AUTO\n");
6782111ac0dSBruno Randolf 		break;
6792111ac0dSBruno Randolf 	default:
680dfb252c7STakashi Iwai 		len += scnprintf(buf + len, sizeof(buf) - len,
6812111ac0dSBruno Randolf 			"??? (not good)\n");
6822111ac0dSBruno Randolf 		break;
6832111ac0dSBruno Randolf 	}
684dfb252c7STakashi Iwai 	len += scnprintf(buf + len, sizeof(buf) - len,
6852111ac0dSBruno Randolf 			"noise immunity level:\t\t%d\n",
6862111ac0dSBruno Randolf 			as->noise_imm_level);
687dfb252c7STakashi Iwai 	len += scnprintf(buf + len, sizeof(buf) - len,
6882111ac0dSBruno Randolf 			"spur immunity level:\t\t%d\n",
6892111ac0dSBruno Randolf 			as->spur_level);
690dfb252c7STakashi Iwai 	len += scnprintf(buf + len, sizeof(buf) - len,
691e4bbf2f5SPavel Roskin 			"firstep level:\t\t\t%d\n",
6922111ac0dSBruno Randolf 			as->firstep_level);
693dfb252c7STakashi Iwai 	len += scnprintf(buf + len, sizeof(buf) - len,
6942111ac0dSBruno Randolf 			"OFDM weak signal detection:\t%s\n",
6952111ac0dSBruno Randolf 			as->ofdm_weak_sig ? "on" : "off");
696dfb252c7STakashi Iwai 	len += scnprintf(buf + len, sizeof(buf) - len,
6972111ac0dSBruno Randolf 			"CCK weak signal detection:\t%s\n",
6982111ac0dSBruno Randolf 			as->cck_weak_sig ? "on" : "off");
6992111ac0dSBruno Randolf 
700dfb252c7STakashi Iwai 	len += scnprintf(buf + len, sizeof(buf) - len,
7012111ac0dSBruno Randolf 			"\nMIB INTERRUPTS:\t\t%u\n",
7022111ac0dSBruno Randolf 			st->mib_intr);
703dfb252c7STakashi Iwai 	len += scnprintf(buf + len, sizeof(buf) - len,
7042111ac0dSBruno Randolf 			"beacon RSSI average:\t%d\n",
70546f26ddfSJohannes Berg 			(int)ewma_beacon_rssi_read(&ah->ah_beacon_rssi_avg));
7067109ca5cSFelix Fietkau 
7077109ca5cSFelix Fietkau #define CC_PRINT(_struct, _field) \
7087109ca5cSFelix Fietkau 	_struct._field, \
7097109ca5cSFelix Fietkau 	_struct.cycles > 0 ? \
7107109ca5cSFelix Fietkau 	_struct._field * 100 / _struct.cycles : 0
7117109ca5cSFelix Fietkau 
712dfb252c7STakashi Iwai 	len += scnprintf(buf + len, sizeof(buf) - len,
713e4bbf2f5SPavel Roskin 			"profcnt tx\t\t%u\t(%d%%)\n",
7147109ca5cSFelix Fietkau 			CC_PRINT(as->last_cc, tx_frame));
715dfb252c7STakashi Iwai 	len += scnprintf(buf + len, sizeof(buf) - len,
716e4bbf2f5SPavel Roskin 			"profcnt rx\t\t%u\t(%d%%)\n",
7177109ca5cSFelix Fietkau 			CC_PRINT(as->last_cc, rx_frame));
718dfb252c7STakashi Iwai 	len += scnprintf(buf + len, sizeof(buf) - len,
719e4bbf2f5SPavel Roskin 			"profcnt busy\t\t%u\t(%d%%)\n",
7207109ca5cSFelix Fietkau 			CC_PRINT(as->last_cc, rx_busy));
7217109ca5cSFelix Fietkau #undef CC_PRINT
722dfb252c7STakashi Iwai 	len += scnprintf(buf + len, sizeof(buf) - len, "profcnt cycles\t\t%u\n",
7237109ca5cSFelix Fietkau 			as->last_cc.cycles);
724dfb252c7STakashi Iwai 	len += scnprintf(buf + len, sizeof(buf) - len,
7252111ac0dSBruno Randolf 			"listen time\t\t%d\tlast: %d\n",
7262111ac0dSBruno Randolf 			as->listen_time, as->last_listen);
727dfb252c7STakashi Iwai 	len += scnprintf(buf + len, sizeof(buf) - len,
7282111ac0dSBruno Randolf 			"OFDM errors\t\t%u\tlast: %u\tsum: %u\n",
7292111ac0dSBruno Randolf 			as->ofdm_errors, as->last_ofdm_errors,
7302111ac0dSBruno Randolf 			as->sum_ofdm_errors);
731dfb252c7STakashi Iwai 	len += scnprintf(buf + len, sizeof(buf) - len,
7322111ac0dSBruno Randolf 			"CCK errors\t\t%u\tlast: %u\tsum: %u\n",
7332111ac0dSBruno Randolf 			as->cck_errors, as->last_cck_errors,
7342111ac0dSBruno Randolf 			as->sum_cck_errors);
735dfb252c7STakashi Iwai 	len += scnprintf(buf + len, sizeof(buf) - len,
7362111ac0dSBruno Randolf 			"AR5K_PHYERR_CNT1\t%x\t(=%d)\n",
737e0d687bdSPavel Roskin 			ath5k_hw_reg_read(ah, AR5K_PHYERR_CNT1),
7382111ac0dSBruno Randolf 			ATH5K_ANI_OFDM_TRIG_HIGH - (ATH5K_PHYERR_CNT_MAX -
739e0d687bdSPavel Roskin 			ath5k_hw_reg_read(ah, AR5K_PHYERR_CNT1)));
740dfb252c7STakashi Iwai 	len += scnprintf(buf + len, sizeof(buf) - len,
7412111ac0dSBruno Randolf 			"AR5K_PHYERR_CNT2\t%x\t(=%d)\n",
742e0d687bdSPavel Roskin 			ath5k_hw_reg_read(ah, AR5K_PHYERR_CNT2),
7432111ac0dSBruno Randolf 			ATH5K_ANI_CCK_TRIG_HIGH - (ATH5K_PHYERR_CNT_MAX -
744e0d687bdSPavel Roskin 			ath5k_hw_reg_read(ah, AR5K_PHYERR_CNT2)));
7452111ac0dSBruno Randolf 
7462189d13fSDan Carpenter 	if (len > sizeof(buf))
7472189d13fSDan Carpenter 		len = sizeof(buf);
7482189d13fSDan Carpenter 
7492111ac0dSBruno Randolf 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
7502111ac0dSBruno Randolf }
7512111ac0dSBruno Randolf 
write_file_ani(struct file * file,const char __user * userbuf,size_t count,loff_t * ppos)7522111ac0dSBruno Randolf static ssize_t write_file_ani(struct file *file,
7532111ac0dSBruno Randolf 				 const char __user *userbuf,
7542111ac0dSBruno Randolf 				 size_t count, loff_t *ppos)
7552111ac0dSBruno Randolf {
756e0d687bdSPavel Roskin 	struct ath5k_hw *ah = file->private_data;
7572111ac0dSBruno Randolf 	char buf[20];
7582111ac0dSBruno Randolf 
7598aada63cSDjalal Harouni 	count = min_t(size_t, count, sizeof(buf) - 1);
7608aada63cSDjalal Harouni 	if (copy_from_user(buf, userbuf, count))
7612111ac0dSBruno Randolf 		return -EFAULT;
7622111ac0dSBruno Randolf 
7638aada63cSDjalal Harouni 	buf[count] = '\0';
7642111ac0dSBruno Randolf 	if (strncmp(buf, "sens-low", 8) == 0) {
765e0d687bdSPavel Roskin 		ath5k_ani_init(ah, ATH5K_ANI_MODE_MANUAL_HIGH);
7662111ac0dSBruno Randolf 	} else if (strncmp(buf, "sens-high", 9) == 0) {
767e0d687bdSPavel Roskin 		ath5k_ani_init(ah, ATH5K_ANI_MODE_MANUAL_LOW);
7682111ac0dSBruno Randolf 	} else if (strncmp(buf, "ani-off", 7) == 0) {
769e0d687bdSPavel Roskin 		ath5k_ani_init(ah, ATH5K_ANI_MODE_OFF);
7702111ac0dSBruno Randolf 	} else if (strncmp(buf, "ani-on", 6) == 0) {
771e0d687bdSPavel Roskin 		ath5k_ani_init(ah, ATH5K_ANI_MODE_AUTO);
7722111ac0dSBruno Randolf 	} else if (strncmp(buf, "noise-low", 9) == 0) {
773e0d687bdSPavel Roskin 		ath5k_ani_set_noise_immunity_level(ah, 0);
7742111ac0dSBruno Randolf 	} else if (strncmp(buf, "noise-high", 10) == 0) {
775e0d687bdSPavel Roskin 		ath5k_ani_set_noise_immunity_level(ah,
7762111ac0dSBruno Randolf 						   ATH5K_ANI_MAX_NOISE_IMM_LVL);
7772111ac0dSBruno Randolf 	} else if (strncmp(buf, "spur-low", 8) == 0) {
778e0d687bdSPavel Roskin 		ath5k_ani_set_spur_immunity_level(ah, 0);
7792111ac0dSBruno Randolf 	} else if (strncmp(buf, "spur-high", 9) == 0) {
780e0d687bdSPavel Roskin 		ath5k_ani_set_spur_immunity_level(ah,
781e0d687bdSPavel Roskin 						  ah->ani_state.max_spur_level);
7822111ac0dSBruno Randolf 	} else if (strncmp(buf, "fir-low", 7) == 0) {
783e0d687bdSPavel Roskin 		ath5k_ani_set_firstep_level(ah, 0);
7842111ac0dSBruno Randolf 	} else if (strncmp(buf, "fir-high", 8) == 0) {
785e0d687bdSPavel Roskin 		ath5k_ani_set_firstep_level(ah, ATH5K_ANI_MAX_FIRSTEP_LVL);
7862111ac0dSBruno Randolf 	} else if (strncmp(buf, "ofdm-off", 8) == 0) {
787e0d687bdSPavel Roskin 		ath5k_ani_set_ofdm_weak_signal_detection(ah, false);
7882111ac0dSBruno Randolf 	} else if (strncmp(buf, "ofdm-on", 7) == 0) {
789e0d687bdSPavel Roskin 		ath5k_ani_set_ofdm_weak_signal_detection(ah, true);
7902111ac0dSBruno Randolf 	} else if (strncmp(buf, "cck-off", 7) == 0) {
791e0d687bdSPavel Roskin 		ath5k_ani_set_cck_weak_signal_detection(ah, false);
7922111ac0dSBruno Randolf 	} else if (strncmp(buf, "cck-on", 6) == 0) {
793e0d687bdSPavel Roskin 		ath5k_ani_set_cck_weak_signal_detection(ah, true);
7942111ac0dSBruno Randolf 	}
7952111ac0dSBruno Randolf 	return count;
7962111ac0dSBruno Randolf }
7972111ac0dSBruno Randolf 
7982111ac0dSBruno Randolf static const struct file_operations fops_ani = {
7992111ac0dSBruno Randolf 	.read = read_file_ani,
8002111ac0dSBruno Randolf 	.write = write_file_ani,
801234e3405SStephen Boyd 	.open = simple_open,
8022111ac0dSBruno Randolf 	.owner = THIS_MODULE,
8036038f373SArnd Bergmann 	.llseek = default_llseek,
8042111ac0dSBruno Randolf };
8052111ac0dSBruno Randolf 
8062111ac0dSBruno Randolf 
8073cfd43f4SBruno Randolf /* debugfs: queues etc */
8083cfd43f4SBruno Randolf 
read_file_queue(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)8093cfd43f4SBruno Randolf static ssize_t read_file_queue(struct file *file, char __user *user_buf,
8103cfd43f4SBruno Randolf 				   size_t count, loff_t *ppos)
8113cfd43f4SBruno Randolf {
812e0d687bdSPavel Roskin 	struct ath5k_hw *ah = file->private_data;
8133cfd43f4SBruno Randolf 	char buf[700];
8143cfd43f4SBruno Randolf 	unsigned int len = 0;
8153cfd43f4SBruno Randolf 
8163cfd43f4SBruno Randolf 	struct ath5k_txq *txq;
8173cfd43f4SBruno Randolf 	struct ath5k_buf *bf, *bf0;
818cfddc11cSBruno Randolf 	int i, n;
8193cfd43f4SBruno Randolf 
820dfb252c7STakashi Iwai 	len += scnprintf(buf + len, sizeof(buf) - len,
821e0d687bdSPavel Roskin 			"available txbuffers: %d\n", ah->txbuf_len);
8223cfd43f4SBruno Randolf 
823e0d687bdSPavel Roskin 	for (i = 0; i < ARRAY_SIZE(ah->txqs); i++) {
824e0d687bdSPavel Roskin 		txq = &ah->txqs[i];
8253cfd43f4SBruno Randolf 
826dfb252c7STakashi Iwai 		len += scnprintf(buf + len, sizeof(buf) - len,
8273cfd43f4SBruno Randolf 			"%02d: %ssetup\n", i, txq->setup ? "" : "not ");
8283cfd43f4SBruno Randolf 
8293cfd43f4SBruno Randolf 		if (!txq->setup)
8303cfd43f4SBruno Randolf 			continue;
8313cfd43f4SBruno Randolf 
832cfddc11cSBruno Randolf 		n = 0;
833cfddc11cSBruno Randolf 		spin_lock_bh(&txq->lock);
8343cfd43f4SBruno Randolf 		list_for_each_entry_safe(bf, bf0, &txq->q, list)
8353cfd43f4SBruno Randolf 			n++;
836cfddc11cSBruno Randolf 		spin_unlock_bh(&txq->lock);
837cfddc11cSBruno Randolf 
838dfb252c7STakashi Iwai 		len += scnprintf(buf + len, sizeof(buf) - len,
839cfddc11cSBruno Randolf 				"  len: %d bufs: %d\n", txq->txq_len, n);
840dfb252c7STakashi Iwai 		len += scnprintf(buf + len, sizeof(buf) - len,
841923e5b3dSBruno Randolf 				"  stuck: %d\n", txq->txq_stuck);
8423cfd43f4SBruno Randolf 	}
8433cfd43f4SBruno Randolf 
8442189d13fSDan Carpenter 	if (len > sizeof(buf))
8452189d13fSDan Carpenter 		len = sizeof(buf);
8462189d13fSDan Carpenter 
8473cfd43f4SBruno Randolf 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
8483cfd43f4SBruno Randolf }
8493cfd43f4SBruno Randolf 
write_file_queue(struct file * file,const char __user * userbuf,size_t count,loff_t * ppos)8503cfd43f4SBruno Randolf static ssize_t write_file_queue(struct file *file,
8513cfd43f4SBruno Randolf 				 const char __user *userbuf,
8523cfd43f4SBruno Randolf 				 size_t count, loff_t *ppos)
8533cfd43f4SBruno Randolf {
854e0d687bdSPavel Roskin 	struct ath5k_hw *ah = file->private_data;
8553cfd43f4SBruno Randolf 	char buf[20];
8563cfd43f4SBruno Randolf 
8578aada63cSDjalal Harouni 	count = min_t(size_t, count, sizeof(buf) - 1);
8588aada63cSDjalal Harouni 	if (copy_from_user(buf, userbuf, count))
8593cfd43f4SBruno Randolf 		return -EFAULT;
8603cfd43f4SBruno Randolf 
8618aada63cSDjalal Harouni 	buf[count] = '\0';
8623cfd43f4SBruno Randolf 	if (strncmp(buf, "start", 5) == 0)
863e0d687bdSPavel Roskin 		ieee80211_wake_queues(ah->hw);
8643cfd43f4SBruno Randolf 	else if (strncmp(buf, "stop", 4) == 0)
865e0d687bdSPavel Roskin 		ieee80211_stop_queues(ah->hw);
8663cfd43f4SBruno Randolf 
8673cfd43f4SBruno Randolf 	return count;
8683cfd43f4SBruno Randolf }
8693cfd43f4SBruno Randolf 
8703cfd43f4SBruno Randolf 
8713cfd43f4SBruno Randolf static const struct file_operations fops_queue = {
8723cfd43f4SBruno Randolf 	.read = read_file_queue,
8733cfd43f4SBruno Randolf 	.write = write_file_queue,
874234e3405SStephen Boyd 	.open = simple_open,
8753cfd43f4SBruno Randolf 	.owner = THIS_MODULE,
8766038f373SArnd Bergmann 	.llseek = default_llseek,
8773cfd43f4SBruno Randolf };
8783cfd43f4SBruno Randolf 
879db906eb2SJade Bilkey /* debugfs: eeprom */
880db906eb2SJade Bilkey 
881db906eb2SJade Bilkey struct eeprom_private {
882db906eb2SJade Bilkey 	u16 *buf;
883db906eb2SJade Bilkey 	int len;
884db906eb2SJade Bilkey };
885db906eb2SJade Bilkey 
open_file_eeprom(struct inode * inode,struct file * file)886db906eb2SJade Bilkey static int open_file_eeprom(struct inode *inode, struct file *file)
887db906eb2SJade Bilkey {
888db906eb2SJade Bilkey 	struct eeprom_private *ep;
889db906eb2SJade Bilkey 	struct ath5k_hw *ah = inode->i_private;
890db906eb2SJade Bilkey 	bool res;
891db906eb2SJade Bilkey 	int i, ret;
892af8a9a67SSergey Ryazanov 	u32 eesize;	/* NB: in 16-bit words */
893db906eb2SJade Bilkey 	u16 val, *buf;
894db906eb2SJade Bilkey 
895db906eb2SJade Bilkey 	/* Get eeprom size */
896db906eb2SJade Bilkey 
897db906eb2SJade Bilkey 	res = ath5k_hw_nvram_read(ah, AR5K_EEPROM_SIZE_UPPER, &val);
898db906eb2SJade Bilkey 	if (!res)
899db906eb2SJade Bilkey 		return -EACCES;
900db906eb2SJade Bilkey 
901db906eb2SJade Bilkey 	if (val == 0) {
902db906eb2SJade Bilkey 		eesize = AR5K_EEPROM_INFO_MAX + AR5K_EEPROM_INFO_BASE;
903db906eb2SJade Bilkey 	} else {
904db906eb2SJade Bilkey 		eesize = (val & AR5K_EEPROM_SIZE_UPPER_MASK) <<
905db906eb2SJade Bilkey 			AR5K_EEPROM_SIZE_ENDLOC_SHIFT;
906db906eb2SJade Bilkey 		ath5k_hw_nvram_read(ah, AR5K_EEPROM_SIZE_LOWER, &val);
907db906eb2SJade Bilkey 		eesize = eesize | val;
908db906eb2SJade Bilkey 	}
909db906eb2SJade Bilkey 
910db906eb2SJade Bilkey 	if (eesize > 4096)
911db906eb2SJade Bilkey 		return -EINVAL;
912db906eb2SJade Bilkey 
913db906eb2SJade Bilkey 	/* Create buffer and read in eeprom */
914db906eb2SJade Bilkey 
91542bc47b3SKees Cook 	buf = vmalloc(array_size(eesize, 2));
916db906eb2SJade Bilkey 	if (!buf) {
917db906eb2SJade Bilkey 		ret = -ENOMEM;
918db906eb2SJade Bilkey 		goto err;
919db906eb2SJade Bilkey 	}
920db906eb2SJade Bilkey 
921db906eb2SJade Bilkey 	for (i = 0; i < eesize; ++i) {
9228fed6823SColin Ian King 		if (!ath5k_hw_nvram_read(ah, i, &val)) {
9238fed6823SColin Ian King 			ret = -EIO;
9248fed6823SColin Ian King 			goto freebuf;
9258fed6823SColin Ian King 		}
926db906eb2SJade Bilkey 		buf[i] = val;
927db906eb2SJade Bilkey 	}
928db906eb2SJade Bilkey 
929db906eb2SJade Bilkey 	/* Create private struct and assign to file */
930db906eb2SJade Bilkey 
931db906eb2SJade Bilkey 	ep = kmalloc(sizeof(*ep), GFP_KERNEL);
932db906eb2SJade Bilkey 	if (!ep) {
933db906eb2SJade Bilkey 		ret = -ENOMEM;
934db906eb2SJade Bilkey 		goto freebuf;
935db906eb2SJade Bilkey 	}
936db906eb2SJade Bilkey 
937db906eb2SJade Bilkey 	ep->buf = buf;
938af8a9a67SSergey Ryazanov 	ep->len = eesize * 2;
939db906eb2SJade Bilkey 
940db906eb2SJade Bilkey 	file->private_data = (void *)ep;
941db906eb2SJade Bilkey 
942db906eb2SJade Bilkey 	return 0;
943db906eb2SJade Bilkey 
944db906eb2SJade Bilkey freebuf:
945db906eb2SJade Bilkey 	vfree(buf);
946db906eb2SJade Bilkey err:
947db906eb2SJade Bilkey 	return ret;
948db906eb2SJade Bilkey 
949db906eb2SJade Bilkey }
950db906eb2SJade Bilkey 
read_file_eeprom(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)951db906eb2SJade Bilkey static ssize_t read_file_eeprom(struct file *file, char __user *user_buf,
952db906eb2SJade Bilkey 				   size_t count, loff_t *ppos)
953db906eb2SJade Bilkey {
954db906eb2SJade Bilkey 	struct eeprom_private *ep = file->private_data;
955db906eb2SJade Bilkey 
956db906eb2SJade Bilkey 	return simple_read_from_buffer(user_buf, count, ppos, ep->buf, ep->len);
957db906eb2SJade Bilkey }
958db906eb2SJade Bilkey 
release_file_eeprom(struct inode * inode,struct file * file)959db906eb2SJade Bilkey static int release_file_eeprom(struct inode *inode, struct file *file)
960db906eb2SJade Bilkey {
961db906eb2SJade Bilkey 	struct eeprom_private *ep = file->private_data;
962db906eb2SJade Bilkey 
963db906eb2SJade Bilkey 	vfree(ep->buf);
964db906eb2SJade Bilkey 	kfree(ep);
965db906eb2SJade Bilkey 
966db906eb2SJade Bilkey 	return 0;
967db906eb2SJade Bilkey }
968db906eb2SJade Bilkey 
969db906eb2SJade Bilkey static const struct file_operations fops_eeprom = {
970db906eb2SJade Bilkey 	.open = open_file_eeprom,
971db906eb2SJade Bilkey 	.read = read_file_eeprom,
972db906eb2SJade Bilkey 	.release = release_file_eeprom,
973db906eb2SJade Bilkey 	.owner = THIS_MODULE,
974db906eb2SJade Bilkey };
975db906eb2SJade Bilkey 
9763cfd43f4SBruno Randolf 
977203c4805SLuis R. Rodriguez void
ath5k_debug_init_device(struct ath5k_hw * ah)978e0d687bdSPavel Roskin ath5k_debug_init_device(struct ath5k_hw *ah)
979203c4805SLuis R. Rodriguez {
9805b7916adSFelix Fietkau 	struct dentry *phydir;
9815b7916adSFelix Fietkau 
982e0d687bdSPavel Roskin 	ah->debug.level = ath5k_debug;
983203c4805SLuis R. Rodriguez 
984e0d687bdSPavel Roskin 	phydir = debugfs_create_dir("ath5k", ah->hw->wiphy->debugfsdir);
985203c4805SLuis R. Rodriguez 
9862ef00c53SJoe Perches 	debugfs_create_file("debug", 0600, phydir, ah, &fops_debug);
987aac352d6SLiu Shixin 	debugfs_create_file("registers", 0400, phydir, ah, &registers_fops);
9882ef00c53SJoe Perches 	debugfs_create_file("beacon", 0600, phydir, ah, &fops_beacon);
9892ef00c53SJoe Perches 	debugfs_create_file("reset", 0200, phydir, ah, &fops_reset);
9902ef00c53SJoe Perches 	debugfs_create_file("antenna", 0600, phydir, ah, &fops_antenna);
9912ef00c53SJoe Perches 	debugfs_create_file("misc", 0400, phydir, ah, &fops_misc);
9922ef00c53SJoe Perches 	debugfs_create_file("eeprom", 0400, phydir, ah, &fops_eeprom);
9932ef00c53SJoe Perches 	debugfs_create_file("frameerrors", 0600, phydir, ah, &fops_frameerrors);
9942ef00c53SJoe Perches 	debugfs_create_file("ani", 0600, phydir, ah, &fops_ani);
9952ef00c53SJoe Perches 	debugfs_create_file("queue", 0600, phydir, ah, &fops_queue);
9962ef00c53SJoe Perches 	debugfs_create_bool("32khz_clock", 0600, phydir,
997e0d687bdSPavel Roskin 			    &ah->ah_use_32khz_clock);
998203c4805SLuis R. Rodriguez }
999203c4805SLuis R. Rodriguez 
1000203c4805SLuis R. Rodriguez /* functions used in other places */
1001203c4805SLuis R. Rodriguez 
1002203c4805SLuis R. Rodriguez void
ath5k_debug_dump_bands(struct ath5k_hw * ah)1003e0d687bdSPavel Roskin ath5k_debug_dump_bands(struct ath5k_hw *ah)
1004203c4805SLuis R. Rodriguez {
1005203c4805SLuis R. Rodriguez 	unsigned int b, i;
1006203c4805SLuis R. Rodriguez 
1007e0d687bdSPavel Roskin 	if (likely(!(ah->debug.level & ATH5K_DEBUG_DUMPBANDS)))
1008203c4805SLuis R. Rodriguez 		return;
1009203c4805SLuis R. Rodriguez 
101057fbcce3SJohannes Berg 	for (b = 0; b < NUM_NL80211_BANDS; b++) {
1011e0d687bdSPavel Roskin 		struct ieee80211_supported_band *band = &ah->sbands[b];
1012aba74530SDavid S. Miller 		char bname[6];
1013203c4805SLuis R. Rodriguez 		switch (band->band) {
101457fbcce3SJohannes Berg 		case NL80211_BAND_2GHZ:
1015203c4805SLuis R. Rodriguez 			strcpy(bname, "2 GHz");
1016203c4805SLuis R. Rodriguez 			break;
101757fbcce3SJohannes Berg 		case NL80211_BAND_5GHZ:
1018203c4805SLuis R. Rodriguez 			strcpy(bname, "5 GHz");
1019203c4805SLuis R. Rodriguez 			break;
1020203c4805SLuis R. Rodriguez 		default:
1021203c4805SLuis R. Rodriguez 			printk(KERN_DEBUG "Band not supported: %d\n",
1022203c4805SLuis R. Rodriguez 				band->band);
1023203c4805SLuis R. Rodriguez 			return;
1024203c4805SLuis R. Rodriguez 		}
1025203c4805SLuis R. Rodriguez 		printk(KERN_DEBUG "Band %s: channels %d, rates %d\n", bname,
1026203c4805SLuis R. Rodriguez 				band->n_channels, band->n_bitrates);
1027203c4805SLuis R. Rodriguez 		printk(KERN_DEBUG " channels:\n");
1028203c4805SLuis R. Rodriguez 		for (i = 0; i < band->n_channels; i++)
1029203c4805SLuis R. Rodriguez 			printk(KERN_DEBUG "  %3d %d %.4x %.4x\n",
1030203c4805SLuis R. Rodriguez 					ieee80211_frequency_to_channel(
1031203c4805SLuis R. Rodriguez 						band->channels[i].center_freq),
1032203c4805SLuis R. Rodriguez 					band->channels[i].center_freq,
1033203c4805SLuis R. Rodriguez 					band->channels[i].hw_value,
1034203c4805SLuis R. Rodriguez 					band->channels[i].flags);
1035203c4805SLuis R. Rodriguez 		printk(KERN_DEBUG " rates:\n");
1036203c4805SLuis R. Rodriguez 		for (i = 0; i < band->n_bitrates; i++)
1037203c4805SLuis R. Rodriguez 			printk(KERN_DEBUG "  %4d %.4x %.4x %.4x\n",
1038203c4805SLuis R. Rodriguez 					band->bitrates[i].bitrate,
1039203c4805SLuis R. Rodriguez 					band->bitrates[i].hw_value,
1040203c4805SLuis R. Rodriguez 					band->bitrates[i].flags,
1041203c4805SLuis R. Rodriguez 					band->bitrates[i].hw_value_short);
1042203c4805SLuis R. Rodriguez 	}
1043203c4805SLuis R. Rodriguez }
1044203c4805SLuis R. Rodriguez 
1045203c4805SLuis R. Rodriguez static inline void
ath5k_debug_printrxbuf(struct ath5k_buf * bf,int done,struct ath5k_rx_status * rs)1046203c4805SLuis R. Rodriguez ath5k_debug_printrxbuf(struct ath5k_buf *bf, int done,
1047203c4805SLuis R. Rodriguez 		       struct ath5k_rx_status *rs)
1048203c4805SLuis R. Rodriguez {
1049203c4805SLuis R. Rodriguez 	struct ath5k_desc *ds = bf->desc;
1050203c4805SLuis R. Rodriguez 	struct ath5k_hw_all_rx_desc *rd = &ds->ud.ds_rx;
1051203c4805SLuis R. Rodriguez 
1052203c4805SLuis R. Rodriguez 	printk(KERN_DEBUG "R (%p %llx) %08x %08x %08x %08x %08x %08x %c\n",
1053203c4805SLuis R. Rodriguez 		ds, (unsigned long long)bf->daddr,
1054203c4805SLuis R. Rodriguez 		ds->ds_link, ds->ds_data,
1055203c4805SLuis R. Rodriguez 		rd->rx_ctl.rx_control_0, rd->rx_ctl.rx_control_1,
105662412a8fSBruno Randolf 		rd->rx_stat.rx_status_0, rd->rx_stat.rx_status_1,
1057203c4805SLuis R. Rodriguez 		!done ? ' ' : (rs->rs_status == 0) ? '*' : '!');
1058203c4805SLuis R. Rodriguez }
1059203c4805SLuis R. Rodriguez 
1060203c4805SLuis R. Rodriguez void
ath5k_debug_printrxbuffs(struct ath5k_hw * ah)1061e0d687bdSPavel Roskin ath5k_debug_printrxbuffs(struct ath5k_hw *ah)
1062203c4805SLuis R. Rodriguez {
1063203c4805SLuis R. Rodriguez 	struct ath5k_desc *ds;
1064203c4805SLuis R. Rodriguez 	struct ath5k_buf *bf;
1065203c4805SLuis R. Rodriguez 	struct ath5k_rx_status rs = {};
1066203c4805SLuis R. Rodriguez 	int status;
1067203c4805SLuis R. Rodriguez 
1068e0d687bdSPavel Roskin 	if (likely(!(ah->debug.level & ATH5K_DEBUG_DESC)))
1069203c4805SLuis R. Rodriguez 		return;
1070203c4805SLuis R. Rodriguez 
1071265faaddSBruno Randolf 	printk(KERN_DEBUG "rxdp %x, rxlink %p\n",
1072e0d687bdSPavel Roskin 		ath5k_hw_get_rxdp(ah), ah->rxlink);
1073203c4805SLuis R. Rodriguez 
1074e0d687bdSPavel Roskin 	spin_lock_bh(&ah->rxbuflock);
1075e0d687bdSPavel Roskin 	list_for_each_entry(bf, &ah->rxbuf, list) {
1076203c4805SLuis R. Rodriguez 		ds = bf->desc;
1077203c4805SLuis R. Rodriguez 		status = ah->ah_proc_rx_desc(ah, ds, &rs);
1078203c4805SLuis R. Rodriguez 		if (!status)
1079203c4805SLuis R. Rodriguez 			ath5k_debug_printrxbuf(bf, status == 0, &rs);
1080203c4805SLuis R. Rodriguez 	}
1081e0d687bdSPavel Roskin 	spin_unlock_bh(&ah->rxbuflock);
1082203c4805SLuis R. Rodriguez }
1083203c4805SLuis R. Rodriguez 
1084203c4805SLuis R. Rodriguez void
ath5k_debug_printtxbuf(struct ath5k_hw * ah,struct ath5k_buf * bf)1085e0d687bdSPavel Roskin ath5k_debug_printtxbuf(struct ath5k_hw *ah, struct ath5k_buf *bf)
1086203c4805SLuis R. Rodriguez {
1087203c4805SLuis R. Rodriguez 	struct ath5k_desc *ds = bf->desc;
1088203c4805SLuis R. Rodriguez 	struct ath5k_hw_5212_tx_desc *td = &ds->ud.ds_tx5212;
1089203c4805SLuis R. Rodriguez 	struct ath5k_tx_status ts = {};
1090203c4805SLuis R. Rodriguez 	int done;
1091203c4805SLuis R. Rodriguez 
1092e0d687bdSPavel Roskin 	if (likely(!(ah->debug.level & ATH5K_DEBUG_DESC)))
1093203c4805SLuis R. Rodriguez 		return;
1094203c4805SLuis R. Rodriguez 
1095e0d687bdSPavel Roskin 	done = ah->ah_proc_tx_desc(ah, bf->desc, &ts);
1096203c4805SLuis R. Rodriguez 
1097203c4805SLuis R. Rodriguez 	printk(KERN_DEBUG "T (%p %llx) %08x %08x %08x %08x %08x %08x %08x "
1098203c4805SLuis R. Rodriguez 		"%08x %c\n", ds, (unsigned long long)bf->daddr, ds->ds_link,
1099203c4805SLuis R. Rodriguez 		ds->ds_data, td->tx_ctl.tx_control_0, td->tx_ctl.tx_control_1,
1100203c4805SLuis R. Rodriguez 		td->tx_ctl.tx_control_2, td->tx_ctl.tx_control_3,
1101203c4805SLuis R. Rodriguez 		td->tx_stat.tx_status_0, td->tx_stat.tx_status_1,
1102203c4805SLuis R. Rodriguez 		done ? ' ' : (ts.ts_status == 0) ? '*' : '!');
1103203c4805SLuis R. Rodriguez }
1104