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 (®s->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 (®s->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 (®s->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 (®s->intrstatus));
- ohci_dump_intr_mask (controller, "intrenable", readl (®s->intrenable));
+ ohci_dump_intr_mask (controller, "intrstatus",
+ readl (®s->intrstatus), next, size);
+ ohci_dump_intr_mask (controller, "intrenable",
+ readl (®s->intrenable), next, size);
// intrdisable always same as intrenable
- maybe_print_eds (controller, "ed_periodcurrent", readl
(®s->ed_periodcurrent));
-
- maybe_print_eds (controller, "ed_controlhead", readl (®s->ed_controlhead));
- maybe_print_eds (controller, "ed_controlcurrent", readl
(®s->ed_controlcurrent));
+ maybe_print_eds (controller, "ed_periodcurrent",
+ readl (®s->ed_periodcurrent), next, size);
- maybe_print_eds (controller, "ed_bulkhead", readl (®s->ed_bulkhead));
- maybe_print_eds (controller, "ed_bulkcurrent", readl (®s->ed_bulkcurrent));
+ maybe_print_eds (controller, "ed_controlhead",
+ readl (®s->ed_controlhead), next, size);
+ maybe_print_eds (controller, "ed_controlcurrent",
+ readl (®s->ed_controlcurrent), next, size);
+
+ maybe_print_eds (controller, "ed_bulkhead",
+ readl (®s->ed_bulkhead), next, size);
+ maybe_print_eds (controller, "ed_bulkcurrent",
+ readl (®s->ed_bulkcurrent), next, size);
+
+ maybe_print_eds (controller, "donehead",
+ readl (®s->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 (®s->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 (®s->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 (®s->fmremaining);
+ temp = snprintf (next, size, "fmremaining 0x%08x %sFR=0x%04x\n",
+ rdata, (rdata >> 31) ? " FRT" : "",
+ rdata & 0x3fff);
+ size -= temp;
+ next += temp;
+
+ rdata = readl (®s->periodicstart);
+ temp = snprintf (next, size, "periodicstart 0x%04x\n",
+ rdata & 0x3fff);
+ size -= temp;
+ next += temp;
+
+ rdata = readl (®s->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, ®s->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 */
