diff options
Diffstat (limited to 'drivers/net/wireless/ath/ath5k/debug.c')
-rw-r--r-- | drivers/net/wireless/ath/ath5k/debug.c | 538 |
1 files changed, 538 insertions, 0 deletions
diff --git a/drivers/net/wireless/ath/ath5k/debug.c b/drivers/net/wireless/ath/ath5k/debug.c new file mode 100644 index 000000000000..9770bb3d40f9 --- /dev/null +++ b/drivers/net/wireless/ath/ath5k/debug.c | |||
@@ -0,0 +1,538 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2007-2008 Bruno Randolf <bruno@thinktube.com> | ||
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 "base.h" | ||
62 | #include "debug.h" | ||
63 | |||
64 | static unsigned int ath5k_debug; | ||
65 | module_param_named(debug, ath5k_debug, uint, 0); | ||
66 | |||
67 | |||
68 | #ifdef CONFIG_ATH5K_DEBUG | ||
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 | const 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 const 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_CPCOVF), | ||
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) ? (void *)®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) ? (void *)®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 const 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: beacons */ | ||
197 | |||
198 | static ssize_t read_file_beacon(struct file *file, char __user *user_buf, | ||
199 | size_t count, loff_t *ppos) | ||
200 | { | ||
201 | struct ath5k_softc *sc = file->private_data; | ||
202 | struct ath5k_hw *ah = sc->ah; | ||
203 | char buf[500]; | ||
204 | unsigned int len = 0; | ||
205 | unsigned int v; | ||
206 | u64 tsf; | ||
207 | |||
208 | v = ath5k_hw_reg_read(sc->ah, AR5K_BEACON); | ||
209 | len += snprintf(buf+len, sizeof(buf)-len, | ||
210 | "%-24s0x%08x\tintval: %d\tTIM: 0x%x\n", | ||
211 | "AR5K_BEACON", v, v & AR5K_BEACON_PERIOD, | ||
212 | (v & AR5K_BEACON_TIM) >> AR5K_BEACON_TIM_S); | ||
213 | |||
214 | len += snprintf(buf+len, sizeof(buf)-len, "%-24s0x%08x\n", | ||
215 | "AR5K_LAST_TSTP", ath5k_hw_reg_read(sc->ah, AR5K_LAST_TSTP)); | ||
216 | |||
217 | len += snprintf(buf+len, sizeof(buf)-len, "%-24s0x%08x\n\n", | ||
218 | "AR5K_BEACON_CNT", ath5k_hw_reg_read(sc->ah, AR5K_BEACON_CNT)); | ||
219 | |||
220 | v = ath5k_hw_reg_read(sc->ah, AR5K_TIMER0); | ||
221 | len += snprintf(buf+len, sizeof(buf)-len, "%-24s0x%08x\tTU: %08x\n", | ||
222 | "AR5K_TIMER0 (TBTT)", v, v); | ||
223 | |||
224 | v = ath5k_hw_reg_read(sc->ah, AR5K_TIMER1); | ||
225 | len += snprintf(buf+len, sizeof(buf)-len, "%-24s0x%08x\tTU: %08x\n", | ||
226 | "AR5K_TIMER1 (DMA)", v, v >> 3); | ||
227 | |||
228 | v = ath5k_hw_reg_read(sc->ah, AR5K_TIMER2); | ||
229 | len += snprintf(buf+len, sizeof(buf)-len, "%-24s0x%08x\tTU: %08x\n", | ||
230 | "AR5K_TIMER2 (SWBA)", v, v >> 3); | ||
231 | |||
232 | v = ath5k_hw_reg_read(sc->ah, AR5K_TIMER3); | ||
233 | len += snprintf(buf+len, sizeof(buf)-len, "%-24s0x%08x\tTU: %08x\n", | ||
234 | "AR5K_TIMER3 (ATIM)", v, v); | ||
235 | |||
236 | tsf = ath5k_hw_get_tsf64(sc->ah); | ||
237 | len += snprintf(buf+len, sizeof(buf)-len, | ||
238 | "TSF\t\t0x%016llx\tTU: %08x\n", | ||
239 | (unsigned long long)tsf, TSF_TO_TU(tsf)); | ||
240 | |||
241 | return simple_read_from_buffer(user_buf, count, ppos, buf, len); | ||
242 | } | ||
243 | |||
244 | static ssize_t write_file_beacon(struct file *file, | ||
245 | const char __user *userbuf, | ||
246 | size_t count, loff_t *ppos) | ||
247 | { | ||
248 | struct ath5k_softc *sc = file->private_data; | ||
249 | struct ath5k_hw *ah = sc->ah; | ||
250 | char buf[20]; | ||
251 | |||
252 | if (copy_from_user(buf, userbuf, min(count, sizeof(buf)))) | ||
253 | return -EFAULT; | ||
254 | |||
255 | if (strncmp(buf, "disable", 7) == 0) { | ||
256 | AR5K_REG_DISABLE_BITS(ah, AR5K_BEACON, AR5K_BEACON_ENABLE); | ||
257 | printk(KERN_INFO "debugfs disable beacons\n"); | ||
258 | } else if (strncmp(buf, "enable", 6) == 0) { | ||
259 | AR5K_REG_ENABLE_BITS(ah, AR5K_BEACON, AR5K_BEACON_ENABLE); | ||
260 | printk(KERN_INFO "debugfs enable beacons\n"); | ||
261 | } | ||
262 | return count; | ||
263 | } | ||
264 | |||
265 | static const struct file_operations fops_beacon = { | ||
266 | .read = read_file_beacon, | ||
267 | .write = write_file_beacon, | ||
268 | .open = ath5k_debugfs_open, | ||
269 | .owner = THIS_MODULE, | ||
270 | }; | ||
271 | |||
272 | |||
273 | /* debugfs: reset */ | ||
274 | |||
275 | static ssize_t write_file_reset(struct file *file, | ||
276 | const char __user *userbuf, | ||
277 | size_t count, loff_t *ppos) | ||
278 | { | ||
279 | struct ath5k_softc *sc = file->private_data; | ||
280 | tasklet_schedule(&sc->restq); | ||
281 | return count; | ||
282 | } | ||
283 | |||
284 | static const struct file_operations fops_reset = { | ||
285 | .write = write_file_reset, | ||
286 | .open = ath5k_debugfs_open, | ||
287 | .owner = THIS_MODULE, | ||
288 | }; | ||
289 | |||
290 | |||
291 | /* debugfs: debug level */ | ||
292 | |||
293 | static const struct { | ||
294 | enum ath5k_debug_level level; | ||
295 | const char *name; | ||
296 | const char *desc; | ||
297 | } dbg_info[] = { | ||
298 | { ATH5K_DEBUG_RESET, "reset", "reset and initialization" }, | ||
299 | { ATH5K_DEBUG_INTR, "intr", "interrupt handling" }, | ||
300 | { ATH5K_DEBUG_MODE, "mode", "mode init/setup" }, | ||
301 | { ATH5K_DEBUG_XMIT, "xmit", "basic xmit operation" }, | ||
302 | { ATH5K_DEBUG_BEACON, "beacon", "beacon handling" }, | ||
303 | { ATH5K_DEBUG_CALIBRATE, "calib", "periodic calibration" }, | ||
304 | { ATH5K_DEBUG_TXPOWER, "txpower", "transmit power setting" }, | ||
305 | { ATH5K_DEBUG_LED, "led", "LED management" }, | ||
306 | { ATH5K_DEBUG_DUMP_RX, "dumprx", "print received skb content" }, | ||
307 | { ATH5K_DEBUG_DUMP_TX, "dumptx", "print transmit skb content" }, | ||
308 | { ATH5K_DEBUG_DUMPBANDS, "dumpbands", "dump bands" }, | ||
309 | { ATH5K_DEBUG_TRACE, "trace", "trace function calls" }, | ||
310 | { ATH5K_DEBUG_ANY, "all", "show all debug levels" }, | ||
311 | }; | ||
312 | |||
313 | static ssize_t read_file_debug(struct file *file, char __user *user_buf, | ||
314 | size_t count, loff_t *ppos) | ||
315 | { | ||
316 | struct ath5k_softc *sc = file->private_data; | ||
317 | char buf[700]; | ||
318 | unsigned int len = 0; | ||
319 | unsigned int i; | ||
320 | |||
321 | len += snprintf(buf+len, sizeof(buf)-len, | ||
322 | "DEBUG LEVEL: 0x%08x\n\n", sc->debug.level); | ||
323 | |||
324 | for (i = 0; i < ARRAY_SIZE(dbg_info) - 1; i++) { | ||
325 | len += snprintf(buf+len, sizeof(buf)-len, | ||
326 | "%10s %c 0x%08x - %s\n", dbg_info[i].name, | ||
327 | sc->debug.level & dbg_info[i].level ? '+' : ' ', | ||
328 | dbg_info[i].level, dbg_info[i].desc); | ||
329 | } | ||
330 | len += snprintf(buf+len, sizeof(buf)-len, | ||
331 | "%10s %c 0x%08x - %s\n", dbg_info[i].name, | ||
332 | sc->debug.level == dbg_info[i].level ? '+' : ' ', | ||
333 | dbg_info[i].level, dbg_info[i].desc); | ||
334 | |||
335 | return simple_read_from_buffer(user_buf, count, ppos, buf, len); | ||
336 | } | ||
337 | |||
338 | static ssize_t write_file_debug(struct file *file, | ||
339 | const char __user *userbuf, | ||
340 | size_t count, loff_t *ppos) | ||
341 | { | ||
342 | struct ath5k_softc *sc = file->private_data; | ||
343 | unsigned int i; | ||
344 | char buf[20]; | ||
345 | |||
346 | if (copy_from_user(buf, userbuf, min(count, sizeof(buf)))) | ||
347 | return -EFAULT; | ||
348 | |||
349 | for (i = 0; i < ARRAY_SIZE(dbg_info); i++) { | ||
350 | if (strncmp(buf, dbg_info[i].name, | ||
351 | strlen(dbg_info[i].name)) == 0) { | ||
352 | sc->debug.level ^= dbg_info[i].level; /* toggle bit */ | ||
353 | break; | ||
354 | } | ||
355 | } | ||
356 | return count; | ||
357 | } | ||
358 | |||
359 | static const struct file_operations fops_debug = { | ||
360 | .read = read_file_debug, | ||
361 | .write = write_file_debug, | ||
362 | .open = ath5k_debugfs_open, | ||
363 | .owner = THIS_MODULE, | ||
364 | }; | ||
365 | |||
366 | |||
367 | /* init */ | ||
368 | |||
369 | void | ||
370 | ath5k_debug_init(void) | ||
371 | { | ||
372 | ath5k_global_debugfs = debugfs_create_dir("ath5k", NULL); | ||
373 | } | ||
374 | |||
375 | void | ||
376 | ath5k_debug_init_device(struct ath5k_softc *sc) | ||
377 | { | ||
378 | sc->debug.level = ath5k_debug; | ||
379 | |||
380 | sc->debug.debugfs_phydir = debugfs_create_dir(wiphy_name(sc->hw->wiphy), | ||
381 | ath5k_global_debugfs); | ||
382 | |||
383 | sc->debug.debugfs_debug = debugfs_create_file("debug", S_IWUSR | S_IRUGO, | ||
384 | sc->debug.debugfs_phydir, sc, &fops_debug); | ||
385 | |||
386 | sc->debug.debugfs_registers = debugfs_create_file("registers", S_IRUGO, | ||
387 | sc->debug.debugfs_phydir, sc, &fops_registers); | ||
388 | |||
389 | sc->debug.debugfs_beacon = debugfs_create_file("beacon", S_IWUSR | S_IRUGO, | ||
390 | sc->debug.debugfs_phydir, sc, &fops_beacon); | ||
391 | |||
392 | sc->debug.debugfs_reset = debugfs_create_file("reset", S_IWUSR, | ||
393 | sc->debug.debugfs_phydir, sc, &fops_reset); | ||
394 | } | ||
395 | |||
396 | void | ||
397 | ath5k_debug_finish(void) | ||
398 | { | ||
399 | debugfs_remove(ath5k_global_debugfs); | ||
400 | } | ||
401 | |||
402 | void | ||
403 | ath5k_debug_finish_device(struct ath5k_softc *sc) | ||
404 | { | ||
405 | debugfs_remove(sc->debug.debugfs_debug); | ||
406 | debugfs_remove(sc->debug.debugfs_registers); | ||
407 | debugfs_remove(sc->debug.debugfs_beacon); | ||
408 | debugfs_remove(sc->debug.debugfs_reset); | ||
409 | debugfs_remove(sc->debug.debugfs_phydir); | ||
410 | } | ||
411 | |||
412 | |||
413 | /* functions used in other places */ | ||
414 | |||
415 | void | ||
416 | ath5k_debug_dump_bands(struct ath5k_softc *sc) | ||
417 | { | ||
418 | unsigned int b, i; | ||
419 | |||
420 | if (likely(!(sc->debug.level & ATH5K_DEBUG_DUMPBANDS))) | ||
421 | return; | ||
422 | |||
423 | BUG_ON(!sc->sbands); | ||
424 | |||
425 | for (b = 0; b < IEEE80211_NUM_BANDS; b++) { | ||
426 | struct ieee80211_supported_band *band = &sc->sbands[b]; | ||
427 | char bname[5]; | ||
428 | switch (band->band) { | ||
429 | case IEEE80211_BAND_2GHZ: | ||
430 | strcpy(bname, "2 GHz"); | ||
431 | break; | ||
432 | case IEEE80211_BAND_5GHZ: | ||
433 | strcpy(bname, "5 GHz"); | ||
434 | break; | ||
435 | default: | ||
436 | printk(KERN_DEBUG "Band not supported: %d\n", | ||
437 | band->band); | ||
438 | return; | ||
439 | } | ||
440 | printk(KERN_DEBUG "Band %s: channels %d, rates %d\n", bname, | ||
441 | band->n_channels, band->n_bitrates); | ||
442 | printk(KERN_DEBUG " channels:\n"); | ||
443 | for (i = 0; i < band->n_channels; i++) | ||
444 | printk(KERN_DEBUG " %3d %d %.4x %.4x\n", | ||
445 | ieee80211_frequency_to_channel( | ||
446 | band->channels[i].center_freq), | ||
447 | band->channels[i].center_freq, | ||
448 | band->channels[i].hw_value, | ||
449 | band->channels[i].flags); | ||
450 | printk(KERN_DEBUG " rates:\n"); | ||
451 | for (i = 0; i < band->n_bitrates; i++) | ||
452 | printk(KERN_DEBUG " %4d %.4x %.4x %.4x\n", | ||
453 | band->bitrates[i].bitrate, | ||
454 | band->bitrates[i].hw_value, | ||
455 | band->bitrates[i].flags, | ||
456 | band->bitrates[i].hw_value_short); | ||
457 | } | ||
458 | } | ||
459 | |||
460 | static inline void | ||
461 | ath5k_debug_printrxbuf(struct ath5k_buf *bf, int done, | ||
462 | struct ath5k_rx_status *rs) | ||
463 | { | ||
464 | struct ath5k_desc *ds = bf->desc; | ||
465 | struct ath5k_hw_all_rx_desc *rd = &ds->ud.ds_rx; | ||
466 | |||
467 | printk(KERN_DEBUG "R (%p %llx) %08x %08x %08x %08x %08x %08x %c\n", | ||
468 | ds, (unsigned long long)bf->daddr, | ||
469 | ds->ds_link, ds->ds_data, | ||
470 | rd->rx_ctl.rx_control_0, rd->rx_ctl.rx_control_1, | ||
471 | rd->u.rx_stat.rx_status_0, rd->u.rx_stat.rx_status_0, | ||
472 | !done ? ' ' : (rs->rs_status == 0) ? '*' : '!'); | ||
473 | } | ||
474 | |||
475 | void | ||
476 | ath5k_debug_printrxbuffs(struct ath5k_softc *sc, struct ath5k_hw *ah) | ||
477 | { | ||
478 | struct ath5k_desc *ds; | ||
479 | struct ath5k_buf *bf; | ||
480 | struct ath5k_rx_status rs = {}; | ||
481 | int status; | ||
482 | |||
483 | if (likely(!(sc->debug.level & ATH5K_DEBUG_RESET))) | ||
484 | return; | ||
485 | |||
486 | printk(KERN_DEBUG "rx queue %x, link %p\n", | ||
487 | ath5k_hw_get_rxdp(ah), sc->rxlink); | ||
488 | |||
489 | spin_lock_bh(&sc->rxbuflock); | ||
490 | list_for_each_entry(bf, &sc->rxbuf, list) { | ||
491 | ds = bf->desc; | ||
492 | status = ah->ah_proc_rx_desc(ah, ds, &rs); | ||
493 | if (!status) | ||
494 | ath5k_debug_printrxbuf(bf, status == 0, &rs); | ||
495 | } | ||
496 | spin_unlock_bh(&sc->rxbuflock); | ||
497 | } | ||
498 | |||
499 | void | ||
500 | ath5k_debug_dump_skb(struct ath5k_softc *sc, | ||
501 | struct sk_buff *skb, const char *prefix, int tx) | ||
502 | { | ||
503 | char buf[16]; | ||
504 | |||
505 | if (likely(!((tx && (sc->debug.level & ATH5K_DEBUG_DUMP_TX)) || | ||
506 | (!tx && (sc->debug.level & ATH5K_DEBUG_DUMP_RX))))) | ||
507 | return; | ||
508 | |||
509 | snprintf(buf, sizeof(buf), "%s %s", wiphy_name(sc->hw->wiphy), prefix); | ||
510 | |||
511 | print_hex_dump_bytes(buf, DUMP_PREFIX_NONE, skb->data, | ||
512 | min(200U, skb->len)); | ||
513 | |||
514 | printk(KERN_DEBUG "\n"); | ||
515 | } | ||
516 | |||
517 | void | ||
518 | ath5k_debug_printtxbuf(struct ath5k_softc *sc, struct ath5k_buf *bf) | ||
519 | { | ||
520 | struct ath5k_desc *ds = bf->desc; | ||
521 | struct ath5k_hw_5212_tx_desc *td = &ds->ud.ds_tx5212; | ||
522 | struct ath5k_tx_status ts = {}; | ||
523 | int done; | ||
524 | |||
525 | if (likely(!(sc->debug.level & ATH5K_DEBUG_RESET))) | ||
526 | return; | ||
527 | |||
528 | done = sc->ah->ah_proc_tx_desc(sc->ah, bf->desc, &ts); | ||
529 | |||
530 | printk(KERN_DEBUG "T (%p %llx) %08x %08x %08x %08x %08x %08x %08x " | ||
531 | "%08x %c\n", ds, (unsigned long long)bf->daddr, ds->ds_link, | ||
532 | ds->ds_data, td->tx_ctl.tx_control_0, td->tx_ctl.tx_control_1, | ||
533 | td->tx_ctl.tx_control_2, td->tx_ctl.tx_control_3, | ||
534 | td->tx_stat.tx_status_0, td->tx_stat.tx_status_1, | ||
535 | done ? ' ' : (ts.ts_status == 0) ? '*' : '!'); | ||
536 | } | ||
537 | |||
538 | #endif /* ifdef CONFIG_ATH5K_DEBUG */ | ||