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