# This is a BitKeeper generated patch for the following project: # Project Name: Linux kernel tree # This patch format is intended for GNU patch command version 2.5 or higher. # This patch includes the following deltas: # ChangeSet 1.546 -> 1.547 # drivers/usb/host/ehci-dbg.c 1.6 -> 1.7 # # The following is the BitKeeper ChangeSet Log # -------------------------------------------- # 02/08/28 david-b@pacbell.net 1.547 # [PATCH] ehci, registers to driverfs (for debug) # # When debugging, it's useful to see what the registers are # saying is up without needing to poke around in the kernel. # This patch exposes them. # -------------------------------------------- # diff -Nru a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c --- a/drivers/usb/host/ehci-dbg.c Wed Aug 28 23:20:27 2002 +++ b/drivers/usb/host/ehci-dbg.c Wed Aug 28 23:20:27 2002 @@ -26,8 +26,10 @@ #ifdef DEBUG -/* check the values in the HCSPARAMS register - host controller structural parameters */ -/* see EHCI 0.95 Spec, Table 2-4 for each value */ +/* check the values in the HCSPARAMS register + * (host controller _Structural_ parameters) + * see EHCI spec, Table 2-4 for each value + */ static void dbg_hcs_params (struct ehci_hcd *ehci, char *label) { u32 params = readl (&ehci->caps->hcs_params); @@ -67,8 +69,10 @@ #ifdef DEBUG -/* check the values in the HCCPARAMS register - host controller capability parameters */ -/* see EHCI 0.95 Spec, Table 2-5 for each value */ +/* check the values in the HCCPARAMS register + * (host controller _Capability_ parameters) + * see EHCI Spec, Table 2-5 for each value + * */ static void dbg_hcc_params (struct ehci_hcd *ehci, char *label) { u32 params = readl (&ehci->caps->hcc_params); @@ -79,13 +83,13 @@ label, HCC_EXT_CAPS (params)); } if (HCC_ISOC_CACHE (params)) { - dbg ("%s hcc_params 0x%04x caching frame %s%s%s", + dbg ("%s hcc_params %04x caching frame %s%s%s", label, params, HCC_PGM_FRAMELISTLEN (params) ? "256/512/1024" : "1024", HCC_CANPARK (params) ? " park" : "", HCC_64BIT_ADDR (params) ? " 64 bit addr" : ""); } else { - dbg ("%s hcc_params 0x%04x caching %d uframes %s%s%s", + dbg ("%s hcc_params %04x caching %d uframes %s%s%s", label, params, HCC_ISOC_THRES (params), @@ -118,62 +122,131 @@ } } +static int dbg_status_buf (char *buf, unsigned len, char *label, u32 status) +{ + return snprintf (buf, len, + "%s%sstatus %04x%s%s%s%s%s%s%s%s%s%s", + label, label [0] ? " " : "", status, + (status & STS_ASS) ? " Async" : "", + (status & STS_PSS) ? " Periodic" : "", + (status & STS_RECL) ? " Recl" : "", + (status & STS_HALT) ? " Halt" : "", + (status & STS_IAA) ? " IAA" : "", + (status & STS_FATAL) ? " FATAL" : "", + (status & STS_FLR) ? " FLR" : "", + (status & STS_PCD) ? " PCD" : "", + (status & STS_ERR) ? " ERR" : "", + (status & STS_INT) ? " INT" : "" + ); +} + +static int dbg_intr_buf (char *buf, unsigned len, char *label, u32 enable) +{ + return snprintf (buf, len, + "%s%sintrenable %02x%s%s%s%s%s%s", + label, label [0] ? " " : "", enable, + (enable & STS_IAA) ? " IAA" : "", + (enable & STS_FATAL) ? " FATAL" : "", + (enable & STS_FLR) ? " FLR" : "", + (enable & STS_PCD) ? " PCD" : "", + (enable & STS_ERR) ? " ERR" : "", + (enable & STS_INT) ? " INT" : "" + ); +} + static const char *const fls_strings [] = { "1024", "512", "256", "??" }; +static int dbg_command_buf (char *buf, unsigned len, char *label, u32 command) +{ + return snprintf (buf, len, + "%s%scommand %06x %s=%d ithresh=%d%s%s%s%s period=%s%s %s", + label, label [0] ? " " : "", command, + (command & CMD_PARK) ? "park" : "(park)", + CMD_PARK_CNT (command), + (command >> 16) & 0x3f, + (command & CMD_LRESET) ? " LReset" : "", + (command & CMD_IAAD) ? " IAAD" : "", + (command & CMD_ASE) ? " Async" : "", + (command & CMD_PSE) ? " Periodic" : "", + fls_strings [(command >> 2) & 0x3], + (command & CMD_RESET) ? " Reset" : "", + (command & CMD_RUN) ? "RUN" : "HALT" + ); +} + +static int +dbg_port_buf (char *buf, unsigned len, char *label, int port, u32 status) +{ + char *sig; + + /* signaling state */ + switch (status & (3 << 10)) { + case 0 << 10: sig = "se0"; break; + case 1 << 10: sig = "k"; break; /* low speed */ + case 2 << 10: sig = "j"; break; + default: sig = "?"; break; + } + + return snprintf (buf, len, + "%s%sport %d status %06x%s%s sig=%s %s%s%s%s%s%s%s%s%s", + label, label [0] ? " " : "", port, status, + (status & PORT_POWER) ? " POWER" : "", + (status & PORT_OWNER) ? " OWNER" : "", + sig, + (status & PORT_RESET) ? " RESET" : "", + (status & PORT_SUSPEND) ? " SUSPEND" : "", + (status & PORT_RESUME) ? " RESUME" : "", + (status & PORT_OCC) ? " OCC" : "", + (status & PORT_OC) ? " OC" : "", + (status & PORT_PEC) ? " PEC" : "", + (status & PORT_PE) ? " PE" : "", + (status & PORT_CSC) ? " CSC" : "", + (status & PORT_CONNECT) ? " CONNECT" : "" + ); +} + #else static inline void __attribute__((__unused__)) -dbg_qh (char *label, struct ehci_hcd *ehci, struct ehci_qh *qh) {} +dbg_qh (char *label, struct ehci_hcd *ehci, struct ehci_qh *qh) +{} + +static inline int __attribute__((__unused__)) +dbg_status_buf (char *buf, unsigned len, char *label, u32 status) +{} + +static inline int __attribute__((__unused__)) +dbg_command_buf (char *buf, unsigned len, char *label, u32 command) +{} + +static inline int __attribute__((__unused__)) +dbg_intr_buf (char *buf, unsigned len, char *label, u32 enable) +{} + +static inline int __attribute__((__unused__)) +dbg_port_buf (char *buf, unsigned len, char *label, int port, u32 status) +{} + #endif /* DEBUG */ /* functions have the "wrong" filename when they're output... */ +#define dbg_status(ehci, label, status) { \ + char _buf [80]; \ + dbg_status_buf (_buf, sizeof _buf, label, status); \ + dbg ("%s", _buf); \ +} + +#define dbg_cmd(ehci, label, command) { \ + char _buf [80]; \ + dbg_command_buf (_buf, sizeof _buf, label, command); \ + dbg ("%s", _buf); \ +} -#define dbg_status(ehci, label, status) \ - dbg ("%s status 0x%x%s%s%s%s%s%s%s%s%s%s", \ - label, status, \ - (status & STS_ASS) ? " Async" : "", \ - (status & STS_PSS) ? " Periodic" : "", \ - (status & STS_RECL) ? " Recl" : "", \ - (status & STS_HALT) ? " Halt" : "", \ - (status & STS_IAA) ? " IAA" : "", \ - (status & STS_FATAL) ? " FATAL" : "", \ - (status & STS_FLR) ? " FLR" : "", \ - (status & STS_PCD) ? " PCD" : "", \ - (status & STS_ERR) ? " ERR" : "", \ - (status & STS_INT) ? " INT" : "" \ - ) - -#define dbg_cmd(ehci, label, command) \ - dbg ("%s %x cmd %s=%d ithresh=%d%s%s%s%s period=%s%s %s", \ - label, command, \ - (command & CMD_PARK) ? "park" : "(park)", \ - CMD_PARK_CNT (command), \ - (command >> 16) & 0x3f, \ - (command & CMD_LRESET) ? " LReset" : "", \ - (command & CMD_IAAD) ? " IAAD" : "", \ - (command & CMD_ASE) ? " Async" : "", \ - (command & CMD_PSE) ? " Periodic" : "", \ - fls_strings [(command >> 2) & 0x3], \ - (command & CMD_RESET) ? " Reset" : "", \ - (command & CMD_RUN) ? "RUN" : "HALT" \ - ) - -#define dbg_port(hcd, label, port, status) \ - dbg ("%s port %d status 0x%x%s%s speed=%d%s%s%s%s%s%s%s%s%s", \ - label, port, status, \ - (status & PORT_OWNER) ? " OWNER" : "", \ - (status & PORT_POWER) ? " POWER" : "", \ - (status >> 10) & 3, \ - (status & PORT_RESET) ? " RESET" : "", \ - (status & PORT_SUSPEND) ? " SUSPEND" : "", \ - (status & PORT_RESUME) ? " RESUME" : "", \ - (status & PORT_OCC) ? " OCC" : "", \ - (status & PORT_OC) ? " OC" : "", \ - (status & PORT_PEC) ? " PEC" : "", \ - (status & PORT_PE) ? " PE" : "", \ - (status & PORT_CSC) ? " CSC" : "", \ - (status & PORT_CONNECT) ? " CONNECT" : "" \ - ) +#define dbg_port(hcd, label, port, status) { \ + char _buf [80]; \ + dbg_port_buf (_buf, sizeof _buf, label, port, status); \ + dbg ("%s", _buf); \ +} #ifdef DEBUG @@ -228,8 +301,9 @@ qtd_list); scratch = cpu_to_le32p (&td->hw_token); temp = snprintf (next, size, - ", td %p len=%d %s", + ", td %p len=%d tok %04x %s", td, scratch >> 16, + scratch & 0xffff, ({ char *tmp; switch ((scratch>>8)&0x03) { case 0: tmp = "out"; break; @@ -364,16 +438,104 @@ #undef DBG_SCHED_LIMIT +static ssize_t +show_registers (struct device *dev, char *buf, size_t count, loff_t off) +{ + struct pci_dev *pdev; + struct ehci_hcd *ehci; + unsigned long flags; + unsigned temp, size, i; + char *next, scratch [80]; + static char fmt [] = "%*s\n"; + static char label [] = ""; + + if (off != 0) + return 0; + + pdev = container_of (dev, struct pci_dev, dev); + ehci = container_of (pci_get_drvdata (pdev), struct ehci_hcd, hcd); + + next = buf; + size = count; + + spin_lock_irqsave (&ehci->lock, flags); + + /* Capability Registers */ + i = readw (&ehci->caps->hci_version); + temp = snprintf (next, size, "EHCI %x.%02x, hcd state %d\n", + i >> 8, i & 0x0ff, ehci->hcd.state); + size -= temp; + next += temp; + + // FIXME interpret both types of params + i = readl (&ehci->caps->hcs_params); + temp = snprintf (next, size, "structural params 0x%08x\n", i); + size -= temp; + next += temp; + + i = readl (&ehci->caps->hcc_params); + temp = snprintf (next, size, "capability params 0x%08x\n", i); + size -= temp; + next += temp; + + /* Operational Registers */ + temp = dbg_status_buf (scratch, sizeof scratch, label, + readl (&ehci->regs->status)); + temp = snprintf (next, size, fmt, temp, scratch); + size -= temp; + next += temp; + + temp = dbg_command_buf (scratch, sizeof scratch, label, + readl (&ehci->regs->command)); + temp = snprintf (next, size, fmt, temp, scratch); + size -= temp; + next += temp; + + temp = dbg_intr_buf (scratch, sizeof scratch, label, + readl (&ehci->regs->intr_enable)); + temp = snprintf (next, size, fmt, temp, scratch); + size -= temp; + next += temp; + + temp = snprintf (next, size, "uframe %04x\n", + readl (&ehci->regs->frame_index)); + size -= temp; + next += temp; + + for (i = 0; i < HCS_N_PORTS (ehci->hcs_params); i++) { + temp = dbg_port_buf (scratch, sizeof scratch, label, i, + readl (&ehci->regs->port_status [i])); + temp = snprintf (next, size, fmt, temp, scratch); + size -= temp; + next += temp; + } + + if (ehci->reclaim) { + temp = snprintf (next, size, "reclaim qh %p%s\n", + ehci->reclaim, + ehci->reclaim_ready ? " ready" : ""); + size -= temp; + next += temp; + } + + spin_unlock_irqrestore (&ehci->lock, flags); + + return count - size; +} +static DEVICE_ATTR (registers, S_IRUSR, show_registers, NULL); + static inline void create_debug_files (struct ehci_hcd *bus) { device_create_file (&bus->hcd.pdev->dev, &dev_attr_async); device_create_file (&bus->hcd.pdev->dev, &dev_attr_periodic); + device_create_file (&bus->hcd.pdev->dev, &dev_attr_registers); } static inline void remove_debug_files (struct ehci_hcd *bus) { device_remove_file (&bus->hcd.pdev->dev, &dev_attr_async); device_remove_file (&bus->hcd.pdev->dev, &dev_attr_periodic); + device_remove_file (&bus->hcd.pdev->dev, &dev_attr_registers); } #else /* DEBUG */