Subversion Repositories shark

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
846 giacomo 1
/*
2
 * UHCI-specific debugging code. Invaluable when something
3
 * goes wrong, but don't get in my face.
4
 *
5
 * Kernel visible pointers are surrounded in []'s and bus
6
 * visible pointers are surrounded in ()'s
7
 *
8
 * (C) Copyright 1999 Linus Torvalds
9
 * (C) Copyright 1999-2001 Johannes Erdfelt
10
 */
11
 
12
#include <linuxcomp.h>
13
 
14
#include <linux/config.h>
15
#include <linux/kernel.h>
16
#include <linux/proc_fs.h>
17
#include <linux/smp_lock.h>
18
#include <asm/io.h>
19
 
20
#include "uhci-hcd.h"
21
 
22
/* Handle REALLY large printk's so we don't overflow buffers */
23
static inline void lprintk(char *buf)
24
{
25
        char *p;
26
 
27
        /* Just write one line at a time */
28
        while (buf) {
29
                p = strchr(buf, '\n');
30
                if (p)
31
                        *p = 0;
32
                printk("%s\n", buf);
33
                buf = p;
34
                if (buf)
35
                        buf++;
36
        }
37
}
38
 
39
static inline int uhci_is_skeleton_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
40
{
41
        int i;
42
 
43
        for (i = 0; i < UHCI_NUM_SKELQH; i++)
44
                if (qh == uhci->skelqh[i])
45
                        return 1;
46
 
47
        return 0;
48
}
49
 
50
static int uhci_show_td(struct uhci_td *td, char *buf, int len, int space)
51
{
52
        char *out = buf;
53
        char *spid;
54
        u32 status, token;
55
 
56
        /* Try to make sure there's enough memory */
57
        if (len < 160)
58
                return 0;
59
 
60
        status = td_status(td);
61
        out += sprintf26(out, "%*s[%p] link (%08x) ", space, "", td, le32_to_cpu(td->link));
62
        out += sprintf26(out, "e%d %s%s%s%s%s%s%s%s%s%sLength=%x ",
63
                ((status >> 27) & 3),
64
                (status & TD_CTRL_SPD) ?      "SPD " : "",
65
                (status & TD_CTRL_LS) ?       "LS " : "",
66
                (status & TD_CTRL_IOC) ?      "IOC " : "",
67
                (status & TD_CTRL_ACTIVE) ?   "Active " : "",
68
                (status & TD_CTRL_STALLED) ?  "Stalled " : "",
69
                (status & TD_CTRL_DBUFERR) ?  "DataBufErr " : "",
70
                (status & TD_CTRL_BABBLE) ?   "Babble " : "",
71
                (status & TD_CTRL_NAK) ?      "NAK " : "",
72
                (status & TD_CTRL_CRCTIMEO) ? "CRC/Timeo " : "",
73
                (status & TD_CTRL_BITSTUFF) ? "BitStuff " : "",
74
                status & 0x7ff);
75
 
76
        token = td_token(td);
77
        switch (uhci_packetid(token)) {
78
                case USB_PID_SETUP:
79
                        spid = "SETUP";
80
                        break;
81
                case USB_PID_OUT:
82
                        spid = "OUT";
83
                        break;
84
                case USB_PID_IN:
85
                        spid = "IN";
86
                        break;
87
                default:
88
                        spid = "?";
89
                        break;
90
        }
91
 
92
        out += sprintf26(out, "MaxLen=%x DT%d EndPt=%x Dev=%x, PID=%x(%s) ",
93
                token >> 21,
94
                ((token >> 19) & 1),
95
                (token >> 15) & 15,
96
                (token >> 8) & 127,
97
                (token & 0xff),
98
                spid);
99
        out += sprintf26(out, "(buf=%08x)\n", le32_to_cpu(td->buffer));
100
 
101
        return out - buf;
102
}
103
 
104
static int uhci_show_qh(struct uhci_qh *qh, char *buf, int len, int space)
105
{
106
        char *out = buf;
107
        struct urb_priv *urbp;
108
        struct list_head *head, *tmp;
109
        struct uhci_td *td;
110
        int i = 0, checked = 0, prevactive = 0;
111
 
112
        /* Try to make sure there's enough memory */
113
        if (len < 80 * 6)
114
                return 0;
115
 
116
        out += sprintf26(out, "%*s[%p] link (%08x) element (%08x)\n", space, "",
117
                        qh, le32_to_cpu(qh->link), le32_to_cpu(qh->element));
118
 
119
        if (qh->element & UHCI_PTR_QH)
120
                out += sprintf26(out, "%*s  Element points to QH (bug?)\n", space, "");
121
 
122
        if (qh->element & UHCI_PTR_DEPTH)
123
                out += sprintf26(out, "%*s  Depth traverse\n", space, "");
124
 
125
        if (qh->element & cpu_to_le32(8))
126
                out += sprintf26(out, "%*s  Bit 3 set (bug?)\n", space, "");
127
 
128
        if (!(qh->element & ~(UHCI_PTR_QH | UHCI_PTR_DEPTH)))
129
                out += sprintf26(out, "%*s  Element is NULL (bug?)\n", space, "");
130
 
131
        if (!qh->urbp) {
132
                out += sprintf26(out, "%*s  urbp == NULL\n", space, "");
133
                goto out;
134
        }
135
 
136
        urbp = qh->urbp;
137
 
138
        head = &urbp->td_list;
139
        tmp = head->next;
140
 
141
        td = list_entry(tmp, struct uhci_td, list);
142
 
143
        if (cpu_to_le32(td->dma_handle) != (qh->element & ~UHCI_PTR_BITS))
144
                out += sprintf26(out, "%*s Element != First TD\n", space, "");
145
 
146
        while (tmp != head) {
147
                struct uhci_td *td = list_entry(tmp, struct uhci_td, list);
148
 
149
                tmp = tmp->next;
150
 
151
                out += sprintf26(out, "%*s%d: ", space + 2, "", i++);
152
                out += uhci_show_td(td, out, len - (out - buf), 0);
153
 
154
                if (i > 10 && !checked && prevactive && tmp != head &&
155
                    debug <= 2) {
156
                        struct list_head *ntmp = tmp;
157
                        struct uhci_td *ntd = td;
158
                        int active = 1, ni = i;
159
 
160
                        checked = 1;
161
 
162
                        while (ntmp != head && ntmp->next != head && active) {
163
                                ntd = list_entry(ntmp, struct uhci_td, list);
164
 
165
                                ntmp = ntmp->next;
166
 
167
                                active = td_status(ntd) & TD_CTRL_ACTIVE;
168
 
169
                                ni++;
170
                        }
171
 
172
                        if (active && ni > i) {
173
                                out += sprintf26(out, "%*s[skipped %d active TD's]\n", space, "", ni - i);
174
                                tmp = ntmp;
175
                                td = ntd;
176
                                i = ni;
177
                        }
178
                }
179
 
180
                prevactive = td_status(td) & TD_CTRL_ACTIVE;
181
        }
182
 
183
        if (list_empty(&urbp->queue_list) || urbp->queued)
184
                goto out;
185
 
186
        out += sprintf26(out, "%*sQueued QH's:\n", -space, "--");
187
 
188
        head = &urbp->queue_list;
189
        tmp = head->next;
190
 
191
        while (tmp != head) {
192
                struct urb_priv *nurbp = list_entry(tmp, struct urb_priv,
193
                                                queue_list);
194
                tmp = tmp->next;
195
 
196
                out += uhci_show_qh(nurbp->qh, out, len - (out - buf), space);
197
        }
198
 
199
out:
200
        return out - buf;
201
}
202
 
203
#define show_frame_num()        \
204
        if (!shown) {           \
205
          shown = 1;            \
206
          out += sprintf26(out, "- Frame %d\n", i); \
207
        }
208
 
209
#ifdef CONFIG_PROC_FS
210
static const char *qh_names[] = {
211
  "skel_int128_qh", "skel_int64_qh",
212
  "skel_int32_qh", "skel_int16_qh",
213
  "skel_int8_qh", "skel_int4_qh",
214
  "skel_int2_qh", "skel_int1_qh",
215
  "skel_ls_control_qh", "skel_hs_control_qh",
216
  "skel_bulk_qh", "skel_term_qh"
217
};
218
 
219
#define show_qh_name()          \
220
        if (!shown) {           \
221
          shown = 1;            \
222
          out += sprintf26(out, "- %s\n", qh_names[i]); \
223
        }
224
 
225
static int uhci_show_sc(int port, unsigned short status, char *buf, int len)
226
{
227
        char *out = buf;
228
 
229
        /* Try to make sure there's enough memory */
230
        if (len < 80)
231
                return 0;
232
 
233
        out += sprintf26(out, "  stat%d     =     %04x   %s%s%s%s%s%s%s%s\n",
234
                port,
235
                status,
236
                (status & USBPORTSC_SUSP) ? "PortSuspend " : "",
237
                (status & USBPORTSC_PR) ?   "PortReset " : "",
238
                (status & USBPORTSC_LSDA) ? "LowSpeed " : "",
239
                (status & USBPORTSC_RD) ?   "ResumeDetect " : "",
240
                (status & USBPORTSC_PEC) ?  "EnableChange " : "",
241
                (status & USBPORTSC_PE) ?   "PortEnabled " : "",
242
                (status & USBPORTSC_CSC) ?  "ConnectChange " : "",
243
                (status & USBPORTSC_CCS) ?  "PortConnected " : "");
244
 
245
        return out - buf;
246
}
247
 
248
static int uhci_show_status(struct uhci_hcd *uhci, char *buf, int len)
249
{
250
        char *out = buf;
251
        unsigned int io_addr = uhci->io_addr;
252
        unsigned short usbcmd, usbstat, usbint, usbfrnum;
253
        unsigned int flbaseadd;
254
        unsigned char sof;
255
        unsigned short portsc1, portsc2;
256
 
257
        /* Try to make sure there's enough memory */
258
        if (len < 80 * 6)
259
                return 0;
260
 
261
        usbcmd    = inw(io_addr + 0);
262
        usbstat   = inw(io_addr + 2);
263
        usbint    = inw(io_addr + 4);
264
        usbfrnum  = inw(io_addr + 6);
265
        flbaseadd = inl(io_addr + 8);
266
        sof       = inb(io_addr + 12);
267
        portsc1   = inw(io_addr + 16);
268
        portsc2   = inw(io_addr + 18);
269
 
270
        out += sprintf26(out, "  usbcmd    =     %04x   %s%s%s%s%s%s%s%s\n",
271
                usbcmd,
272
                (usbcmd & USBCMD_MAXP) ?    "Maxp64 " : "Maxp32 ",
273
                (usbcmd & USBCMD_CF) ?      "CF " : "",
274
                (usbcmd & USBCMD_SWDBG) ?   "SWDBG " : "",
275
                (usbcmd & USBCMD_FGR) ?     "FGR " : "",
276
                (usbcmd & USBCMD_EGSM) ?    "EGSM " : "",
277
                (usbcmd & USBCMD_GRESET) ?  "GRESET " : "",
278
                (usbcmd & USBCMD_HCRESET) ? "HCRESET " : "",
279
                (usbcmd & USBCMD_RS) ?      "RS " : "");
280
 
281
        out += sprintf26(out, "  usbstat   =     %04x   %s%s%s%s%s%s\n",
282
                usbstat,
283
                (usbstat & USBSTS_HCH) ?    "HCHalted " : "",
284
                (usbstat & USBSTS_HCPE) ?   "HostControllerProcessError " : "",
285
                (usbstat & USBSTS_HSE) ?    "HostSystemError " : "",
286
                (usbstat & USBSTS_RD) ?     "ResumeDetect " : "",
287
                (usbstat & USBSTS_ERROR) ?  "USBError " : "",
288
                (usbstat & USBSTS_USBINT) ? "USBINT " : "");
289
 
290
        out += sprintf26(out, "  usbint    =     %04x\n", usbint);
291
        out += sprintf26(out, "  usbfrnum  =   (%d)%03x\n", (usbfrnum >> 10) & 1,
292
                0xfff & (4*(unsigned int)usbfrnum));
293
        out += sprintf26(out, "  flbaseadd = %08x\n", flbaseadd);
294
        out += sprintf26(out, "  sof       =       %02x\n", sof);
295
        out += uhci_show_sc(1, portsc1, out, len - (out - buf));
296
        out += uhci_show_sc(2, portsc2, out, len - (out - buf));
297
 
298
        return out - buf;
299
}
300
 
301
static int uhci_show_urbp(struct uhci_hcd *uhci, struct urb_priv *urbp, char *buf, int len)
302
{
303
        struct list_head *tmp;
304
        char *out = buf;
305
        int count = 0;
306
 
307
        if (len < 200)
308
                return 0;
309
 
310
        out += sprintf26(out, "urb_priv [%p] ", urbp);
311
        out += sprintf26(out, "urb [%p] ", urbp->urb);
312
        out += sprintf26(out, "qh [%p] ", urbp->qh);
313
        out += sprintf26(out, "Dev=%d ", usb_pipedevice(urbp->urb->pipe));
314
        out += sprintf26(out, "EP=%x(%s) ", usb_pipeendpoint(urbp->urb->pipe), (usb_pipein(urbp->urb->pipe) ? "IN" : "OUT"));
315
 
316
        switch (usb_pipetype(urbp->urb->pipe)) {
317
        case PIPE_ISOCHRONOUS: out += sprintf26(out, "ISO "); break;
318
        case PIPE_INTERRUPT: out += sprintf26(out, "INT "); break;
319
        case PIPE_BULK: out += sprintf26(out, "BLK "); break;
320
        case PIPE_CONTROL: out += sprintf26(out, "CTL "); break;
321
        }
322
 
323
        out += sprintf26(out, "%s", (urbp->fsbr ? "FSBR " : ""));
324
        out += sprintf26(out, "%s", (urbp->fsbr_timeout ? "FSBR_TO " : ""));
325
 
326
        if (urbp->status != -EINPROGRESS)
327
                out += sprintf26(out, "Status=%d ", urbp->status);
328
        //out += sprintf26(out, "Inserttime=%lx ",urbp->inserttime);
329
        //out += sprintf26(out, "FSBRtime=%lx ",urbp->fsbrtime);
330
 
331
        spin_lock(&urbp->urb->lock);
332
        count = 0;
333
        list_for_each(tmp, &urbp->td_list)
334
                count++;
335
        spin_unlock(&urbp->urb->lock);
336
        out += sprintf26(out, "TDs=%d ",count);
337
 
338
        if (urbp->queued)
339
                out += sprintf26(out, "queued\n");
340
        else {
341
                spin_lock(&uhci->frame_list_lock);
342
                count = 0;
343
                list_for_each(tmp, &urbp->queue_list)
344
                        count++;
345
                spin_unlock(&uhci->frame_list_lock);
346
                out += sprintf26(out, "queued URBs=%d\n", count);
347
        }
348
 
349
        return out - buf;
350
}
351
 
352
static int uhci_show_lists(struct uhci_hcd *uhci, char *buf, int len)
353
{
354
        char *out = buf;
355
        unsigned long flags;
356
        struct list_head *head, *tmp;
357
        int count;
358
 
359
        out += sprintf26(out, "Main list URBs:");
360
        spin_lock_irqsave(&uhci->urb_list_lock, flags);
361
        if (list_empty(&uhci->urb_list))
362
                out += sprintf26(out, " Empty\n");
363
        else {
364
                out += sprintf26(out, "\n");
365
                count = 0;
366
                head = &uhci->urb_list;
367
                tmp = head->next;
368
                while (tmp != head) {
369
                        struct urb_priv *urbp = list_entry(tmp, struct urb_priv, urb_list);
370
 
371
                        out += sprintf26(out, "  %d: ", ++count);
372
                        out += uhci_show_urbp(uhci, urbp, out, len - (out - buf));
373
                        tmp = tmp->next;
374
                }
375
        }
376
        spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
377
 
378
        out += sprintf26(out, "Remove list URBs:");
379
        spin_lock_irqsave(&uhci->urb_remove_list_lock, flags);
380
        if (list_empty(&uhci->urb_remove_list))
381
                out += sprintf26(out, " Empty\n");
382
        else {
383
                out += sprintf26(out, "\n");
384
                count = 0;
385
                head = &uhci->urb_remove_list;
386
                tmp = head->next;
387
                while (tmp != head) {
388
                        struct urb_priv *urbp = list_entry(tmp, struct urb_priv, urb_list);
389
 
390
                        out += sprintf26(out, "  %d: ", ++count);
391
                        out += uhci_show_urbp(uhci, urbp, out, len - (out - buf));
392
                        tmp = tmp->next;
393
                }
394
        }
395
        spin_unlock_irqrestore(&uhci->urb_remove_list_lock, flags);
396
 
397
        out += sprintf26(out, "Complete list URBs:");
398
        spin_lock_irqsave(&uhci->complete_list_lock, flags);
399
        if (list_empty(&uhci->complete_list))
400
                out += sprintf26(out, " Empty\n");
401
        else {
402
                out += sprintf26(out, "\n");
403
                count = 0;
404
                head = &uhci->complete_list;
405
                tmp = head->next;
406
                while (tmp != head) {
407
                        struct urb_priv *urbp = list_entry(tmp, struct urb_priv, complete_list);
408
 
409
                        out += sprintf26(out, "  %d: ", ++count);
410
                        out += uhci_show_urbp(uhci, urbp, out, len - (out - buf));
411
                        tmp = tmp->next;
412
                }
413
        }
414
        spin_unlock_irqrestore(&uhci->complete_list_lock, flags);
415
 
416
        return out - buf;
417
}
418
 
419
static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len)
420
{
421
        unsigned long flags;
422
        char *out = buf;
423
        int i;
424
        struct uhci_qh *qh;
425
        struct uhci_td *td;
426
        struct list_head *tmp, *head;
427
 
428
        spin_lock_irqsave(&uhci->frame_list_lock, flags);
429
 
430
        out += sprintf26(out, "HC status\n");
431
        out += uhci_show_status(uhci, out, len - (out - buf));
432
 
433
        out += sprintf26(out, "Frame List\n");
434
        for (i = 0; i < UHCI_NUMFRAMES; ++i) {
435
                int shown = 0;
436
                td = uhci->fl->frame_cpu[i];
437
                if (!td)
438
                        continue;
439
 
440
                if (td->dma_handle != (dma_addr_t)uhci->fl->frame[i]) {
441
                        show_frame_num();
442
                        out += sprintf26(out, "    frame list does not match td->dma_handle!\n");
443
                }
444
                show_frame_num();
445
 
446
                head = &td->fl_list;
447
                tmp = head;
448
                do {
449
                        td = list_entry(tmp, struct uhci_td, fl_list);
450
                        tmp = tmp->next;
451
                        out += uhci_show_td(td, out, len - (out - buf), 4);
452
                } while (tmp != head);
453
        }
454
 
455
        out += sprintf26(out, "Skeleton QH's\n");
456
 
457
        for (i = 0; i < UHCI_NUM_SKELQH; ++i) {
458
                int shown = 0;
459
 
460
                qh = uhci->skelqh[i];
461
 
462
                if (debug > 1) {
463
                        show_qh_name();
464
                        out += uhci_show_qh(qh, out, len - (out - buf), 4);
465
                }
466
 
467
                /* Last QH is the Terminating QH, it's different */
468
                if (i == UHCI_NUM_SKELQH - 1) {
469
                        if (qh->link != UHCI_PTR_TERM)
470
                                out += sprintf26(out, "    bandwidth reclamation on!\n");
471
 
472
                        if (qh->element != cpu_to_le32(uhci->term_td->dma_handle))
473
                                out += sprintf26(out, "    skel_term_qh element is not set to term_td!\n");
474
 
475
                        continue;
476
                }
477
 
478
                if (list_empty(&qh->list)) {
479
                        if (i < UHCI_NUM_SKELQH - 1) {
480
                                if (qh->link !=
481
                                    (cpu_to_le32(uhci->skelqh[i + 1]->dma_handle) | UHCI_PTR_QH)) {
482
                                        show_qh_name();
483
                                        out += sprintf26(out, "    skeleton QH not linked to next skeleton QH!\n");
484
                                }
485
                        }
486
 
487
                        continue;
488
                }
489
 
490
                show_qh_name();
491
 
492
                head = &qh->list;
493
                tmp = head->next;
494
 
495
                while (tmp != head) {
496
                        qh = list_entry(tmp, struct uhci_qh, list);
497
 
498
                        tmp = tmp->next;
499
 
500
                        out += uhci_show_qh(qh, out, len - (out - buf), 4);
501
                }
502
 
503
                if (i < UHCI_NUM_SKELQH - 1) {
504
                        if (qh->link !=
505
                            (cpu_to_le32(uhci->skelqh[i + 1]->dma_handle) | UHCI_PTR_QH))
506
                                out += sprintf26(out, "    last QH not linked to next skeleton!\n");
507
                }
508
        }
509
 
510
        spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
511
 
512
        if (debug > 2)
513
                out += uhci_show_lists(uhci, out, len - (out - buf));
514
 
515
        return out - buf;
516
}
517
 
518
#define MAX_OUTPUT      (64 * 1024)
519
 
520
static struct proc_dir_entry *uhci_proc_root = NULL;
521
 
522
struct uhci_proc {
523
        int size;
524
        char *data;
525
        struct uhci_hcd *uhci;
526
};
527
 
528
static int uhci_proc_open(struct inode *inode, struct file *file)
529
{
530
        const struct proc_dir_entry *dp = PDE(inode);
531
        struct uhci_hcd *uhci = dp->data;
532
        struct uhci_proc *up;
533
        int ret = -ENOMEM;
534
 
535
        lock_kernel();
536
        up = kmalloc(sizeof(*up), GFP_KERNEL);
537
        if (!up)
538
                goto out;
539
 
540
        up->data = kmalloc(MAX_OUTPUT, GFP_KERNEL);
541
        if (!up->data) {
542
                kfree(up);
543
                goto out;
544
        }
545
 
546
        up->size = uhci_sprint_schedule(uhci, up->data, MAX_OUTPUT);
547
 
548
        file->private_data = up;
549
 
550
        ret = 0;
551
out:
552
        unlock_kernel();
553
        return ret;
554
}
555
 
556
static loff_t uhci_proc_lseek(struct file *file, loff_t off, int whence)
557
{
558
        struct uhci_proc *up;
559
        loff_t new = -1;
560
 
561
        lock_kernel();
562
        up = file->private_data;
563
 
564
        switch (whence) {
565
        case 0:
566
                new = off;
567
                break;
568
        case 1:
569
                new = file->f_pos + off;
570
                break;
571
        }
572
        if (new < 0 || new > up->size) {
573
                unlock_kernel();
574
                return -EINVAL;
575
        }
576
        unlock_kernel();
577
        return (file->f_pos = new);
578
}
579
 
580
static ssize_t uhci_proc_read(struct file *file, char *buf, size_t nbytes,
581
                        loff_t *ppos)
582
{
583
        struct uhci_proc *up = file->private_data;
584
        unsigned int pos;
585
        unsigned int size;
586
 
587
        pos = *ppos;
588
        size = up->size;
589
        if (pos >= size)
590
                return 0;
591
        if (nbytes >= size)
592
                nbytes = size;
593
        if (pos + nbytes > size)
594
                nbytes = size - pos;
595
 
596
        if (!access_ok(VERIFY_WRITE, buf, nbytes))
597
                return -EINVAL;
598
 
599
        if (copy_to_user(buf, up->data + pos, nbytes))
600
                return -EFAULT;
601
 
602
        *ppos += nbytes;
603
 
604
        return nbytes;
605
}
606
 
607
static int uhci_proc_release(struct inode *inode, struct file *file)
608
{
609
        struct uhci_proc *up = file->private_data;
610
 
611
        kfree(up->data);
612
        kfree(up);
613
 
614
        return 0;
615
}
616
 
617
static struct file_operations uhci_proc_operations = {
618
        .open =         uhci_proc_open,
619
        .llseek =       uhci_proc_lseek,
620
        .read =         uhci_proc_read,
621
//      write:          uhci_proc_write,
622
        .release =      uhci_proc_release,
623
};
624
#endif
625