0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013 #include <linux/slab.h>
0014 #include <linux/kernel.h>
0015 #include <linux/debugfs.h>
0016 #include <asm/io.h>
0017
0018 #include "uhci-hcd.h"
0019
0020 #define EXTRA_SPACE 1024
0021
0022 static struct dentry *uhci_debugfs_root;
0023
0024 #ifdef CONFIG_DYNAMIC_DEBUG
0025
0026
0027 static void lprintk(char *buf)
0028 {
0029 char *p;
0030
0031
0032 while (buf) {
0033 p = strchr(buf, '\n');
0034 if (p)
0035 *p = 0;
0036 printk(KERN_DEBUG "%s\n", buf);
0037 buf = p;
0038 if (buf)
0039 buf++;
0040 }
0041 }
0042
0043 static int uhci_show_td(struct uhci_hcd *uhci, struct uhci_td *td, char *buf,
0044 int len, int space)
0045 {
0046 char *out = buf;
0047 char *spid;
0048 u32 status, token;
0049
0050 status = td_status(uhci, td);
0051 out += sprintf(out, "%*s[%p] link (%08x) ", space, "", td,
0052 hc32_to_cpu(uhci, td->link));
0053 out += sprintf(out, "e%d %s%s%s%s%s%s%s%s%s%sLength=%x ",
0054 ((status >> 27) & 3),
0055 (status & TD_CTRL_SPD) ? "SPD " : "",
0056 (status & TD_CTRL_LS) ? "LS " : "",
0057 (status & TD_CTRL_IOC) ? "IOC " : "",
0058 (status & TD_CTRL_ACTIVE) ? "Active " : "",
0059 (status & TD_CTRL_STALLED) ? "Stalled " : "",
0060 (status & TD_CTRL_DBUFERR) ? "DataBufErr " : "",
0061 (status & TD_CTRL_BABBLE) ? "Babble " : "",
0062 (status & TD_CTRL_NAK) ? "NAK " : "",
0063 (status & TD_CTRL_CRCTIMEO) ? "CRC/Timeo " : "",
0064 (status & TD_CTRL_BITSTUFF) ? "BitStuff " : "",
0065 status & 0x7ff);
0066 if (out - buf > len)
0067 goto done;
0068
0069 token = td_token(uhci, td);
0070 switch (uhci_packetid(token)) {
0071 case USB_PID_SETUP:
0072 spid = "SETUP";
0073 break;
0074 case USB_PID_OUT:
0075 spid = "OUT";
0076 break;
0077 case USB_PID_IN:
0078 spid = "IN";
0079 break;
0080 default:
0081 spid = "?";
0082 break;
0083 }
0084
0085 out += sprintf(out, "MaxLen=%x DT%d EndPt=%x Dev=%x, PID=%x(%s) ",
0086 token >> 21,
0087 ((token >> 19) & 1),
0088 (token >> 15) & 15,
0089 (token >> 8) & 127,
0090 (token & 0xff),
0091 spid);
0092 out += sprintf(out, "(buf=%08x)\n", hc32_to_cpu(uhci, td->buffer));
0093
0094 done:
0095 if (out - buf > len)
0096 out += sprintf(out, " ...\n");
0097 return out - buf;
0098 }
0099
0100 static int uhci_show_urbp(struct uhci_hcd *uhci, struct urb_priv *urbp,
0101 char *buf, int len, int space)
0102 {
0103 char *out = buf;
0104 struct uhci_td *td;
0105 int i, nactive, ninactive;
0106 char *ptype;
0107
0108
0109 out += sprintf(out, "urb_priv [%p] ", urbp);
0110 out += sprintf(out, "urb [%p] ", urbp->urb);
0111 out += sprintf(out, "qh [%p] ", urbp->qh);
0112 out += sprintf(out, "Dev=%d ", usb_pipedevice(urbp->urb->pipe));
0113 out += sprintf(out, "EP=%x(%s) ", usb_pipeendpoint(urbp->urb->pipe),
0114 (usb_pipein(urbp->urb->pipe) ? "IN" : "OUT"));
0115 if (out - buf > len)
0116 goto done;
0117
0118 switch (usb_pipetype(urbp->urb->pipe)) {
0119 case PIPE_ISOCHRONOUS: ptype = "ISO"; break;
0120 case PIPE_INTERRUPT: ptype = "INT"; break;
0121 case PIPE_BULK: ptype = "BLK"; break;
0122 default:
0123 case PIPE_CONTROL: ptype = "CTL"; break;
0124 }
0125
0126 out += sprintf(out, "%s%s", ptype, (urbp->fsbr ? " FSBR" : ""));
0127 out += sprintf(out, " Actlen=%d%s", urbp->urb->actual_length,
0128 (urbp->qh->type == USB_ENDPOINT_XFER_CONTROL ?
0129 "-8" : ""));
0130
0131 if (urbp->urb->unlinked)
0132 out += sprintf(out, " Unlinked=%d", urbp->urb->unlinked);
0133 out += sprintf(out, "\n");
0134
0135 if (out - buf > len)
0136 goto done;
0137
0138 i = nactive = ninactive = 0;
0139 list_for_each_entry(td, &urbp->td_list, list) {
0140 if (urbp->qh->type != USB_ENDPOINT_XFER_ISOC &&
0141 (++i <= 10 || debug > 2)) {
0142 out += sprintf(out, "%*s%d: ", space + 2, "", i);
0143 out += uhci_show_td(uhci, td, out,
0144 len - (out - buf), 0);
0145 if (out - buf > len)
0146 goto tail;
0147 } else {
0148 if (td_status(uhci, td) & TD_CTRL_ACTIVE)
0149 ++nactive;
0150 else
0151 ++ninactive;
0152 }
0153 }
0154 if (nactive + ninactive > 0)
0155 out += sprintf(out,
0156 "%*s[skipped %d inactive and %d active TDs]\n",
0157 space, "", ninactive, nactive);
0158 done:
0159 if (out - buf > len)
0160 out += sprintf(out, " ...\n");
0161 tail:
0162 return out - buf;
0163 }
0164
0165 static int uhci_show_qh(struct uhci_hcd *uhci,
0166 struct uhci_qh *qh, char *buf, int len, int space)
0167 {
0168 char *out = buf;
0169 int i, nurbs;
0170 __hc32 element = qh_element(qh);
0171 char *qtype;
0172
0173 switch (qh->type) {
0174 case USB_ENDPOINT_XFER_ISOC: qtype = "ISO"; break;
0175 case USB_ENDPOINT_XFER_INT: qtype = "INT"; break;
0176 case USB_ENDPOINT_XFER_BULK: qtype = "BLK"; break;
0177 case USB_ENDPOINT_XFER_CONTROL: qtype = "CTL"; break;
0178 default: qtype = "Skel" ; break;
0179 }
0180
0181 out += sprintf(out, "%*s[%p] %s QH link (%08x) element (%08x)\n",
0182 space, "", qh, qtype,
0183 hc32_to_cpu(uhci, qh->link),
0184 hc32_to_cpu(uhci, element));
0185 if (qh->type == USB_ENDPOINT_XFER_ISOC)
0186 out += sprintf(out,
0187 "%*s period %d phase %d load %d us, frame %x desc [%p]\n",
0188 space, "", qh->period, qh->phase, qh->load,
0189 qh->iso_frame, qh->iso_packet_desc);
0190 else if (qh->type == USB_ENDPOINT_XFER_INT)
0191 out += sprintf(out, "%*s period %d phase %d load %d us\n",
0192 space, "", qh->period, qh->phase, qh->load);
0193 if (out - buf > len)
0194 goto done;
0195
0196 if (element & UHCI_PTR_QH(uhci))
0197 out += sprintf(out, "%*s Element points to QH (bug?)\n", space, "");
0198
0199 if (element & UHCI_PTR_DEPTH(uhci))
0200 out += sprintf(out, "%*s Depth traverse\n", space, "");
0201
0202 if (element & cpu_to_hc32(uhci, 8))
0203 out += sprintf(out, "%*s Bit 3 set (bug?)\n", space, "");
0204
0205 if (!(element & ~(UHCI_PTR_QH(uhci) | UHCI_PTR_DEPTH(uhci))))
0206 out += sprintf(out, "%*s Element is NULL (bug?)\n", space, "");
0207
0208 if (out - buf > len)
0209 goto done;
0210
0211 if (list_empty(&qh->queue)) {
0212 out += sprintf(out, "%*s queue is empty\n", space, "");
0213 if (qh == uhci->skel_async_qh) {
0214 out += uhci_show_td(uhci, uhci->term_td, out,
0215 len - (out - buf), 0);
0216 if (out - buf > len)
0217 goto tail;
0218 }
0219 } else {
0220 struct urb_priv *urbp = list_entry(qh->queue.next,
0221 struct urb_priv, node);
0222 struct uhci_td *td = list_entry(urbp->td_list.next,
0223 struct uhci_td, list);
0224
0225 if (element != LINK_TO_TD(uhci, td))
0226 out += sprintf(out, "%*s Element != First TD\n",
0227 space, "");
0228 i = nurbs = 0;
0229 list_for_each_entry(urbp, &qh->queue, node) {
0230 if (++i <= 10) {
0231 out += uhci_show_urbp(uhci, urbp, out,
0232 len - (out - buf), space + 2);
0233 if (out - buf > len)
0234 goto tail;
0235 }
0236 else
0237 ++nurbs;
0238 }
0239 if (nurbs > 0)
0240 out += sprintf(out, "%*s Skipped %d URBs\n",
0241 space, "", nurbs);
0242 }
0243
0244 if (out - buf > len)
0245 goto done;
0246
0247 if (qh->dummy_td) {
0248 out += sprintf(out, "%*s Dummy TD\n", space, "");
0249 out += uhci_show_td(uhci, qh->dummy_td, out,
0250 len - (out - buf), 0);
0251 if (out - buf > len)
0252 goto tail;
0253 }
0254
0255 done:
0256 if (out - buf > len)
0257 out += sprintf(out, " ...\n");
0258 tail:
0259 return out - buf;
0260 }
0261
0262 static int uhci_show_sc(int port, unsigned short status, char *buf)
0263 {
0264 return sprintf(buf, " stat%d = %04x %s%s%s%s%s%s%s%s%s%s\n",
0265 port,
0266 status,
0267 (status & USBPORTSC_SUSP) ? " Suspend" : "",
0268 (status & USBPORTSC_OCC) ? " OverCurrentChange" : "",
0269 (status & USBPORTSC_OC) ? " OverCurrent" : "",
0270 (status & USBPORTSC_PR) ? " Reset" : "",
0271 (status & USBPORTSC_LSDA) ? " LowSpeed" : "",
0272 (status & USBPORTSC_RD) ? " ResumeDetect" : "",
0273 (status & USBPORTSC_PEC) ? " EnableChange" : "",
0274 (status & USBPORTSC_PE) ? " Enabled" : "",
0275 (status & USBPORTSC_CSC) ? " ConnectChange" : "",
0276 (status & USBPORTSC_CCS) ? " Connected" : "");
0277 }
0278
0279 static int uhci_show_root_hub_state(struct uhci_hcd *uhci, char *buf)
0280 {
0281 char *rh_state;
0282
0283 switch (uhci->rh_state) {
0284 case UHCI_RH_RESET:
0285 rh_state = "reset"; break;
0286 case UHCI_RH_SUSPENDED:
0287 rh_state = "suspended"; break;
0288 case UHCI_RH_AUTO_STOPPED:
0289 rh_state = "auto-stopped"; break;
0290 case UHCI_RH_RESUMING:
0291 rh_state = "resuming"; break;
0292 case UHCI_RH_SUSPENDING:
0293 rh_state = "suspending"; break;
0294 case UHCI_RH_RUNNING:
0295 rh_state = "running"; break;
0296 case UHCI_RH_RUNNING_NODEVS:
0297 rh_state = "running, no devs"; break;
0298 default:
0299 rh_state = "?"; break;
0300 }
0301 return sprintf(buf, "Root-hub state: %s FSBR: %d\n",
0302 rh_state, uhci->fsbr_is_on);
0303 }
0304
0305 static int uhci_show_status(struct uhci_hcd *uhci, char *buf, int len)
0306 {
0307 char *out = buf;
0308 unsigned short usbcmd, usbstat, usbint, usbfrnum;
0309 unsigned int flbaseadd;
0310 unsigned char sof;
0311 unsigned short portsc1, portsc2;
0312
0313
0314 usbcmd = uhci_readw(uhci, USBCMD);
0315 usbstat = uhci_readw(uhci, USBSTS);
0316 usbint = uhci_readw(uhci, USBINTR);
0317 usbfrnum = uhci_readw(uhci, USBFRNUM);
0318 flbaseadd = uhci_readl(uhci, USBFLBASEADD);
0319 sof = uhci_readb(uhci, USBSOF);
0320 portsc1 = uhci_readw(uhci, USBPORTSC1);
0321 portsc2 = uhci_readw(uhci, USBPORTSC2);
0322
0323 out += sprintf(out, " usbcmd = %04x %s%s%s%s%s%s%s%s\n",
0324 usbcmd,
0325 (usbcmd & USBCMD_MAXP) ? "Maxp64 " : "Maxp32 ",
0326 (usbcmd & USBCMD_CF) ? "CF " : "",
0327 (usbcmd & USBCMD_SWDBG) ? "SWDBG " : "",
0328 (usbcmd & USBCMD_FGR) ? "FGR " : "",
0329 (usbcmd & USBCMD_EGSM) ? "EGSM " : "",
0330 (usbcmd & USBCMD_GRESET) ? "GRESET " : "",
0331 (usbcmd & USBCMD_HCRESET) ? "HCRESET " : "",
0332 (usbcmd & USBCMD_RS) ? "RS " : "");
0333 if (out - buf > len)
0334 goto done;
0335
0336 out += sprintf(out, " usbstat = %04x %s%s%s%s%s%s\n",
0337 usbstat,
0338 (usbstat & USBSTS_HCH) ? "HCHalted " : "",
0339 (usbstat & USBSTS_HCPE) ? "HostControllerProcessError " : "",
0340 (usbstat & USBSTS_HSE) ? "HostSystemError " : "",
0341 (usbstat & USBSTS_RD) ? "ResumeDetect " : "",
0342 (usbstat & USBSTS_ERROR) ? "USBError " : "",
0343 (usbstat & USBSTS_USBINT) ? "USBINT " : "");
0344 if (out - buf > len)
0345 goto done;
0346
0347 out += sprintf(out, " usbint = %04x\n", usbint);
0348 out += sprintf(out, " usbfrnum = (%d)%03x\n", (usbfrnum >> 10) & 1,
0349 0xfff & (4*(unsigned int)usbfrnum));
0350 out += sprintf(out, " flbaseadd = %08x\n", flbaseadd);
0351 out += sprintf(out, " sof = %02x\n", sof);
0352 if (out - buf > len)
0353 goto done;
0354
0355 out += uhci_show_sc(1, portsc1, out);
0356 if (out - buf > len)
0357 goto done;
0358
0359 out += uhci_show_sc(2, portsc2, out);
0360 if (out - buf > len)
0361 goto done;
0362
0363 out += sprintf(out,
0364 "Most recent frame: %x (%d) Last ISO frame: %x (%d)\n",
0365 uhci->frame_number, uhci->frame_number & 1023,
0366 uhci->last_iso_frame, uhci->last_iso_frame & 1023);
0367
0368 done:
0369 if (out - buf > len)
0370 out += sprintf(out, " ...\n");
0371 return out - buf;
0372 }
0373
0374 static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len)
0375 {
0376 char *out = buf;
0377 int i, j;
0378 struct uhci_qh *qh;
0379 struct uhci_td *td;
0380 struct list_head *tmp, *head;
0381 int nframes, nerrs;
0382 __hc32 link;
0383 __hc32 fsbr_link;
0384
0385 static const char * const qh_names[] = {
0386 "unlink", "iso", "int128", "int64", "int32", "int16",
0387 "int8", "int4", "int2", "async", "term"
0388 };
0389
0390 out += uhci_show_root_hub_state(uhci, out);
0391 if (out - buf > len)
0392 goto done;
0393 out += sprintf(out, "HC status\n");
0394 out += uhci_show_status(uhci, out, len - (out - buf));
0395 if (out - buf > len)
0396 goto tail;
0397
0398 out += sprintf(out, "Periodic load table\n");
0399 for (i = 0; i < MAX_PHASE; ++i) {
0400 out += sprintf(out, "\t%d", uhci->load[i]);
0401 if (i % 8 == 7)
0402 *out++ = '\n';
0403 }
0404 out += sprintf(out, "Total: %d, #INT: %d, #ISO: %d\n",
0405 uhci->total_load,
0406 uhci_to_hcd(uhci)->self.bandwidth_int_reqs,
0407 uhci_to_hcd(uhci)->self.bandwidth_isoc_reqs);
0408 if (debug <= 1)
0409 goto tail;
0410
0411 out += sprintf(out, "Frame List\n");
0412 nframes = 10;
0413 nerrs = 0;
0414 for (i = 0; i < UHCI_NUMFRAMES; ++i) {
0415 __hc32 qh_dma;
0416
0417 if (out - buf > len)
0418 goto done;
0419 j = 0;
0420 td = uhci->frame_cpu[i];
0421 link = uhci->frame[i];
0422 if (!td)
0423 goto check_link;
0424
0425 if (nframes > 0) {
0426 out += sprintf(out, "- Frame %d -> (%08x)\n",
0427 i, hc32_to_cpu(uhci, link));
0428 j = 1;
0429 }
0430
0431 head = &td->fl_list;
0432 tmp = head;
0433 do {
0434 td = list_entry(tmp, struct uhci_td, fl_list);
0435 tmp = tmp->next;
0436 if (link != LINK_TO_TD(uhci, td)) {
0437 if (nframes > 0) {
0438 out += sprintf(out,
0439 " link does not match list entry!\n");
0440 if (out - buf > len)
0441 goto done;
0442 } else
0443 ++nerrs;
0444 }
0445 if (nframes > 0) {
0446 out += uhci_show_td(uhci, td, out,
0447 len - (out - buf), 4);
0448 if (out - buf > len)
0449 goto tail;
0450 }
0451 link = td->link;
0452 } while (tmp != head);
0453
0454 check_link:
0455 qh_dma = uhci_frame_skel_link(uhci, i);
0456 if (link != qh_dma) {
0457 if (nframes > 0) {
0458 if (!j) {
0459 out += sprintf(out,
0460 "- Frame %d -> (%08x)\n",
0461 i, hc32_to_cpu(uhci, link));
0462 j = 1;
0463 }
0464 out += sprintf(out,
0465 " link does not match QH (%08x)!\n",
0466 hc32_to_cpu(uhci, qh_dma));
0467 if (out - buf > len)
0468 goto done;
0469 } else
0470 ++nerrs;
0471 }
0472 nframes -= j;
0473 }
0474 if (nerrs > 0)
0475 out += sprintf(out, "Skipped %d bad links\n", nerrs);
0476
0477 out += sprintf(out, "Skeleton QHs\n");
0478
0479 if (out - buf > len)
0480 goto done;
0481
0482 fsbr_link = 0;
0483 for (i = 0; i < UHCI_NUM_SKELQH; ++i) {
0484 int cnt = 0;
0485
0486 qh = uhci->skelqh[i];
0487 out += sprintf(out, "- skel_%s_qh\n", qh_names[i]);
0488 out += uhci_show_qh(uhci, qh, out, len - (out - buf), 4);
0489 if (out - buf > len)
0490 goto tail;
0491
0492
0493 if (i == SKEL_TERM) {
0494 if (qh_element(qh) != LINK_TO_TD(uhci, uhci->term_td)) {
0495 out += sprintf(out,
0496 " skel_term_qh element is not set to term_td!\n");
0497 if (out - buf > len)
0498 goto done;
0499 }
0500 link = fsbr_link;
0501 if (!link)
0502 link = LINK_TO_QH(uhci, uhci->skel_term_qh);
0503 goto check_qh_link;
0504 }
0505
0506 head = &qh->node;
0507 tmp = head->next;
0508
0509 while (tmp != head) {
0510 qh = list_entry(tmp, struct uhci_qh, node);
0511 tmp = tmp->next;
0512 if (++cnt <= 10) {
0513 out += uhci_show_qh(uhci, qh, out,
0514 len - (out - buf), 4);
0515 if (out - buf > len)
0516 goto tail;
0517 }
0518 if (!fsbr_link && qh->skel >= SKEL_FSBR)
0519 fsbr_link = LINK_TO_QH(uhci, qh);
0520 }
0521 if ((cnt -= 10) > 0)
0522 out += sprintf(out, " Skipped %d QHs\n", cnt);
0523
0524 link = UHCI_PTR_TERM(uhci);
0525 if (i <= SKEL_ISO)
0526 ;
0527 else if (i < SKEL_ASYNC)
0528 link = LINK_TO_QH(uhci, uhci->skel_async_qh);
0529 else if (!uhci->fsbr_is_on)
0530 ;
0531 else
0532 link = LINK_TO_QH(uhci, uhci->skel_term_qh);
0533 check_qh_link:
0534 if (qh->link != link)
0535 out += sprintf(out,
0536 " last QH not linked to next skeleton!\n");
0537
0538 if (out - buf > len)
0539 goto done;
0540 }
0541
0542 done:
0543 if (out - buf > len)
0544 out += sprintf(out, " ...\n");
0545 tail:
0546 return out - buf;
0547 }
0548
0549 #ifdef CONFIG_DEBUG_FS
0550
0551 #define MAX_OUTPUT (64 * 1024)
0552
0553 struct uhci_debug {
0554 int size;
0555 char *data;
0556 };
0557
0558 static int uhci_debug_open(struct inode *inode, struct file *file)
0559 {
0560 struct uhci_hcd *uhci = inode->i_private;
0561 struct uhci_debug *up;
0562 unsigned long flags;
0563
0564 up = kmalloc(sizeof(*up), GFP_KERNEL);
0565 if (!up)
0566 return -ENOMEM;
0567
0568 up->data = kmalloc(MAX_OUTPUT, GFP_KERNEL);
0569 if (!up->data) {
0570 kfree(up);
0571 return -ENOMEM;
0572 }
0573
0574 up->size = 0;
0575 spin_lock_irqsave(&uhci->lock, flags);
0576 if (uhci->is_initialized)
0577 up->size = uhci_sprint_schedule(uhci, up->data,
0578 MAX_OUTPUT - EXTRA_SPACE);
0579 spin_unlock_irqrestore(&uhci->lock, flags);
0580
0581 file->private_data = up;
0582
0583 return 0;
0584 }
0585
0586 static loff_t uhci_debug_lseek(struct file *file, loff_t off, int whence)
0587 {
0588 struct uhci_debug *up = file->private_data;
0589 return no_seek_end_llseek_size(file, off, whence, up->size);
0590 }
0591
0592 static ssize_t uhci_debug_read(struct file *file, char __user *buf,
0593 size_t nbytes, loff_t *ppos)
0594 {
0595 struct uhci_debug *up = file->private_data;
0596 return simple_read_from_buffer(buf, nbytes, ppos, up->data, up->size);
0597 }
0598
0599 static int uhci_debug_release(struct inode *inode, struct file *file)
0600 {
0601 struct uhci_debug *up = file->private_data;
0602
0603 kfree(up->data);
0604 kfree(up);
0605
0606 return 0;
0607 }
0608
0609 static const struct file_operations uhci_debug_operations = {
0610 .owner = THIS_MODULE,
0611 .open = uhci_debug_open,
0612 .llseek = uhci_debug_lseek,
0613 .read = uhci_debug_read,
0614 .release = uhci_debug_release,
0615 };
0616 #define UHCI_DEBUG_OPS
0617
0618 #endif
0619
0620 #else
0621
0622 static inline void lprintk(char *buf)
0623 {}
0624
0625 static inline int uhci_show_qh(struct uhci_hcd *uhci,
0626 struct uhci_qh *qh, char *buf, int len, int space)
0627 {
0628 return 0;
0629 }
0630
0631 static inline int uhci_sprint_schedule(struct uhci_hcd *uhci,
0632 char *buf, int len)
0633 {
0634 return 0;
0635 }
0636
0637 #endif