Hi,

This is a slightly cleaned up version of Kevin's patch to
add a "registers" sysfs debug file.  Minor style and whitespace
fixups, prints the other register, resolved config/build
issues (minor).

It also has two minor tweaks: a fix for a potential assertion
violation on a "dead-hc" cleanup path (rare), and wasting less
time blocking irqs when they're already blocked.

Please merge; this is against your current BK.

- Dave

--- 1.33/drivers/usb/host/ohci-dbg.c    Tue Feb 18 09:35:35 2003
+++ edited/drivers/usb/host/ohci-dbg.c  Mon Feb 24 12:02:45 2003
@@ -1,50 +1,50 @@
 /*
  * OHCI HCD (Host Controller Driver) for USB.
- * 
+ *
  * (C) Copyright 1999 Roman Weissgaerber <[EMAIL PROTECTED]>
  * (C) Copyright 2000-2002 David Brownell <[EMAIL PROTECTED]>
- * 
+ *
  * This file is licenced under the GPL.
  */
- 
+
 /*-------------------------------------------------------------------------*/
 
 #ifdef DEBUG
 
 #define edstring(ed_type) ({ char *temp; \
        switch (ed_type) { \
-       case PIPE_CONTROL:      temp = "CTRL"; break; \
-       case PIPE_BULK:         temp = "BULK"; break; \
-       case PIPE_INTERRUPT:    temp = "INTR"; break; \
-       default:                temp = "ISOC"; break; \
+       case PIPE_CONTROL:      temp = "ctrl"; break; \
+       case PIPE_BULK:         temp = "bulk"; break; \
+       case PIPE_INTERRUPT:    temp = "intr"; break; \
+       default:                temp = "isoc"; break; \
        }; temp;})
 #define pipestring(pipe) edstring(usb_pipetype(pipe))
 
-/* debug| print the main components of an URB     
+/* debug| print the main components of an URB
  * small: 0) header + data packets 1) just header
  */
 static void __attribute__((unused))
 urb_print (struct urb * urb, char * str, int small)
 {
        unsigned int pipe= urb->pipe;
-       
+
        if (!urb->dev || !urb->dev->bus) {
                dbg("%s URB: no dev", str);
                return;
        }
-       
+
 #ifndef        OHCI_VERBOSE_DEBUG
        if (urb->status != 0)
 #endif
-       dbg("%s %p dev:%d,ep=%d-%c,%s,flags:%x,len:%d/%d,stat:%d", 
+       dbg("%s %p dev=%d ep=%d%s-%s flags=%x len=%d/%d stat=%d",
                    str,
                    urb,
                    usb_pipedevice (pipe),
-                   usb_pipeendpoint (pipe), 
-                   usb_pipeout (pipe)? 'O': 'I',
+                   usb_pipeendpoint (pipe),
+                   usb_pipeout (pipe)? "out" : "in",
                    pipestring (pipe),
-                   urb->transfer_flags, 
-                   urb->actual_length, 
+                   urb->transfer_flags,
+                   urb->actual_length,
                    urb->transfer_buffer_length,
                    urb->status);
 
@@ -54,27 +54,43 @@
 
                if (usb_pipecontrol (pipe)) {
                        printk (KERN_DEBUG __FILE__ ": setup(8):");
-                       for (i = 0; i < 8 ; i++) 
+                       for (i = 0; i < 8 ; i++)
                                printk (" %02x", ((__u8 *) urb->setup_packet) [i]);
                        printk ("\n");
                }
                if (urb->transfer_buffer_length > 0 && urb->transfer_buffer) {
-                       printk (KERN_DEBUG __FILE__ ": data(%d/%d):", 
-                               urb->actual_length, 
+                       printk (KERN_DEBUG __FILE__ ": data(%d/%d):",
+                               urb->actual_length,
                                urb->transfer_buffer_length);
-                       len = usb_pipeout (pipe)? 
+                       len = usb_pipeout (pipe)?
                                                urb->transfer_buffer_length: 
urb->actual_length;
-                       for (i = 0; i < 16 && i < len; i++) 
+                       for (i = 0; i < 16 && i < len; i++)
                                printk (" %02x", ((__u8 *) urb->transfer_buffer) [i]);
                        printk ("%s stat:%d\n", i < len? "...": "", urb->status);
                }
-       } 
+       }
 #endif
 }
 
-static void ohci_dump_intr_mask (struct ohci_hcd *ohci, char *label, __u32 mask)
+#define ohci_dbg_sw(ohci, next, size, format, arg...) \
+       do { \
+       if (next) { \
+               unsigned s_len; \
+               s_len = snprintf (*next, *size, format, ## arg ); \
+               *size -= s_len; *next += s_len; \
+       } else \
+               ohci_dbg(ohci,format, ## arg ); \
+       } while (0);
+
+
+static void ohci_dump_intr_mask (
+       struct ohci_hcd *ohci,
+       char *label,
+       u32 mask,
+       char **next,
+       unsigned *size)
 {
-       ohci_dbg (ohci, "%s: 0x%08x%s%s%s%s%s%s%s%s%s\n",
+       ohci_dbg_sw (ohci, next, size, "%s 0x%08x%s%s%s%s%s%s%s%s%s\n",
                label,
                mask,
                (mask & OHCI_INTR_MIE) ? " MIE" : "",
@@ -89,10 +105,15 @@
                );
 }
 
-static void maybe_print_eds (struct ohci_hcd *ohci, char *label, __u32 value)
+static void maybe_print_eds (
+       struct ohci_hcd *ohci,
+       char *label,
+       u32 value,
+       char **next,
+       unsigned *size)
 {
        if (value)
-               ohci_dbg (ohci, "%s %08x\n", label, value);
+               ohci_dbg_sw (ohci, next, size, "%s %08x\n", label, value);
 }
 
 static char *hcfs2string (int state)
@@ -107,19 +128,22 @@
 }
 
 // dump control and status registers
-static void ohci_dump_status (struct ohci_hcd *controller)
+static void
+ohci_dump_status (struct ohci_hcd *controller, char **next, unsigned *size)
 {
        struct ohci_regs        *regs = controller->regs;
-       __u32                   temp;
+       u32                     temp;
 
        temp = readl (&regs->revision) & 0xff;
-       ohci_dbg (controller, "OHCI %d.%d, %s legacy support registers\n",
+       ohci_dbg_sw (controller, next, size,
+               "OHCI %d.%d, %s legacy support registers\n",
                0x03 & (temp >> 4), (temp & 0x0f),
                (temp & 0x10) ? "with" : "NO");
 
        temp = readl (&regs->control);
-       ohci_dbg (controller,
-               "control: 0x%08x%s%s%s HCFS=%s%s%s%s%s CBSR=%d\n", temp,
+       ohci_dbg_sw (controller, next, size,
+               "control 0x%03x%s%s%s HCFS=%s%s%s%s%s CBSR=%d\n",
+               temp,
                (temp & OHCI_CTRL_RWE) ? " RWE" : "",
                (temp & OHCI_CTRL_RWC) ? " RWC" : "",
                (temp & OHCI_CTRL_IR) ? " IR" : "",
@@ -132,7 +156,8 @@
                );
 
        temp = readl (&regs->cmdstatus);
-       ohci_dbg (controller, "cmdstatus: 0x%08x SOC=%d%s%s%s%s\n", temp,
+       ohci_dbg_sw (controller, next, size,
+               "cmdstatus 0x%05x SOC=%d%s%s%s%s\n", temp,
                (temp & OHCI_SOC) >> 16,
                (temp & OHCI_OCR) ? " OCR" : "",
                (temp & OHCI_BLF) ? " BLF" : "",
@@ -140,24 +165,59 @@
                (temp & OHCI_HCR) ? " HCR" : ""
                );
 
-       ohci_dump_intr_mask (controller, "intrstatus", readl (&regs->intrstatus));
-       ohci_dump_intr_mask (controller, "intrenable", readl (&regs->intrenable));
+       ohci_dump_intr_mask (controller, "intrstatus",
+                       readl (&regs->intrstatus), next, size);
+       ohci_dump_intr_mask (controller, "intrenable",
+                       readl (&regs->intrenable), next, size);
        // intrdisable always same as intrenable
 
-       maybe_print_eds (controller, "ed_periodcurrent", readl 
(&regs->ed_periodcurrent));
-
-       maybe_print_eds (controller, "ed_controlhead", readl (&regs->ed_controlhead));
-       maybe_print_eds (controller, "ed_controlcurrent", readl 
(&regs->ed_controlcurrent));
+       maybe_print_eds (controller, "ed_periodcurrent",
+                       readl (&regs->ed_periodcurrent), next, size);
 
-       maybe_print_eds (controller, "ed_bulkhead", readl (&regs->ed_bulkhead));
-       maybe_print_eds (controller, "ed_bulkcurrent", readl (&regs->ed_bulkcurrent));
+       maybe_print_eds (controller, "ed_controlhead",
+                       readl (&regs->ed_controlhead), next, size);
+       maybe_print_eds (controller, "ed_controlcurrent",
+                       readl (&regs->ed_controlcurrent), next, size);
+
+       maybe_print_eds (controller, "ed_bulkhead",
+                       readl (&regs->ed_bulkhead), next, size);
+       maybe_print_eds (controller, "ed_bulkcurrent",
+                       readl (&regs->ed_bulkcurrent), next, size);
+
+       maybe_print_eds (controller, "donehead",
+                       readl (&regs->donehead), next, size);
+}
+
+#define dbg_port_sw(hc,num,value,next,size) \
+       ohci_dbg_sw (hc, next, size, \
+               "roothub.portstatus [%d] " \
+               "0x%08x%s%s%s%s%s%s%s%s%s%s%s%s\n", \
+               num, temp, \
+               (temp & RH_PS_PRSC) ? " PRSC" : "", \
+               (temp & RH_PS_OCIC) ? " OCIC" : "", \
+               (temp & RH_PS_PSSC) ? " PSSC" : "", \
+               (temp & RH_PS_PESC) ? " PESC" : "", \
+               (temp & RH_PS_CSC) ? " CSC" : "", \
+               \
+               (temp & RH_PS_LSDA) ? " LSDA" : "", \
+               (temp & RH_PS_PPS) ? " PPS" : "", \
+               (temp & RH_PS_PRS) ? " PRS" : "", \
+               (temp & RH_PS_POCI) ? " POCI" : "", \
+               (temp & RH_PS_PSS) ? " PSS" : "", \
+               \
+               (temp & RH_PS_PES) ? " PES" : "", \
+               (temp & RH_PS_CCS) ? " CCS" : "" \
+               );
 
-       maybe_print_eds (controller, "donehead", readl (&regs->donehead));
-}
 
-static void ohci_dump_roothub (struct ohci_hcd *controller, int verbose)
+static void
+ohci_dump_roothub (
+       struct ohci_hcd *controller,
+       int verbose,
+       char **next,
+       unsigned *size)
 {
-       __u32                   temp, ndp, i;
+       u32                     temp, ndp, i;
 
        temp = roothub_a (controller);
        if (temp == ~(u32)0)
@@ -165,8 +225,8 @@
        ndp = (temp & RH_A_NDP);
 
        if (verbose) {
-               ohci_dbg (controller,
-                       "roothub.a: %08x POTPGT=%d%s%s%s%s%s NDP=%d\n", temp,
+               ohci_dbg_sw (controller, next, size,
+                       "roothub.a %08x POTPGT=%d%s%s%s%s%s NDP=%d\n", temp,
                        ((temp & RH_A_POTPGT) >> 24) & 0xff,
                        (temp & RH_A_NOCP) ? " NOCP" : "",
                        (temp & RH_A_OCPM) ? " OCPM" : "",
@@ -176,15 +236,15 @@
                        ndp
                        );
                temp = roothub_b (controller);
-               ohci_dbg (controller,
-                       "roothub.b: %08x PPCM=%04x DR=%04x\n",
+               ohci_dbg_sw (controller, next, size,
+                       "roothub.b %08x PPCM=%04x DR=%04x\n",
                        temp,
                        (temp & RH_B_PPCM) >> 16,
                        (temp & RH_B_DR)
                        );
                temp = roothub_status (controller);
-               ohci_dbg (controller,
-                       "roothub.status: %08x%s%s%s%s%s%s\n",
+               ohci_dbg_sw (controller, next, size,
+                       "roothub.status %08x%s%s%s%s%s%s\n",
                        temp,
                        (temp & RH_HS_CRWE) ? " CRWE" : "",
                        (temp & RH_HS_OCIC) ? " OCIC" : "",
@@ -194,10 +254,10 @@
                        (temp & RH_HS_LPS) ? " LPS" : ""
                        );
        }
-       
+
        for (i = 0; i < ndp; i++) {
                temp = roothub_portstatus (controller, i);
-               dbg_port (controller, "", i, temp);
+               dbg_port_sw (controller, i, temp, next, size);
        }
 }
 
@@ -206,11 +266,11 @@
        ohci_dbg (controller, "OHCI controller state\n");
 
        // dumps some of the state we know about
-       ohci_dump_status (controller);
+       ohci_dump_status (controller, NULL, 0);
        if (controller->hcca)
                ohci_dbg (controller,
                        "hcca frame #%04x\n", controller->hcca->frame_no);
-       ohci_dump_roothub (controller, 1);
+       ohci_dump_roothub (controller, 1, NULL, 0);
 }
 
 static const char data0 [] = "DATA0";
@@ -277,8 +337,7 @@
        u32     tmp = ed->hwINFO;
        char    *type = "";
 
-       ohci_dbg (ohci,
-               "%s, ed %p state 0x%x type %s; next ed %08x\n",
+       ohci_dbg (ohci, "%s, ed %p state 0x%x type %s; next ed %08x",
                label,
                ed, ed->state, edstring (ed->type),
                le32_to_cpup (&ed->hwNextED));
@@ -297,8 +356,7 @@
                0x000f & (le32_to_cpu (tmp) >> 7),
                type,
                0x007f & le32_to_cpu (tmp));
-       ohci_dbg (ohci,
-               "  tds: head %08x %s%s tail %08x%s",
+       ohci_dbg (ohci, "  tds: head %08x %s%s tail %08x%s",
                tmp = le32_to_cpup (&ed->hwHeadP),
                (ed->hwHeadP & ED_C) ? data1 : data0,
                (ed->hwHeadP & ED_H) ? " HALT" : "",
@@ -321,6 +379,8 @@
 #else
 static inline void ohci_dump (struct ohci_hcd *controller, int verbose) {}
 
+#undef OHCI_VERBOSE_DEBUG
+
 #endif /* DEBUG */
 
 /*-------------------------------------------------------------------------*/
@@ -359,7 +419,7 @@
                struct td               *td;
 
                temp = snprintf (buf, size,
-                       "ed/%p %cs dev%d ep%d-%s max %d %08x%s%s %s",
+                       "ed/%p %cs dev%d ep%d%s max %d %08x%s%s %s",
                        ed,
                        (info & ED_LOWSPEED) ? 'l' : 'f',
                        scratch & 0x7f,
@@ -475,7 +535,7 @@
                                u32     scratch = cpu_to_le32p (&ed->hwINFO);
 
                                temp = snprintf (next, size,
-                                       " (%cs dev%d%s ep%d-%s"
+                                       " (%cs dev%d%s ep%d%s"
                                        " max %d %08x%s%s)",
                                        (info & ED_LOWSPEED) ? 'l' : 'f',
                                        scratch & 0x7f,
@@ -518,11 +578,78 @@
 
 #undef DBG_SCHED_LIMIT
 
+static ssize_t
+show_registers (struct device *dev, char *buf)
+{
+       struct ohci_hcd         *ohci;
+       struct ohci_regs        *regs;
+       unsigned long           flags;
+       unsigned                temp, size;
+       char                    *next;
+       u32                     rdata;
+
+       ohci = dev_to_ohci(dev);
+       regs = ohci->regs;
+       next = buf;
+       size = PAGE_SIZE;
+
+       spin_lock_irqsave (&ohci->lock, flags);
+
+       /* dump driver info, then registers in spec order */
+
+       ohci_dbg_sw (ohci, &next, &size,
+               "%s version " DRIVER_VERSION "\n", hcd_name);
+
+       ohci_dump_status(ohci, &next, &size);
+
+       /* hcca */
+       if (ohci->hcca)
+               ohci_dbg_sw (ohci, &next, &size,
+                       "hcca frame 0x%04x\n", ohci->hcca->frame_no);
+
+       /* other registers mostly affect frame timings */
+       rdata = readl (&regs->fminterval);
+       temp = snprintf (next, size,
+                       "fmintvl 0x%08x %sFSMPS=0x%04x FI=0x%04x\n",
+                       rdata, (rdata >> 31) ? " FIT" : "",
+                       (rdata >> 16) & 0xefff, rdata & 0xffff);
+       size -= temp;
+       next += temp;
+
+       rdata = readl (&regs->fmremaining);
+       temp = snprintf (next, size, "fmremaining 0x%08x %sFR=0x%04x\n",
+                       rdata, (rdata >> 31) ? " FRT" : "",
+                       rdata & 0x3fff);
+       size -= temp;
+       next += temp;
+
+       rdata = readl (&regs->periodicstart);
+       temp = snprintf (next, size, "periodicstart 0x%04x\n",
+                       rdata & 0x3fff);
+       size -= temp;
+       next += temp;
+
+       rdata = readl (&regs->lsthresh);
+       temp = snprintf (next, size, "lsthresh 0x%04x\n",
+                       rdata & 0x3fff);
+       size -= temp;
+       next += temp;
+
+       /* roothub */
+       ohci_dump_roothub (ohci, 1, &next, &size);
+
+       spin_unlock_irqrestore (&ohci->lock, flags);
+
+       return PAGE_SIZE - size;
+}
+static DEVICE_ATTR (registers, S_IRUGO, show_registers, NULL);
+
+
 static inline void create_debug_files (struct ohci_hcd *bus)
 {
        device_create_file (bus->hcd.controller, &dev_attr_async);
        device_create_file (bus->hcd.controller, &dev_attr_periodic);
-       // registers
+       device_create_file (bus->hcd.controller, &dev_attr_registers);
        ohci_dbg (bus, "created debug files\n");
 }
 
@@ -530,6 +657,7 @@
 {
        device_remove_file (bus->hcd.controller, &dev_attr_async);
        device_remove_file (bus->hcd.controller, &dev_attr_periodic);
+       device_remove_file (bus->hcd.controller, &dev_attr_registers);
 }
 
 #endif
--- 1.61/drivers/usb/host/ohci-hcd.c    Tue Feb 18 09:35:35 2003
+++ edited/drivers/usb/host/ohci-hcd.c  Mon Feb 24 11:56:31 2003
@@ -17,6 +17,8 @@
  *
  * History:
  * 
+ * 2003/02/24 show registers in sysfs (Kevin Brosius)
+ *
  * 2002/09/03 get rid of ed hashtables, rework periodic scheduling and
  *     bandwidth accounting; if debugging, show schedules in driverfs
  * 2002/07/19 fixes to management of ED and schedule state.
@@ -104,11 +106,10 @@
  * TO DO:
  *
  *     - "disabled" and "sleeping" should be in hcd->state
- *     - bandwidth alloc to generic code
  *     - lots more testing!!
  */
 
-#define DRIVER_VERSION "2002-Sep-17"
+#define DRIVER_VERSION "2003 Feb 24"
 #define DRIVER_AUTHOR "Roman Weissgaerber, David Brownell"
 #define DRIVER_DESC "USB 1.1 'Open' Host Controller (OHCI) Driver"
 
@@ -276,6 +277,7 @@
        urb_print (urb, "UNLINK", 1);
 #endif           
 
+       spin_lock_irqsave (&ohci->lock, flags);
        if (!ohci->disabled) {
                urb_priv_t  *urb_priv;
 
@@ -283,21 +285,24 @@
                 * handed to us, flag it for unlink and giveback, and force
                 * some upcoming INTR_SF to call finish_unlinks()
                 */
-               spin_lock_irqsave (&ohci->lock, flags);
                urb_priv = urb->hcpriv;
                if (urb_priv) {
                        urb_priv->state = URB_DEL; 
                        if (urb_priv->ed->state == ED_OPER)
                                start_urb_unlink (ohci, urb_priv->ed);
                }
-               spin_unlock_irqrestore (&ohci->lock, flags);
        } else {
                /*
                 * with HC dead, we won't respect hc queue pointers
                 * any more ... just clean up every urb's memory.
                 */
-               finish_urb (ohci, urb, NULL);
+               if (urb->hcpriv) {
+                       spin_unlock (&ohci->lock);
+                       finish_urb (ohci, urb, NULL);
+                       spin_lock (&ohci->lock);
+               }
        }
+       spin_unlock_irqrestore (&ohci->lock, flags);
        return 0;
 }
 
@@ -597,7 +602,8 @@
         */
        spin_lock (&ohci->lock);
        if (ohci->ed_rm_list)
-               finish_unlinks (ohci, le16_to_cpu (ohci->hcca->frame_no), ptregs);
+               finish_unlinks (ohci, le16_to_cpu (ohci->hcca->frame_no),
+                               ptregs);
        if ((ints & OHCI_INTR_SF) != 0 && !ohci->ed_rm_list)
                writel (OHCI_INTR_SF, &regs->intrdisable);      
        spin_unlock (&ohci->lock);
--- 1.13/drivers/usb/host/ohci-pci.c    Tue Feb 18 09:35:35 2003
+++ edited/drivers/usb/host/ohci-pci.c  Mon Feb 24 11:30:39 2003
@@ -214,7 +214,7 @@
 
 #ifdef DEBUG
        /* the registers may look crazy here */
-       ohci_dump_status (ohci);
+       ohci_dump_status (ohci, 0, 0);
 #endif
 
        /* Re-enable bus mastering */
--- 1.60/drivers/usb/host/ohci-q.c      Wed Feb 19 07:05:57 2003
+++ edited/drivers/usb/host/ohci-q.c    Mon Feb 24 11:30:39 2003
@@ -30,21 +30,20 @@
 /*
  * URB goes back to driver, and isn't reissued.
  * It's completely gone from HC data structures.
- * PRECONDITION:  no locks held  (Giveback can call into HCD.)
+ * PRECONDITION:  no locks held, irqs blocked  (Giveback can call into HCD.)
  */
-static void finish_urb (struct ohci_hcd *ohci, struct urb *urb, struct pt_regs *regs)
+static void
+finish_urb (struct ohci_hcd *ohci, struct urb *urb, struct pt_regs *regs)
 {
-       unsigned long   flags;
-
        // ASSERT (urb->hcpriv != 0);
 
        urb_free_priv (ohci, urb->hcpriv);
        urb->hcpriv = NULL;
 
-       spin_lock_irqsave (&urb->lock, flags);
+       spin_lock (&urb->lock);
        if (likely (urb->status == -EINPROGRESS))
                urb->status = 0;
-       spin_unlock_irqrestore (&urb->lock, flags);
+       spin_unlock (&urb->lock);
 
        // what lock protects these?
        switch (usb_pipetype (urb->pipe)) {
@@ -850,7 +849,8 @@
 #define tick_before(t1,t2) ((((s16)(t1))-((s16)(t2))) < 0)
 
 /* there are some urbs/eds to unlink; called in_irq(), with HCD locked */
-static void finish_unlinks (struct ohci_hcd *ohci, u16 tick, struct pt_regs *regs)
+static void
+finish_unlinks (struct ohci_hcd *ohci, u16 tick, struct pt_regs *regs)
 {
        struct ed       *ed, **last;
 
@@ -978,7 +978,8 @@
  * path is finish_unlinks(), which unlinks URBs using ed_rm_list, instead of
  * scanning the (re-reversed) donelist as this does.
  */
-static void dl_done_list (struct ohci_hcd *ohci, struct td *td, struct pt_regs *regs)
+static void
+dl_done_list (struct ohci_hcd *ohci, struct td *td, struct pt_regs *regs)
 {
        unsigned long   flags;
 
@@ -995,9 +996,9 @@
 
                /* If all this urb's TDs are done, call complete() */
                if (urb_priv->td_cnt == urb_priv->length) {
-                       spin_unlock_irqrestore (&ohci->lock, flags);
+                       spin_unlock (&ohci->lock);
                        finish_urb (ohci, urb, regs);
-                       spin_lock_irqsave (&ohci->lock, flags);
+                       spin_lock (&ohci->lock);
                }
 
                /* clean schedule:  unlink EDs that are no longer busy */

Reply via email to