1*b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds * UHCI-specific debugging code. Invaluable when something
41da177e4SLinus Torvalds * goes wrong, but don't get in my face.
51da177e4SLinus Torvalds *
6687f5f34SAlan Stern * Kernel visible pointers are surrounded in []s and bus
7687f5f34SAlan Stern * visible pointers are surrounded in ()s
81da177e4SLinus Torvalds *
91da177e4SLinus Torvalds * (C) Copyright 1999 Linus Torvalds
101da177e4SLinus Torvalds * (C) Copyright 1999-2001 Johannes Erdfelt
111da177e4SLinus Torvalds */
121da177e4SLinus Torvalds
135a0e3ad6STejun Heo #include <linux/slab.h>
141da177e4SLinus Torvalds #include <linux/kernel.h>
151da177e4SLinus Torvalds #include <linux/debugfs.h>
161da177e4SLinus Torvalds #include <asm/io.h>
171da177e4SLinus Torvalds
181da177e4SLinus Torvalds #include "uhci-hcd.h"
191da177e4SLinus Torvalds
2013996ca7SChen Gang #define EXTRA_SPACE 1024
2113996ca7SChen Gang
228d402e1aSAlan Stern static struct dentry *uhci_debugfs_root;
238d402e1aSAlan Stern
241c20163dSOliver Neukum #ifdef CONFIG_DYNAMIC_DEBUG
251da177e4SLinus Torvalds
26687f5f34SAlan Stern /* Handle REALLY large printks so we don't overflow buffers */
lprintk(char * buf)278d402e1aSAlan Stern static void lprintk(char *buf)
281da177e4SLinus Torvalds {
291da177e4SLinus Torvalds char *p;
301da177e4SLinus Torvalds
311da177e4SLinus Torvalds /* Just write one line at a time */
321da177e4SLinus Torvalds while (buf) {
331da177e4SLinus Torvalds p = strchr(buf, '\n');
341da177e4SLinus Torvalds if (p)
351da177e4SLinus Torvalds *p = 0;
361da177e4SLinus Torvalds printk(KERN_DEBUG "%s\n", buf);
371da177e4SLinus Torvalds buf = p;
381da177e4SLinus Torvalds if (buf)
391da177e4SLinus Torvalds buf++;
401da177e4SLinus Torvalds }
411da177e4SLinus Torvalds }
421da177e4SLinus Torvalds
uhci_show_td(struct uhci_hcd * uhci,struct uhci_td * td,char * buf,int len,int space)4351e2f62fSJan Andersson static int uhci_show_td(struct uhci_hcd *uhci, struct uhci_td *td, char *buf,
4451e2f62fSJan Andersson int len, int space)
451da177e4SLinus Torvalds {
461da177e4SLinus Torvalds char *out = buf;
471da177e4SLinus Torvalds char *spid;
481da177e4SLinus Torvalds u32 status, token;
491da177e4SLinus Torvalds
5051e2f62fSJan Andersson status = td_status(uhci, td);
5151e2f62fSJan Andersson out += sprintf(out, "%*s[%p] link (%08x) ", space, "", td,
5251e2f62fSJan Andersson hc32_to_cpu(uhci, td->link));
531da177e4SLinus Torvalds out += sprintf(out, "e%d %s%s%s%s%s%s%s%s%s%sLength=%x ",
541da177e4SLinus Torvalds ((status >> 27) & 3),
551da177e4SLinus Torvalds (status & TD_CTRL_SPD) ? "SPD " : "",
561da177e4SLinus Torvalds (status & TD_CTRL_LS) ? "LS " : "",
571da177e4SLinus Torvalds (status & TD_CTRL_IOC) ? "IOC " : "",
581da177e4SLinus Torvalds (status & TD_CTRL_ACTIVE) ? "Active " : "",
591da177e4SLinus Torvalds (status & TD_CTRL_STALLED) ? "Stalled " : "",
601da177e4SLinus Torvalds (status & TD_CTRL_DBUFERR) ? "DataBufErr " : "",
611da177e4SLinus Torvalds (status & TD_CTRL_BABBLE) ? "Babble " : "",
621da177e4SLinus Torvalds (status & TD_CTRL_NAK) ? "NAK " : "",
631da177e4SLinus Torvalds (status & TD_CTRL_CRCTIMEO) ? "CRC/Timeo " : "",
641da177e4SLinus Torvalds (status & TD_CTRL_BITSTUFF) ? "BitStuff " : "",
651da177e4SLinus Torvalds status & 0x7ff);
6613996ca7SChen Gang if (out - buf > len)
6713996ca7SChen Gang goto done;
681da177e4SLinus Torvalds
6951e2f62fSJan Andersson token = td_token(uhci, td);
701da177e4SLinus Torvalds switch (uhci_packetid(token)) {
711da177e4SLinus Torvalds case USB_PID_SETUP:
721da177e4SLinus Torvalds spid = "SETUP";
731da177e4SLinus Torvalds break;
741da177e4SLinus Torvalds case USB_PID_OUT:
751da177e4SLinus Torvalds spid = "OUT";
761da177e4SLinus Torvalds break;
771da177e4SLinus Torvalds case USB_PID_IN:
781da177e4SLinus Torvalds spid = "IN";
791da177e4SLinus Torvalds break;
801da177e4SLinus Torvalds default:
811da177e4SLinus Torvalds spid = "?";
821da177e4SLinus Torvalds break;
831da177e4SLinus Torvalds }
841da177e4SLinus Torvalds
851da177e4SLinus Torvalds out += sprintf(out, "MaxLen=%x DT%d EndPt=%x Dev=%x, PID=%x(%s) ",
861da177e4SLinus Torvalds token >> 21,
871da177e4SLinus Torvalds ((token >> 19) & 1),
881da177e4SLinus Torvalds (token >> 15) & 15,
891da177e4SLinus Torvalds (token >> 8) & 127,
901da177e4SLinus Torvalds (token & 0xff),
911da177e4SLinus Torvalds spid);
9251e2f62fSJan Andersson out += sprintf(out, "(buf=%08x)\n", hc32_to_cpu(uhci, td->buffer));
931da177e4SLinus Torvalds
9413996ca7SChen Gang done:
9513996ca7SChen Gang if (out - buf > len)
9613996ca7SChen Gang out += sprintf(out, " ...\n");
971da177e4SLinus Torvalds return out - buf;
981da177e4SLinus Torvalds }
991da177e4SLinus Torvalds
uhci_show_urbp(struct uhci_hcd * uhci,struct urb_priv * urbp,char * buf,int len,int space)10051e2f62fSJan Andersson static int uhci_show_urbp(struct uhci_hcd *uhci, struct urb_priv *urbp,
10151e2f62fSJan Andersson char *buf, int len, int space)
102dccf4a48SAlan Stern {
103dccf4a48SAlan Stern char *out = buf;
104dccf4a48SAlan Stern struct uhci_td *td;
105dccf4a48SAlan Stern int i, nactive, ninactive;
1064de7d2c2SAlan Stern char *ptype;
107dccf4a48SAlan Stern
108dccf4a48SAlan Stern
109dccf4a48SAlan Stern out += sprintf(out, "urb_priv [%p] ", urbp);
110dccf4a48SAlan Stern out += sprintf(out, "urb [%p] ", urbp->urb);
111dccf4a48SAlan Stern out += sprintf(out, "qh [%p] ", urbp->qh);
112dccf4a48SAlan Stern out += sprintf(out, "Dev=%d ", usb_pipedevice(urbp->urb->pipe));
113dccf4a48SAlan Stern out += sprintf(out, "EP=%x(%s) ", usb_pipeendpoint(urbp->urb->pipe),
114dccf4a48SAlan Stern (usb_pipein(urbp->urb->pipe) ? "IN" : "OUT"));
11513996ca7SChen Gang if (out - buf > len)
11613996ca7SChen Gang goto done;
117dccf4a48SAlan Stern
118dccf4a48SAlan Stern switch (usb_pipetype(urbp->urb->pipe)) {
1194de7d2c2SAlan Stern case PIPE_ISOCHRONOUS: ptype = "ISO"; break;
1204de7d2c2SAlan Stern case PIPE_INTERRUPT: ptype = "INT"; break;
1214de7d2c2SAlan Stern case PIPE_BULK: ptype = "BLK"; break;
1224de7d2c2SAlan Stern default:
1234de7d2c2SAlan Stern case PIPE_CONTROL: ptype = "CTL"; break;
124dccf4a48SAlan Stern }
125dccf4a48SAlan Stern
1264de7d2c2SAlan Stern out += sprintf(out, "%s%s", ptype, (urbp->fsbr ? " FSBR" : ""));
1277ea0a2bcSAlan Stern out += sprintf(out, " Actlen=%d%s", urbp->urb->actual_length,
1287ea0a2bcSAlan Stern (urbp->qh->type == USB_ENDPOINT_XFER_CONTROL ?
1297ea0a2bcSAlan Stern "-8" : ""));
130dccf4a48SAlan Stern
131eb231054SAlan Stern if (urbp->urb->unlinked)
132eb231054SAlan Stern out += sprintf(out, " Unlinked=%d", urbp->urb->unlinked);
133dccf4a48SAlan Stern out += sprintf(out, "\n");
134dccf4a48SAlan Stern
13513996ca7SChen Gang if (out - buf > len)
13613996ca7SChen Gang goto done;
13713996ca7SChen Gang
138dccf4a48SAlan Stern i = nactive = ninactive = 0;
139dccf4a48SAlan Stern list_for_each_entry(td, &urbp->td_list, list) {
140c8155cc5SAlan Stern if (urbp->qh->type != USB_ENDPOINT_XFER_ISOC &&
141c8155cc5SAlan Stern (++i <= 10 || debug > 2)) {
142dccf4a48SAlan Stern out += sprintf(out, "%*s%d: ", space + 2, "", i);
14351e2f62fSJan Andersson out += uhci_show_td(uhci, td, out,
14451e2f62fSJan Andersson len - (out - buf), 0);
14513996ca7SChen Gang if (out - buf > len)
14613996ca7SChen Gang goto tail;
147dccf4a48SAlan Stern } else {
14851e2f62fSJan Andersson if (td_status(uhci, td) & TD_CTRL_ACTIVE)
149dccf4a48SAlan Stern ++nactive;
150dccf4a48SAlan Stern else
151dccf4a48SAlan Stern ++ninactive;
152dccf4a48SAlan Stern }
153dccf4a48SAlan Stern }
154dccf4a48SAlan Stern if (nactive + ninactive > 0)
1553171fcabSChen Gang out += sprintf(out,
1563171fcabSChen Gang "%*s[skipped %d inactive and %d active TDs]\n",
157dccf4a48SAlan Stern space, "", ninactive, nactive);
15813996ca7SChen Gang done:
15913996ca7SChen Gang if (out - buf > len)
16013996ca7SChen Gang out += sprintf(out, " ...\n");
16113996ca7SChen Gang tail:
162dccf4a48SAlan Stern return out - buf;
163dccf4a48SAlan Stern }
164dccf4a48SAlan Stern
uhci_show_qh(struct uhci_hcd * uhci,struct uhci_qh * qh,char * buf,int len,int space)165e009f1b2SAlan Stern static int uhci_show_qh(struct uhci_hcd *uhci,
166e009f1b2SAlan Stern struct uhci_qh *qh, char *buf, int len, int space)
1671da177e4SLinus Torvalds {
1681da177e4SLinus Torvalds char *out = buf;
169dccf4a48SAlan Stern int i, nurbs;
17051e2f62fSJan Andersson __hc32 element = qh_element(qh);
1714de7d2c2SAlan Stern char *qtype;
1721da177e4SLinus Torvalds
1734de7d2c2SAlan Stern switch (qh->type) {
1744de7d2c2SAlan Stern case USB_ENDPOINT_XFER_ISOC: qtype = "ISO"; break;
1754de7d2c2SAlan Stern case USB_ENDPOINT_XFER_INT: qtype = "INT"; break;
1764de7d2c2SAlan Stern case USB_ENDPOINT_XFER_BULK: qtype = "BLK"; break;
1774de7d2c2SAlan Stern case USB_ENDPOINT_XFER_CONTROL: qtype = "CTL"; break;
1784de7d2c2SAlan Stern default: qtype = "Skel" ; break;
1794de7d2c2SAlan Stern }
1804de7d2c2SAlan Stern
1814de7d2c2SAlan Stern out += sprintf(out, "%*s[%p] %s QH link (%08x) element (%08x)\n",
1824de7d2c2SAlan Stern space, "", qh, qtype,
18351e2f62fSJan Andersson hc32_to_cpu(uhci, qh->link),
18451e2f62fSJan Andersson hc32_to_cpu(uhci, element));
185caf3827aSAlan Stern if (qh->type == USB_ENDPOINT_XFER_ISOC)
1863171fcabSChen Gang out += sprintf(out,
1873171fcabSChen Gang "%*s period %d phase %d load %d us, frame %x desc [%p]\n",
1883ca2a321SAlan Stern space, "", qh->period, qh->phase, qh->load,
1893ca2a321SAlan Stern qh->iso_frame, qh->iso_packet_desc);
1903ca2a321SAlan Stern else if (qh->type == USB_ENDPOINT_XFER_INT)
1913ca2a321SAlan Stern out += sprintf(out, "%*s period %d phase %d load %d us\n",
1923ca2a321SAlan Stern space, "", qh->period, qh->phase, qh->load);
19313996ca7SChen Gang if (out - buf > len)
19413996ca7SChen Gang goto done;
1951da177e4SLinus Torvalds
19651e2f62fSJan Andersson if (element & UHCI_PTR_QH(uhci))
1971da177e4SLinus Torvalds out += sprintf(out, "%*s Element points to QH (bug?)\n", space, "");
1981da177e4SLinus Torvalds
19951e2f62fSJan Andersson if (element & UHCI_PTR_DEPTH(uhci))
2001da177e4SLinus Torvalds out += sprintf(out, "%*s Depth traverse\n", space, "");
2011da177e4SLinus Torvalds
20251e2f62fSJan Andersson if (element & cpu_to_hc32(uhci, 8))
2031da177e4SLinus Torvalds out += sprintf(out, "%*s Bit 3 set (bug?)\n", space, "");
2041da177e4SLinus Torvalds
20551e2f62fSJan Andersson if (!(element & ~(UHCI_PTR_QH(uhci) | UHCI_PTR_DEPTH(uhci))))
2061da177e4SLinus Torvalds out += sprintf(out, "%*s Element is NULL (bug?)\n", space, "");
2071da177e4SLinus Torvalds
20813996ca7SChen Gang if (out - buf > len)
20913996ca7SChen Gang goto done;
21013996ca7SChen Gang
211dccf4a48SAlan Stern if (list_empty(&qh->queue)) {
212dccf4a48SAlan Stern out += sprintf(out, "%*s queue is empty\n", space, "");
21313996ca7SChen Gang if (qh == uhci->skel_async_qh) {
21451e2f62fSJan Andersson out += uhci_show_td(uhci, uhci->term_td, out,
215e009f1b2SAlan Stern len - (out - buf), 0);
21613996ca7SChen Gang if (out - buf > len)
21713996ca7SChen Gang goto tail;
21813996ca7SChen Gang }
219dccf4a48SAlan Stern } else {
220dccf4a48SAlan Stern struct urb_priv *urbp = list_entry(qh->queue.next,
221dccf4a48SAlan Stern struct urb_priv, node);
222dccf4a48SAlan Stern struct uhci_td *td = list_entry(urbp->td_list.next,
223dccf4a48SAlan Stern struct uhci_td, list);
2241da177e4SLinus Torvalds
22551e2f62fSJan Andersson if (element != LINK_TO_TD(uhci, td))
226dccf4a48SAlan Stern out += sprintf(out, "%*s Element != First TD\n",
227dccf4a48SAlan Stern space, "");
228dccf4a48SAlan Stern i = nurbs = 0;
229dccf4a48SAlan Stern list_for_each_entry(urbp, &qh->queue, node) {
23013996ca7SChen Gang if (++i <= 10) {
23151e2f62fSJan Andersson out += uhci_show_urbp(uhci, urbp, out,
232dccf4a48SAlan Stern len - (out - buf), space + 2);
23313996ca7SChen Gang if (out - buf > len)
23413996ca7SChen Gang goto tail;
23513996ca7SChen Gang }
236dccf4a48SAlan Stern else
237dccf4a48SAlan Stern ++nurbs;
238dccf4a48SAlan Stern }
239dccf4a48SAlan Stern if (nurbs > 0)
240dccf4a48SAlan Stern out += sprintf(out, "%*s Skipped %d URBs\n",
241dccf4a48SAlan Stern space, "", nurbs);
2421da177e4SLinus Torvalds }
2431da177e4SLinus Torvalds
24413996ca7SChen Gang if (out - buf > len)
24513996ca7SChen Gang goto done;
24613996ca7SChen Gang
24785a975d0SAlan Stern if (qh->dummy_td) {
248af0bb599SAlan Stern out += sprintf(out, "%*s Dummy TD\n", space, "");
24951e2f62fSJan Andersson out += uhci_show_td(uhci, qh->dummy_td, out,
25051e2f62fSJan Andersson len - (out - buf), 0);
25113996ca7SChen Gang if (out - buf > len)
25213996ca7SChen Gang goto tail;
253af0bb599SAlan Stern }
254af0bb599SAlan Stern
25513996ca7SChen Gang done:
25613996ca7SChen Gang if (out - buf > len)
25713996ca7SChen Gang out += sprintf(out, " ...\n");
25813996ca7SChen Gang tail:
2591da177e4SLinus Torvalds return out - buf;
2601da177e4SLinus Torvalds }
2611da177e4SLinus Torvalds
uhci_show_sc(int port,unsigned short status,char * buf)26213996ca7SChen Gang static int uhci_show_sc(int port, unsigned short status, char *buf)
2631da177e4SLinus Torvalds {
26413996ca7SChen Gang return sprintf(buf, " stat%d = %04x %s%s%s%s%s%s%s%s%s%s\n",
2651da177e4SLinus Torvalds port,
2661da177e4SLinus Torvalds status,
2671da177e4SLinus Torvalds (status & USBPORTSC_SUSP) ? " Suspend" : "",
2681da177e4SLinus Torvalds (status & USBPORTSC_OCC) ? " OverCurrentChange" : "",
2691da177e4SLinus Torvalds (status & USBPORTSC_OC) ? " OverCurrent" : "",
2701da177e4SLinus Torvalds (status & USBPORTSC_PR) ? " Reset" : "",
2711da177e4SLinus Torvalds (status & USBPORTSC_LSDA) ? " LowSpeed" : "",
2721da177e4SLinus Torvalds (status & USBPORTSC_RD) ? " ResumeDetect" : "",
2731da177e4SLinus Torvalds (status & USBPORTSC_PEC) ? " EnableChange" : "",
2741da177e4SLinus Torvalds (status & USBPORTSC_PE) ? " Enabled" : "",
2751da177e4SLinus Torvalds (status & USBPORTSC_CSC) ? " ConnectChange" : "",
2761da177e4SLinus Torvalds (status & USBPORTSC_CCS) ? " Connected" : "");
2771da177e4SLinus Torvalds }
2781da177e4SLinus Torvalds
uhci_show_root_hub_state(struct uhci_hcd * uhci,char * buf)27913996ca7SChen Gang static int uhci_show_root_hub_state(struct uhci_hcd *uhci, char *buf)
280c8f4fe43SAlan Stern {
281c8f4fe43SAlan Stern char *rh_state;
282c8f4fe43SAlan Stern
283c8f4fe43SAlan Stern switch (uhci->rh_state) {
284c8f4fe43SAlan Stern case UHCI_RH_RESET:
285c8f4fe43SAlan Stern rh_state = "reset"; break;
286c8f4fe43SAlan Stern case UHCI_RH_SUSPENDED:
287c8f4fe43SAlan Stern rh_state = "suspended"; break;
288c8f4fe43SAlan Stern case UHCI_RH_AUTO_STOPPED:
289c8f4fe43SAlan Stern rh_state = "auto-stopped"; break;
290c8f4fe43SAlan Stern case UHCI_RH_RESUMING:
291c8f4fe43SAlan Stern rh_state = "resuming"; break;
292c8f4fe43SAlan Stern case UHCI_RH_SUSPENDING:
293c8f4fe43SAlan Stern rh_state = "suspending"; break;
294c8f4fe43SAlan Stern case UHCI_RH_RUNNING:
295c8f4fe43SAlan Stern rh_state = "running"; break;
296c8f4fe43SAlan Stern case UHCI_RH_RUNNING_NODEVS:
297c8f4fe43SAlan Stern rh_state = "running, no devs"; break;
298c8f4fe43SAlan Stern default:
299c8f4fe43SAlan Stern rh_state = "?"; break;
300c8f4fe43SAlan Stern }
30113996ca7SChen Gang return sprintf(buf, "Root-hub state: %s FSBR: %d\n",
30284afddd7SAlan Stern rh_state, uhci->fsbr_is_on);
303c8f4fe43SAlan Stern }
304c8f4fe43SAlan Stern
uhci_show_status(struct uhci_hcd * uhci,char * buf,int len)3051da177e4SLinus Torvalds static int uhci_show_status(struct uhci_hcd *uhci, char *buf, int len)
3061da177e4SLinus Torvalds {
3071da177e4SLinus Torvalds char *out = buf;
3081da177e4SLinus Torvalds unsigned short usbcmd, usbstat, usbint, usbfrnum;
3091da177e4SLinus Torvalds unsigned int flbaseadd;
3101da177e4SLinus Torvalds unsigned char sof;
3111da177e4SLinus Torvalds unsigned short portsc1, portsc2;
3121da177e4SLinus Torvalds
3131da177e4SLinus Torvalds
314f1125f81SDeng-Cheng Zhu usbcmd = uhci_readw(uhci, USBCMD);
315f1125f81SDeng-Cheng Zhu usbstat = uhci_readw(uhci, USBSTS);
316f1125f81SDeng-Cheng Zhu usbint = uhci_readw(uhci, USBINTR);
317f1125f81SDeng-Cheng Zhu usbfrnum = uhci_readw(uhci, USBFRNUM);
318f1125f81SDeng-Cheng Zhu flbaseadd = uhci_readl(uhci, USBFLBASEADD);
319f1125f81SDeng-Cheng Zhu sof = uhci_readb(uhci, USBSOF);
320f1125f81SDeng-Cheng Zhu portsc1 = uhci_readw(uhci, USBPORTSC1);
321f1125f81SDeng-Cheng Zhu portsc2 = uhci_readw(uhci, USBPORTSC2);
3221da177e4SLinus Torvalds
3231da177e4SLinus Torvalds out += sprintf(out, " usbcmd = %04x %s%s%s%s%s%s%s%s\n",
3241da177e4SLinus Torvalds usbcmd,
3251da177e4SLinus Torvalds (usbcmd & USBCMD_MAXP) ? "Maxp64 " : "Maxp32 ",
3261da177e4SLinus Torvalds (usbcmd & USBCMD_CF) ? "CF " : "",
3271da177e4SLinus Torvalds (usbcmd & USBCMD_SWDBG) ? "SWDBG " : "",
3281da177e4SLinus Torvalds (usbcmd & USBCMD_FGR) ? "FGR " : "",
3291da177e4SLinus Torvalds (usbcmd & USBCMD_EGSM) ? "EGSM " : "",
3301da177e4SLinus Torvalds (usbcmd & USBCMD_GRESET) ? "GRESET " : "",
3311da177e4SLinus Torvalds (usbcmd & USBCMD_HCRESET) ? "HCRESET " : "",
3321da177e4SLinus Torvalds (usbcmd & USBCMD_RS) ? "RS " : "");
33313996ca7SChen Gang if (out - buf > len)
33413996ca7SChen Gang goto done;
3351da177e4SLinus Torvalds
3361da177e4SLinus Torvalds out += sprintf(out, " usbstat = %04x %s%s%s%s%s%s\n",
3371da177e4SLinus Torvalds usbstat,
3381da177e4SLinus Torvalds (usbstat & USBSTS_HCH) ? "HCHalted " : "",
3391da177e4SLinus Torvalds (usbstat & USBSTS_HCPE) ? "HostControllerProcessError " : "",
3401da177e4SLinus Torvalds (usbstat & USBSTS_HSE) ? "HostSystemError " : "",
3411da177e4SLinus Torvalds (usbstat & USBSTS_RD) ? "ResumeDetect " : "",
3421da177e4SLinus Torvalds (usbstat & USBSTS_ERROR) ? "USBError " : "",
3431da177e4SLinus Torvalds (usbstat & USBSTS_USBINT) ? "USBINT " : "");
34413996ca7SChen Gang if (out - buf > len)
34513996ca7SChen Gang goto done;
3461da177e4SLinus Torvalds
3471da177e4SLinus Torvalds out += sprintf(out, " usbint = %04x\n", usbint);
3481da177e4SLinus Torvalds out += sprintf(out, " usbfrnum = (%d)%03x\n", (usbfrnum >> 10) & 1,
3491da177e4SLinus Torvalds 0xfff & (4*(unsigned int)usbfrnum));
3501da177e4SLinus Torvalds out += sprintf(out, " flbaseadd = %08x\n", flbaseadd);
3511da177e4SLinus Torvalds out += sprintf(out, " sof = %02x\n", sof);
35213996ca7SChen Gang if (out - buf > len)
35313996ca7SChen Gang goto done;
35413996ca7SChen Gang
35513996ca7SChen Gang out += uhci_show_sc(1, portsc1, out);
35613996ca7SChen Gang if (out - buf > len)
35713996ca7SChen Gang goto done;
35813996ca7SChen Gang
35913996ca7SChen Gang out += uhci_show_sc(2, portsc2, out);
36013996ca7SChen Gang if (out - buf > len)
36113996ca7SChen Gang goto done;
36213996ca7SChen Gang
36313996ca7SChen Gang out += sprintf(out,
36413996ca7SChen Gang "Most recent frame: %x (%d) Last ISO frame: %x (%d)\n",
365c8155cc5SAlan Stern uhci->frame_number, uhci->frame_number & 1023,
366c8155cc5SAlan Stern uhci->last_iso_frame, uhci->last_iso_frame & 1023);
3671da177e4SLinus Torvalds
36813996ca7SChen Gang done:
36913996ca7SChen Gang if (out - buf > len)
37013996ca7SChen Gang out += sprintf(out, " ...\n");
3711da177e4SLinus Torvalds return out - buf;
3721da177e4SLinus Torvalds }
3731da177e4SLinus Torvalds
uhci_sprint_schedule(struct uhci_hcd * uhci,char * buf,int len)3741da177e4SLinus Torvalds static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len)
3751da177e4SLinus Torvalds {
3761da177e4SLinus Torvalds char *out = buf;
3771da177e4SLinus Torvalds int i, j;
3781da177e4SLinus Torvalds struct uhci_qh *qh;
3791da177e4SLinus Torvalds struct uhci_td *td;
3801da177e4SLinus Torvalds struct list_head *tmp, *head;
381f3fe239bSAlan Stern int nframes, nerrs;
38251e2f62fSJan Andersson __hc32 link;
38351e2f62fSJan Andersson __hc32 fsbr_link;
38417230acdSAlan Stern
38517230acdSAlan Stern static const char * const qh_names[] = {
38617230acdSAlan Stern "unlink", "iso", "int128", "int64", "int32", "int16",
38717230acdSAlan Stern "int8", "int4", "int2", "async", "term"
38817230acdSAlan Stern };
3891da177e4SLinus Torvalds
39013996ca7SChen Gang out += uhci_show_root_hub_state(uhci, out);
39113996ca7SChen Gang if (out - buf > len)
39213996ca7SChen Gang goto done;
3931da177e4SLinus Torvalds out += sprintf(out, "HC status\n");
3941da177e4SLinus Torvalds out += uhci_show_status(uhci, out, len - (out - buf));
39513996ca7SChen Gang if (out - buf > len)
39613996ca7SChen Gang goto tail;
3973ca2a321SAlan Stern
3983ca2a321SAlan Stern out += sprintf(out, "Periodic load table\n");
3993ca2a321SAlan Stern for (i = 0; i < MAX_PHASE; ++i) {
4003ca2a321SAlan Stern out += sprintf(out, "\t%d", uhci->load[i]);
4013ca2a321SAlan Stern if (i % 8 == 7)
4023ca2a321SAlan Stern *out++ = '\n';
4033ca2a321SAlan Stern }
4043ca2a321SAlan Stern out += sprintf(out, "Total: %d, #INT: %d, #ISO: %d\n",
4053ca2a321SAlan Stern uhci->total_load,
4063ca2a321SAlan Stern uhci_to_hcd(uhci)->self.bandwidth_int_reqs,
4073ca2a321SAlan Stern uhci_to_hcd(uhci)->self.bandwidth_isoc_reqs);
408dccf4a48SAlan Stern if (debug <= 1)
40913996ca7SChen Gang goto tail;
4101da177e4SLinus Torvalds
4111da177e4SLinus Torvalds out += sprintf(out, "Frame List\n");
412f3fe239bSAlan Stern nframes = 10;
413f3fe239bSAlan Stern nerrs = 0;
4141da177e4SLinus Torvalds for (i = 0; i < UHCI_NUMFRAMES; ++i) {
41551e2f62fSJan Andersson __hc32 qh_dma;
4161da177e4SLinus Torvalds
41713996ca7SChen Gang if (out - buf > len)
41813996ca7SChen Gang goto done;
419f3fe239bSAlan Stern j = 0;
420f3fe239bSAlan Stern td = uhci->frame_cpu[i];
421f3fe239bSAlan Stern link = uhci->frame[i];
422f3fe239bSAlan Stern if (!td)
423f3fe239bSAlan Stern goto check_link;
424f3fe239bSAlan Stern
425f3fe239bSAlan Stern if (nframes > 0) {
426f3fe239bSAlan Stern out += sprintf(out, "- Frame %d -> (%08x)\n",
42751e2f62fSJan Andersson i, hc32_to_cpu(uhci, link));
428f3fe239bSAlan Stern j = 1;
429f3fe239bSAlan Stern }
4301da177e4SLinus Torvalds
4311da177e4SLinus Torvalds head = &td->fl_list;
4321da177e4SLinus Torvalds tmp = head;
4331da177e4SLinus Torvalds do {
4341da177e4SLinus Torvalds td = list_entry(tmp, struct uhci_td, fl_list);
4351da177e4SLinus Torvalds tmp = tmp->next;
43651e2f62fSJan Andersson if (link != LINK_TO_TD(uhci, td)) {
43713996ca7SChen Gang if (nframes > 0) {
4383171fcabSChen Gang out += sprintf(out,
4393171fcabSChen Gang " link does not match list entry!\n");
44013996ca7SChen Gang if (out - buf > len)
44113996ca7SChen Gang goto done;
44213996ca7SChen Gang } else
443f3fe239bSAlan Stern ++nerrs;
4441da177e4SLinus Torvalds }
44513996ca7SChen Gang if (nframes > 0) {
44651e2f62fSJan Andersson out += uhci_show_td(uhci, td, out,
447f3fe239bSAlan Stern len - (out - buf), 4);
44813996ca7SChen Gang if (out - buf > len)
44913996ca7SChen Gang goto tail;
45013996ca7SChen Gang }
451f3fe239bSAlan Stern link = td->link;
452f3fe239bSAlan Stern } while (tmp != head);
453f3fe239bSAlan Stern
454f3fe239bSAlan Stern check_link:
455f3fe239bSAlan Stern qh_dma = uhci_frame_skel_link(uhci, i);
456f3fe239bSAlan Stern if (link != qh_dma) {
457f3fe239bSAlan Stern if (nframes > 0) {
458f3fe239bSAlan Stern if (!j) {
459f3fe239bSAlan Stern out += sprintf(out,
460f3fe239bSAlan Stern "- Frame %d -> (%08x)\n",
46151e2f62fSJan Andersson i, hc32_to_cpu(uhci, link));
462f3fe239bSAlan Stern j = 1;
463f3fe239bSAlan Stern }
4643171fcabSChen Gang out += sprintf(out,
4653171fcabSChen Gang " link does not match QH (%08x)!\n",
46651e2f62fSJan Andersson hc32_to_cpu(uhci, qh_dma));
46713996ca7SChen Gang if (out - buf > len)
46813996ca7SChen Gang goto done;
469f3fe239bSAlan Stern } else
470f3fe239bSAlan Stern ++nerrs;
471f3fe239bSAlan Stern }
472f3fe239bSAlan Stern nframes -= j;
473f3fe239bSAlan Stern }
474f3fe239bSAlan Stern if (nerrs > 0)
475f3fe239bSAlan Stern out += sprintf(out, "Skipped %d bad links\n", nerrs);
4761da177e4SLinus Torvalds
477687f5f34SAlan Stern out += sprintf(out, "Skeleton QHs\n");
4781da177e4SLinus Torvalds
47913996ca7SChen Gang if (out - buf > len)
48013996ca7SChen Gang goto done;
48113996ca7SChen Gang
482e009f1b2SAlan Stern fsbr_link = 0;
4831da177e4SLinus Torvalds for (i = 0; i < UHCI_NUM_SKELQH; ++i) {
484dccf4a48SAlan Stern int cnt = 0;
4851da177e4SLinus Torvalds
4861da177e4SLinus Torvalds qh = uhci->skelqh[i];
4873171fcabSChen Gang out += sprintf(out, "- skel_%s_qh\n", qh_names[i]);
488e009f1b2SAlan Stern out += uhci_show_qh(uhci, qh, out, len - (out - buf), 4);
48913996ca7SChen Gang if (out - buf > len)
49013996ca7SChen Gang goto tail;
4911da177e4SLinus Torvalds
4921da177e4SLinus Torvalds /* Last QH is the Terminating QH, it's different */
49317230acdSAlan Stern if (i == SKEL_TERM) {
49413996ca7SChen Gang if (qh_element(qh) != LINK_TO_TD(uhci, uhci->term_td)) {
4953171fcabSChen Gang out += sprintf(out,
4963171fcabSChen Gang " skel_term_qh element is not set to term_td!\n");
49713996ca7SChen Gang if (out - buf > len)
49813996ca7SChen Gang goto done;
49913996ca7SChen Gang }
500e009f1b2SAlan Stern link = fsbr_link;
501e009f1b2SAlan Stern if (!link)
50251e2f62fSJan Andersson link = LINK_TO_QH(uhci, uhci->skel_term_qh);
50317230acdSAlan Stern goto check_qh_link;
5041da177e4SLinus Torvalds }
5051da177e4SLinus Torvalds
506dccf4a48SAlan Stern head = &qh->node;
5071da177e4SLinus Torvalds tmp = head->next;
5081da177e4SLinus Torvalds
5091da177e4SLinus Torvalds while (tmp != head) {
510dccf4a48SAlan Stern qh = list_entry(tmp, struct uhci_qh, node);
5111da177e4SLinus Torvalds tmp = tmp->next;
51213996ca7SChen Gang if (++cnt <= 10) {
513e009f1b2SAlan Stern out += uhci_show_qh(uhci, qh, out,
514dccf4a48SAlan Stern len - (out - buf), 4);
51513996ca7SChen Gang if (out - buf > len)
51613996ca7SChen Gang goto tail;
51713996ca7SChen Gang }
51817230acdSAlan Stern if (!fsbr_link && qh->skel >= SKEL_FSBR)
51951e2f62fSJan Andersson fsbr_link = LINK_TO_QH(uhci, qh);
5201da177e4SLinus Torvalds }
521dccf4a48SAlan Stern if ((cnt -= 10) > 0)
522dccf4a48SAlan Stern out += sprintf(out, " Skipped %d QHs\n", cnt);
5231da177e4SLinus Torvalds
52451e2f62fSJan Andersson link = UHCI_PTR_TERM(uhci);
52517230acdSAlan Stern if (i <= SKEL_ISO)
52617230acdSAlan Stern ;
52717230acdSAlan Stern else if (i < SKEL_ASYNC)
52851e2f62fSJan Andersson link = LINK_TO_QH(uhci, uhci->skel_async_qh);
52917230acdSAlan Stern else if (!uhci->fsbr_is_on)
53017230acdSAlan Stern ;
53117230acdSAlan Stern else
53251e2f62fSJan Andersson link = LINK_TO_QH(uhci, uhci->skel_term_qh);
53317230acdSAlan Stern check_qh_link:
53417230acdSAlan Stern if (qh->link != link)
5353171fcabSChen Gang out += sprintf(out,
5363171fcabSChen Gang " last QH not linked to next skeleton!\n");
53713996ca7SChen Gang
53813996ca7SChen Gang if (out - buf > len)
53913996ca7SChen Gang goto done;
5401da177e4SLinus Torvalds }
5411da177e4SLinus Torvalds
54213996ca7SChen Gang done:
54313996ca7SChen Gang if (out - buf > len)
54413996ca7SChen Gang out += sprintf(out, " ...\n");
54513996ca7SChen Gang tail:
5461da177e4SLinus Torvalds return out - buf;
5471da177e4SLinus Torvalds }
5481da177e4SLinus Torvalds
5498d402e1aSAlan Stern #ifdef CONFIG_DEBUG_FS
5508d402e1aSAlan Stern
5511da177e4SLinus Torvalds #define MAX_OUTPUT (64 * 1024)
5521da177e4SLinus Torvalds
5531da177e4SLinus Torvalds struct uhci_debug {
5541da177e4SLinus Torvalds int size;
5551da177e4SLinus Torvalds char *data;
5561da177e4SLinus Torvalds };
5571da177e4SLinus Torvalds
uhci_debug_open(struct inode * inode,struct file * file)5581da177e4SLinus Torvalds static int uhci_debug_open(struct inode *inode, struct file *file)
5591da177e4SLinus Torvalds {
5608e18e294STheodore Ts'o struct uhci_hcd *uhci = inode->i_private;
5611da177e4SLinus Torvalds struct uhci_debug *up;
562dccf4a48SAlan Stern unsigned long flags;
5631da177e4SLinus Torvalds
5641da177e4SLinus Torvalds up = kmalloc(sizeof(*up), GFP_KERNEL);
5651da177e4SLinus Torvalds if (!up)
56600b81fb2SAndi Kleen return -ENOMEM;
5671da177e4SLinus Torvalds
5681da177e4SLinus Torvalds up->data = kmalloc(MAX_OUTPUT, GFP_KERNEL);
5691da177e4SLinus Torvalds if (!up->data) {
5701da177e4SLinus Torvalds kfree(up);
57100b81fb2SAndi Kleen return -ENOMEM;
5721da177e4SLinus Torvalds }
5731da177e4SLinus Torvalds
5748d402e1aSAlan Stern up->size = 0;
575dccf4a48SAlan Stern spin_lock_irqsave(&uhci->lock, flags);
5768d402e1aSAlan Stern if (uhci->is_initialized)
57713996ca7SChen Gang up->size = uhci_sprint_schedule(uhci, up->data,
57813996ca7SChen Gang MAX_OUTPUT - EXTRA_SPACE);
579dccf4a48SAlan Stern spin_unlock_irqrestore(&uhci->lock, flags);
5801da177e4SLinus Torvalds
5811da177e4SLinus Torvalds file->private_data = up;
5821da177e4SLinus Torvalds
58300b81fb2SAndi Kleen return 0;
5841da177e4SLinus Torvalds }
5851da177e4SLinus Torvalds
uhci_debug_lseek(struct file * file,loff_t off,int whence)5861da177e4SLinus Torvalds static loff_t uhci_debug_lseek(struct file *file, loff_t off, int whence)
5871da177e4SLinus Torvalds {
588b25472f9SAl Viro struct uhci_debug *up = file->private_data;
589b25472f9SAl Viro return no_seek_end_llseek_size(file, off, whence, up->size);
5901da177e4SLinus Torvalds }
5911da177e4SLinus Torvalds
uhci_debug_read(struct file * file,char __user * buf,size_t nbytes,loff_t * ppos)5921da177e4SLinus Torvalds static ssize_t uhci_debug_read(struct file *file, char __user *buf,
5931da177e4SLinus Torvalds size_t nbytes, loff_t *ppos)
5941da177e4SLinus Torvalds {
5951da177e4SLinus Torvalds struct uhci_debug *up = file->private_data;
5961da177e4SLinus Torvalds return simple_read_from_buffer(buf, nbytes, ppos, up->data, up->size);
5971da177e4SLinus Torvalds }
5981da177e4SLinus Torvalds
uhci_debug_release(struct inode * inode,struct file * file)5991da177e4SLinus Torvalds static int uhci_debug_release(struct inode *inode, struct file *file)
6001da177e4SLinus Torvalds {
6011da177e4SLinus Torvalds struct uhci_debug *up = file->private_data;
6021da177e4SLinus Torvalds
6031da177e4SLinus Torvalds kfree(up->data);
6041da177e4SLinus Torvalds kfree(up);
6051da177e4SLinus Torvalds
6061da177e4SLinus Torvalds return 0;
6071da177e4SLinus Torvalds }
6081da177e4SLinus Torvalds
609066202ddSLuiz Fernando N. Capitulino static const struct file_operations uhci_debug_operations = {
6108d402e1aSAlan Stern .owner = THIS_MODULE,
6111da177e4SLinus Torvalds .open = uhci_debug_open,
6121da177e4SLinus Torvalds .llseek = uhci_debug_lseek,
6131da177e4SLinus Torvalds .read = uhci_debug_read,
6141da177e4SLinus Torvalds .release = uhci_debug_release,
6151da177e4SLinus Torvalds };
616b409214cSAlan Stern #define UHCI_DEBUG_OPS
6171da177e4SLinus Torvalds
6188d402e1aSAlan Stern #endif /* CONFIG_DEBUG_FS */
6191da177e4SLinus Torvalds
6201c20163dSOliver Neukum #else /* CONFIG_DYNAMIC_DEBUG*/
6218d402e1aSAlan Stern
lprintk(char * buf)6228d402e1aSAlan Stern static inline void lprintk(char *buf)
6238d402e1aSAlan Stern {}
6248d402e1aSAlan Stern
uhci_show_qh(struct uhci_hcd * uhci,struct uhci_qh * qh,char * buf,int len,int space)625e009f1b2SAlan Stern static inline int uhci_show_qh(struct uhci_hcd *uhci,
626e009f1b2SAlan Stern struct uhci_qh *qh, char *buf, int len, int space)
6278d402e1aSAlan Stern {
6288d402e1aSAlan Stern return 0;
6298d402e1aSAlan Stern }
6308d402e1aSAlan Stern
uhci_sprint_schedule(struct uhci_hcd * uhci,char * buf,int len)6318d402e1aSAlan Stern static inline int uhci_sprint_schedule(struct uhci_hcd *uhci,
6328d402e1aSAlan Stern char *buf, int len)
6338d402e1aSAlan Stern {
6348d402e1aSAlan Stern return 0;
6358d402e1aSAlan Stern }
6361da177e4SLinus Torvalds
6371da177e4SLinus Torvalds #endif
638