]>
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 | */ | |
60 | ||
61 | #include "debug.h" | |
62 | #include "base.h" | |
63 | ||
64 | static unsigned int ath5k_debug; | |
65 | module_param_named(debug, ath5k_debug, uint, 0); | |
66 | ||
67 | ||
b446197c | 68 | #ifdef CONFIG_ATH5K_DEBUG |
fa1c114f JS |
69 | |
70 | #include <linux/seq_file.h> | |
71 | #include "reg.h" | |
72 | ||
73 | static struct dentry *ath5k_global_debugfs; | |
74 | ||
75 | static int ath5k_debugfs_open(struct inode *inode, struct file *file) | |
76 | { | |
77 | file->private_data = inode->i_private; | |
78 | return 0; | |
79 | } | |
80 | ||
81 | ||
82 | /* debugfs: registers */ | |
83 | ||
84 | struct reg { | |
85 | char *name; | |
86 | int addr; | |
87 | }; | |
88 | ||
89 | #define REG_STRUCT_INIT(r) { #r, r } | |
90 | ||
91 | /* just a few random registers, might want to add more */ | |
92 | static struct reg regs[] = { | |
93 | REG_STRUCT_INIT(AR5K_CR), | |
94 | REG_STRUCT_INIT(AR5K_RXDP), | |
95 | REG_STRUCT_INIT(AR5K_CFG), | |
96 | REG_STRUCT_INIT(AR5K_IER), | |
97 | REG_STRUCT_INIT(AR5K_BCR), | |
98 | REG_STRUCT_INIT(AR5K_RTSD0), | |
99 | REG_STRUCT_INIT(AR5K_RTSD1), | |
100 | REG_STRUCT_INIT(AR5K_TXCFG), | |
101 | REG_STRUCT_INIT(AR5K_RXCFG), | |
102 | REG_STRUCT_INIT(AR5K_RXJLA), | |
103 | REG_STRUCT_INIT(AR5K_MIBC), | |
104 | REG_STRUCT_INIT(AR5K_TOPS), | |
105 | REG_STRUCT_INIT(AR5K_RXNOFRM), | |
106 | REG_STRUCT_INIT(AR5K_TXNOFRM), | |
107 | REG_STRUCT_INIT(AR5K_RPGTO), | |
108 | REG_STRUCT_INIT(AR5K_RFCNT), | |
109 | REG_STRUCT_INIT(AR5K_MISC), | |
110 | REG_STRUCT_INIT(AR5K_QCUDCU_CLKGT), | |
111 | REG_STRUCT_INIT(AR5K_ISR), | |
112 | REG_STRUCT_INIT(AR5K_PISR), | |
113 | REG_STRUCT_INIT(AR5K_SISR0), | |
114 | REG_STRUCT_INIT(AR5K_SISR1), | |
115 | REG_STRUCT_INIT(AR5K_SISR2), | |
116 | REG_STRUCT_INIT(AR5K_SISR3), | |
117 | REG_STRUCT_INIT(AR5K_SISR4), | |
118 | REG_STRUCT_INIT(AR5K_IMR), | |
119 | REG_STRUCT_INIT(AR5K_PIMR), | |
120 | REG_STRUCT_INIT(AR5K_SIMR0), | |
121 | REG_STRUCT_INIT(AR5K_SIMR1), | |
122 | REG_STRUCT_INIT(AR5K_SIMR2), | |
123 | REG_STRUCT_INIT(AR5K_SIMR3), | |
124 | REG_STRUCT_INIT(AR5K_SIMR4), | |
125 | REG_STRUCT_INIT(AR5K_DCM_ADDR), | |
126 | REG_STRUCT_INIT(AR5K_DCCFG), | |
127 | REG_STRUCT_INIT(AR5K_CCFG), | |
128 | REG_STRUCT_INIT(AR5K_CPC0), | |
129 | REG_STRUCT_INIT(AR5K_CPC1), | |
130 | REG_STRUCT_INIT(AR5K_CPC2), | |
131 | REG_STRUCT_INIT(AR5K_CPC3), | |
132 | REG_STRUCT_INIT(AR5K_CPCORN), | |
133 | REG_STRUCT_INIT(AR5K_RESET_CTL), | |
134 | REG_STRUCT_INIT(AR5K_SLEEP_CTL), | |
135 | REG_STRUCT_INIT(AR5K_INTPEND), | |
136 | REG_STRUCT_INIT(AR5K_SFR), | |
137 | REG_STRUCT_INIT(AR5K_PCICFG), | |
138 | REG_STRUCT_INIT(AR5K_GPIOCR), | |
139 | REG_STRUCT_INIT(AR5K_GPIODO), | |
140 | REG_STRUCT_INIT(AR5K_SREV), | |
141 | }; | |
142 | ||
143 | static void *reg_start(struct seq_file *seq, loff_t *pos) | |
144 | { | |
145 | return *pos < ARRAY_SIZE(regs) ? ®s[*pos] : NULL; | |
146 | } | |
147 | ||
148 | static void reg_stop(struct seq_file *seq, void *p) | |
149 | { | |
150 | /* nothing to do */ | |
151 | } | |
152 | ||
153 | static void *reg_next(struct seq_file *seq, void *p, loff_t *pos) | |
154 | { | |
155 | ++*pos; | |
156 | return *pos < ARRAY_SIZE(regs) ? ®s[*pos] : NULL; | |
157 | } | |
158 | ||
159 | static int reg_show(struct seq_file *seq, void *p) | |
160 | { | |
161 | struct ath5k_softc *sc = seq->private; | |
162 | struct reg *r = p; | |
163 | seq_printf(seq, "%-25s0x%08x\n", r->name, | |
164 | ath5k_hw_reg_read(sc->ah, r->addr)); | |
165 | return 0; | |
166 | } | |
167 | ||
168 | static struct seq_operations register_seq_ops = { | |
169 | .start = reg_start, | |
170 | .next = reg_next, | |
171 | .stop = reg_stop, | |
172 | .show = reg_show | |
173 | }; | |
174 | ||
175 | static int open_file_registers(struct inode *inode, struct file *file) | |
176 | { | |
177 | struct seq_file *s; | |
178 | int res; | |
179 | res = seq_open(file, ®ister_seq_ops); | |
180 | if (res == 0) { | |
181 | s = file->private_data; | |
182 | s->private = inode->i_private; | |
183 | } | |
184 | return res; | |
185 | } | |
186 | ||
187 | static const struct file_operations fops_registers = { | |
188 | .open = open_file_registers, | |
189 | .read = seq_read, | |
190 | .llseek = seq_lseek, | |
191 | .release = seq_release, | |
192 | .owner = THIS_MODULE, | |
193 | }; | |
194 | ||
195 | ||
196 | /* debugfs: TSF */ | |
197 | ||
198 | static ssize_t read_file_tsf(struct file *file, char __user *user_buf, | |
199 | size_t count, loff_t *ppos) | |
200 | { | |
201 | struct ath5k_softc *sc = file->private_data; | |
202 | char buf[100]; | |
be9b7259 | 203 | snprintf(buf, sizeof(buf), "0x%016llx\n", ath5k_hw_get_tsf64(sc->ah)); |
fa1c114f JS |
204 | return simple_read_from_buffer(user_buf, count, ppos, buf, 19); |
205 | } | |
206 | ||
207 | static ssize_t write_file_tsf(struct file *file, | |
208 | const char __user *userbuf, | |
209 | size_t count, loff_t *ppos) | |
210 | { | |
211 | struct ath5k_softc *sc = file->private_data; | |
be9b7259 BR |
212 | char buf[20]; |
213 | ||
214 | if (copy_from_user(buf, userbuf, min(count, sizeof(buf)))) | |
215 | return -EFAULT; | |
216 | ||
217 | if (strncmp(buf, "reset", 5) == 0) { | |
fa1c114f JS |
218 | ath5k_hw_reset_tsf(sc->ah); |
219 | printk(KERN_INFO "debugfs reset TSF\n"); | |
220 | } | |
221 | return count; | |
222 | } | |
223 | ||
224 | static const struct file_operations fops_tsf = { | |
225 | .read = read_file_tsf, | |
226 | .write = write_file_tsf, | |
227 | .open = ath5k_debugfs_open, | |
228 | .owner = THIS_MODULE, | |
229 | }; | |
230 | ||
231 | ||
232 | /* debugfs: beacons */ | |
233 | ||
234 | static ssize_t read_file_beacon(struct file *file, char __user *user_buf, | |
235 | size_t count, loff_t *ppos) | |
236 | { | |
237 | struct ath5k_softc *sc = file->private_data; | |
238 | struct ath5k_hw *ah = sc->ah; | |
be9b7259 BR |
239 | char buf[500]; |
240 | unsigned int len = 0; | |
fa1c114f JS |
241 | unsigned int v; |
242 | u64 tsf; | |
243 | ||
244 | v = ath5k_hw_reg_read(sc->ah, AR5K_BEACON); | |
245 | len += snprintf(buf+len, sizeof(buf)-len, | |
246 | "%-24s0x%08x\tintval: %d\tTIM: 0x%x\n", | |
247 | "AR5K_BEACON", v, v & AR5K_BEACON_PERIOD, | |
248 | (v & AR5K_BEACON_TIM) >> AR5K_BEACON_TIM_S); | |
249 | ||
250 | len += snprintf(buf+len, sizeof(buf)-len, "%-24s0x%08x\n", | |
251 | "AR5K_LAST_TSTP", ath5k_hw_reg_read(sc->ah, AR5K_LAST_TSTP)); | |
252 | ||
253 | len += snprintf(buf+len, sizeof(buf)-len, "%-24s0x%08x\n\n", | |
254 | "AR5K_BEACON_CNT", ath5k_hw_reg_read(sc->ah, AR5K_BEACON_CNT)); | |
255 | ||
256 | v = ath5k_hw_reg_read(sc->ah, AR5K_TIMER0); | |
257 | len += snprintf(buf+len, sizeof(buf)-len, "%-24s0x%08x\tTU: %08x\n", | |
258 | "AR5K_TIMER0 (TBTT)", v, v); | |
259 | ||
260 | v = ath5k_hw_reg_read(sc->ah, AR5K_TIMER1); | |
261 | len += snprintf(buf+len, sizeof(buf)-len, "%-24s0x%08x\tTU: %08x\n", | |
262 | "AR5K_TIMER1 (DMA)", v, v >> 3); | |
263 | ||
264 | v = ath5k_hw_reg_read(sc->ah, AR5K_TIMER2); | |
265 | len += snprintf(buf+len, sizeof(buf)-len, "%-24s0x%08x\tTU: %08x\n", | |
266 | "AR5K_TIMER2 (SWBA)", v, v >> 3); | |
267 | ||
268 | v = ath5k_hw_reg_read(sc->ah, AR5K_TIMER3); | |
269 | len += snprintf(buf+len, sizeof(buf)-len, "%-24s0x%08x\tTU: %08x\n", | |
270 | "AR5K_TIMER3 (ATIM)", v, v); | |
271 | ||
272 | tsf = ath5k_hw_get_tsf64(sc->ah); | |
273 | len += snprintf(buf+len, sizeof(buf)-len, | |
274 | "TSF\t\t0x%016llx\tTU: %08x\n", tsf, TSF_TO_TU(tsf)); | |
275 | ||
276 | return simple_read_from_buffer(user_buf, count, ppos, buf, len); | |
277 | } | |
278 | ||
279 | static ssize_t write_file_beacon(struct file *file, | |
280 | const char __user *userbuf, | |
281 | size_t count, loff_t *ppos) | |
282 | { | |
283 | struct ath5k_softc *sc = file->private_data; | |
284 | struct ath5k_hw *ah = sc->ah; | |
be9b7259 | 285 | char buf[20]; |
fa1c114f | 286 | |
be9b7259 BR |
287 | if (copy_from_user(buf, userbuf, min(count, sizeof(buf)))) |
288 | return -EFAULT; | |
289 | ||
290 | if (strncmp(buf, "disable", 7) == 0) { | |
fa1c114f JS |
291 | AR5K_REG_DISABLE_BITS(ah, AR5K_BEACON, AR5K_BEACON_ENABLE); |
292 | printk(KERN_INFO "debugfs disable beacons\n"); | |
be9b7259 | 293 | } else if (strncmp(buf, "enable", 6) == 0) { |
fa1c114f JS |
294 | AR5K_REG_ENABLE_BITS(ah, AR5K_BEACON, AR5K_BEACON_ENABLE); |
295 | printk(KERN_INFO "debugfs enable beacons\n"); | |
296 | } | |
297 | return count; | |
298 | } | |
299 | ||
300 | static const struct file_operations fops_beacon = { | |
301 | .read = read_file_beacon, | |
302 | .write = write_file_beacon, | |
303 | .open = ath5k_debugfs_open, | |
304 | .owner = THIS_MODULE, | |
305 | }; | |
306 | ||
307 | ||
308 | /* debugfs: reset */ | |
309 | ||
310 | static ssize_t write_file_reset(struct file *file, | |
311 | const char __user *userbuf, | |
312 | size_t count, loff_t *ppos) | |
313 | { | |
314 | struct ath5k_softc *sc = file->private_data; | |
315 | tasklet_schedule(&sc->restq); | |
316 | return count; | |
317 | } | |
318 | ||
319 | static const struct file_operations fops_reset = { | |
320 | .write = write_file_reset, | |
321 | .open = ath5k_debugfs_open, | |
322 | .owner = THIS_MODULE, | |
323 | }; | |
324 | ||
325 | ||
be9b7259 BR |
326 | /* debugfs: debug level */ |
327 | ||
328 | static struct { | |
329 | enum ath5k_debug_level level; | |
330 | const char *name; | |
331 | const char *desc; | |
332 | } dbg_info[] = { | |
333 | { ATH5K_DEBUG_RESET, "reset", "reset and initialization" }, | |
334 | { ATH5K_DEBUG_INTR, "intr", "interrupt handling" }, | |
335 | { ATH5K_DEBUG_MODE, "mode", "mode init/setup" }, | |
336 | { ATH5K_DEBUG_XMIT, "xmit", "basic xmit operation" }, | |
337 | { ATH5K_DEBUG_BEACON, "beacon", "beacon handling" }, | |
338 | { ATH5K_DEBUG_CALIBRATE, "calib", "periodic calibration" }, | |
339 | { ATH5K_DEBUG_TXPOWER, "txpower", "transmit power setting" }, | |
340 | { ATH5K_DEBUG_LED, "led", "LED mamagement" }, | |
341 | { ATH5K_DEBUG_DUMP_RX, "dumprx", "print received skb content" }, | |
342 | { ATH5K_DEBUG_DUMP_TX, "dumptx", "print transmit skb content" }, | |
b446197c | 343 | { ATH5K_DEBUG_DUMPBANDS, "dumpbands", "dump bands" }, |
be9b7259 BR |
344 | { ATH5K_DEBUG_TRACE, "trace", "trace function calls" }, |
345 | { ATH5K_DEBUG_ANY, "all", "show all debug levels" }, | |
346 | }; | |
347 | ||
348 | static ssize_t read_file_debug(struct file *file, char __user *user_buf, | |
349 | size_t count, loff_t *ppos) | |
350 | { | |
351 | struct ath5k_softc *sc = file->private_data; | |
352 | char buf[700]; | |
353 | unsigned int len = 0; | |
354 | unsigned int i; | |
355 | ||
356 | len += snprintf(buf+len, sizeof(buf)-len, | |
357 | "DEBUG LEVEL: 0x%08x\n\n", sc->debug.level); | |
358 | ||
359 | for (i = 0; i < ARRAY_SIZE(dbg_info) - 1; i++) { | |
360 | len += snprintf(buf+len, sizeof(buf)-len, | |
361 | "%10s %c 0x%08x - %s\n", dbg_info[i].name, | |
362 | sc->debug.level & dbg_info[i].level ? '+' : ' ', | |
363 | dbg_info[i].level, dbg_info[i].desc); | |
364 | } | |
365 | len += snprintf(buf+len, sizeof(buf)-len, | |
366 | "%10s %c 0x%08x - %s\n", dbg_info[i].name, | |
367 | sc->debug.level == dbg_info[i].level ? '+' : ' ', | |
368 | dbg_info[i].level, dbg_info[i].desc); | |
369 | ||
370 | return simple_read_from_buffer(user_buf, count, ppos, buf, len); | |
371 | } | |
372 | ||
373 | static ssize_t write_file_debug(struct file *file, | |
374 | const char __user *userbuf, | |
375 | size_t count, loff_t *ppos) | |
376 | { | |
377 | struct ath5k_softc *sc = file->private_data; | |
378 | unsigned int i; | |
379 | char buf[20]; | |
380 | ||
381 | if (copy_from_user(buf, userbuf, min(count, sizeof(buf)))) | |
382 | return -EFAULT; | |
383 | ||
384 | for (i = 0; i < ARRAY_SIZE(dbg_info); i++) { | |
385 | if (strncmp(buf, dbg_info[i].name, | |
386 | strlen(dbg_info[i].name)) == 0) { | |
387 | sc->debug.level ^= dbg_info[i].level; /* toggle bit */ | |
388 | break; | |
389 | } | |
390 | } | |
391 | return count; | |
392 | } | |
393 | ||
394 | static const struct file_operations fops_debug = { | |
395 | .read = read_file_debug, | |
396 | .write = write_file_debug, | |
397 | .open = ath5k_debugfs_open, | |
398 | .owner = THIS_MODULE, | |
399 | }; | |
400 | ||
401 | ||
fa1c114f JS |
402 | /* init */ |
403 | ||
404 | void | |
405 | ath5k_debug_init(void) | |
406 | { | |
407 | ath5k_global_debugfs = debugfs_create_dir("ath5k", NULL); | |
408 | } | |
409 | ||
410 | void | |
411 | ath5k_debug_init_device(struct ath5k_softc *sc) | |
412 | { | |
413 | sc->debug.level = ath5k_debug; | |
be9b7259 | 414 | |
fa1c114f | 415 | sc->debug.debugfs_phydir = debugfs_create_dir(wiphy_name(sc->hw->wiphy), |
be9b7259 BR |
416 | ath5k_global_debugfs); |
417 | ||
418 | sc->debug.debugfs_debug = debugfs_create_file("debug", 0666, | |
419 | sc->debug.debugfs_phydir, sc, &fops_debug); | |
fa1c114f JS |
420 | |
421 | sc->debug.debugfs_registers = debugfs_create_file("registers", 0444, | |
be9b7259 | 422 | sc->debug.debugfs_phydir, sc, &fops_registers); |
fa1c114f JS |
423 | |
424 | sc->debug.debugfs_tsf = debugfs_create_file("tsf", 0666, | |
be9b7259 | 425 | sc->debug.debugfs_phydir, sc, &fops_tsf); |
fa1c114f JS |
426 | |
427 | sc->debug.debugfs_beacon = debugfs_create_file("beacon", 0666, | |
be9b7259 | 428 | sc->debug.debugfs_phydir, sc, &fops_beacon); |
fa1c114f JS |
429 | |
430 | sc->debug.debugfs_reset = debugfs_create_file("reset", 0222, | |
be9b7259 | 431 | sc->debug.debugfs_phydir, sc, &fops_reset); |
fa1c114f JS |
432 | } |
433 | ||
434 | void | |
435 | ath5k_debug_finish(void) | |
436 | { | |
437 | debugfs_remove(ath5k_global_debugfs); | |
438 | } | |
439 | ||
440 | void | |
441 | ath5k_debug_finish_device(struct ath5k_softc *sc) | |
442 | { | |
443 | debugfs_remove(sc->debug.debugfs_debug); | |
444 | debugfs_remove(sc->debug.debugfs_registers); | |
445 | debugfs_remove(sc->debug.debugfs_tsf); | |
446 | debugfs_remove(sc->debug.debugfs_beacon); | |
447 | debugfs_remove(sc->debug.debugfs_reset); | |
448 | debugfs_remove(sc->debug.debugfs_phydir); | |
449 | } | |
450 | ||
451 | ||
452 | /* functions used in other places */ | |
453 | ||
454 | void | |
b446197c | 455 | ath5k_debug_dump_bands(struct ath5k_softc *sc) |
fa1c114f | 456 | { |
b446197c | 457 | unsigned int b, i; |
fa1c114f | 458 | |
b446197c | 459 | if (likely(!(sc->debug.level & ATH5K_DEBUG_DUMPBANDS))) |
fa1c114f JS |
460 | return; |
461 | ||
b446197c LR |
462 | BUG_ON(!sc->sbands); |
463 | ||
464 | for (b = 0; b < IEEE80211_NUM_BANDS; b++) { | |
465 | struct ieee80211_supported_band *band = &sc->sbands[b]; | |
466 | char bname[5]; | |
467 | switch (band->band) { | |
468 | case IEEE80211_BAND_2GHZ: | |
469 | strcpy(bname, "2 GHz"); | |
470 | break; | |
471 | case IEEE80211_BAND_5GHZ: | |
472 | strcpy(bname, "5 GHz"); | |
473 | break; | |
474 | default: | |
475 | printk(KERN_DEBUG "Band not supported: %d\n", | |
476 | band->band); | |
477 | return; | |
478 | } | |
479 | printk(KERN_DEBUG "Band %s: channels %d, rates %d\n", bname, | |
480 | band->n_channels, band->n_bitrates); | |
fa1c114f | 481 | printk(KERN_DEBUG " channels:\n"); |
b446197c | 482 | for (i = 0; i < band->n_channels; i++) |
fa1c114f | 483 | printk(KERN_DEBUG " %3d %d %.4x %.4x\n", |
b446197c LR |
484 | ieee80211_frequency_to_channel( |
485 | band->channels[i].center_freq), | |
486 | band->channels[i].center_freq, | |
487 | band->channels[i].hw_value, | |
488 | band->channels[i].flags); | |
fa1c114f | 489 | printk(KERN_DEBUG " rates:\n"); |
b446197c | 490 | for (i = 0; i < band->n_bitrates; i++) |
fa1c114f | 491 | printk(KERN_DEBUG " %4d %.4x %.4x %.4x\n", |
b446197c LR |
492 | band->bitrates[i].bitrate, |
493 | band->bitrates[i].hw_value, | |
494 | band->bitrates[i].flags, | |
495 | band->bitrates[i].hw_value_short); | |
fa1c114f JS |
496 | } |
497 | } | |
498 | ||
499 | static inline void | |
b47f407b BR |
500 | ath5k_debug_printrxbuf(struct ath5k_buf *bf, int done, |
501 | struct ath5k_rx_status *rs) | |
fa1c114f JS |
502 | { |
503 | struct ath5k_desc *ds = bf->desc; | |
19fd6e55 | 504 | struct ath5k_hw_all_rx_desc *rd = &ds->ud.ds_rx; |
fa1c114f JS |
505 | |
506 | printk(KERN_DEBUG "R (%p %llx) %08x %08x %08x %08x %08x %08x %c\n", | |
507 | ds, (unsigned long long)bf->daddr, | |
19fd6e55 BR |
508 | ds->ds_link, ds->ds_data, |
509 | rd->rx_ctl.rx_control_0, rd->rx_ctl.rx_control_1, | |
510 | rd->u.rx_stat.rx_status_0, rd->u.rx_stat.rx_status_0, | |
b47f407b | 511 | !done ? ' ' : (rs->rs_status == 0) ? '*' : '!'); |
fa1c114f JS |
512 | } |
513 | ||
514 | void | |
515 | ath5k_debug_printrxbuffs(struct ath5k_softc *sc, struct ath5k_hw *ah) | |
516 | { | |
517 | struct ath5k_desc *ds; | |
518 | struct ath5k_buf *bf; | |
b47f407b | 519 | struct ath5k_rx_status rs = {}; |
fa1c114f JS |
520 | int status; |
521 | ||
be9b7259 | 522 | if (likely(!(sc->debug.level & ATH5K_DEBUG_RESET))) |
fa1c114f JS |
523 | return; |
524 | ||
525 | printk(KERN_DEBUG "rx queue %x, link %p\n", | |
526 | ath5k_hw_get_rx_buf(ah), sc->rxlink); | |
527 | ||
528 | spin_lock_bh(&sc->rxbuflock); | |
529 | list_for_each_entry(bf, &sc->rxbuf, list) { | |
530 | ds = bf->desc; | |
b47f407b | 531 | status = ah->ah_proc_rx_desc(ah, ds, &rs); |
be9b7259 | 532 | if (!status) |
b47f407b | 533 | ath5k_debug_printrxbuf(bf, status == 0, &rs); |
fa1c114f JS |
534 | } |
535 | spin_unlock_bh(&sc->rxbuflock); | |
536 | } | |
537 | ||
538 | void | |
539 | ath5k_debug_dump_skb(struct ath5k_softc *sc, | |
540 | struct sk_buff *skb, const char *prefix, int tx) | |
541 | { | |
542 | char buf[16]; | |
543 | ||
544 | if (likely(!((tx && (sc->debug.level & ATH5K_DEBUG_DUMP_TX)) || | |
545 | (!tx && (sc->debug.level & ATH5K_DEBUG_DUMP_RX))))) | |
546 | return; | |
547 | ||
548 | snprintf(buf, sizeof(buf), "%s %s", wiphy_name(sc->hw->wiphy), prefix); | |
549 | ||
550 | print_hex_dump_bytes(buf, DUMP_PREFIX_NONE, skb->data, | |
551 | min(200U, skb->len)); | |
552 | ||
553 | printk(KERN_DEBUG "\n"); | |
554 | } | |
555 | ||
556 | void | |
b47f407b | 557 | ath5k_debug_printtxbuf(struct ath5k_softc *sc, struct ath5k_buf *bf) |
fa1c114f JS |
558 | { |
559 | struct ath5k_desc *ds = bf->desc; | |
19fd6e55 | 560 | struct ath5k_hw_5212_tx_desc *td = &ds->ud.ds_tx5212; |
b47f407b BR |
561 | struct ath5k_tx_status ts = {}; |
562 | int done; | |
fa1c114f JS |
563 | |
564 | if (likely(!(sc->debug.level & ATH5K_DEBUG_RESET))) | |
565 | return; | |
566 | ||
b47f407b BR |
567 | done = sc->ah->ah_proc_tx_desc(sc->ah, bf->desc, &ts); |
568 | ||
fa1c114f JS |
569 | printk(KERN_DEBUG "T (%p %llx) %08x %08x %08x %08x %08x %08x %08x " |
570 | "%08x %c\n", ds, (unsigned long long)bf->daddr, ds->ds_link, | |
19fd6e55 BR |
571 | ds->ds_data, td->tx_ctl.tx_control_0, td->tx_ctl.tx_control_1, |
572 | td->tx_ctl.tx_control_2, td->tx_ctl.tx_control_3, | |
573 | td->tx_stat.tx_status_0, td->tx_stat.tx_status_1, | |
b47f407b | 574 | done ? ' ' : (ts.ts_status == 0) ? '*' : '!'); |
fa1c114f JS |
575 | } |
576 | ||
b446197c | 577 | #endif /* ifdef CONFIG_ATH5K_DEBUG */ |