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