ChangeSet 1.1002.3.1, 2003/02/20 10:17:07-08:00, david-b@pacbell.net [PATCH] USB: sync with some 2.4 ohci fixes, prepare for backport The 2.5 version branched from 2.4.5 or so, and since then a couple hardware-specific tweaks were merged to 2.4; this teaches 2.5 about NatSemi SUPERIO and PA-RISC quirks. This also uses os/version neutral HCD calls to register the root hub and find the HCD's bus. It also adds os/version neutral macros for its diagnostic macros. Most of those changes have been split out separately, but the macros and a few uses of them weren't naturally splittable. Also a couple minor cleanups, like removing CVS ids, having only one copy of a routine used with the debug files, and getting rid of some inline #ifdefs. drivers/usb/host/ohci-dbg.c | 26 +++++++++++--------- drivers/usb/host/ohci-hcd.c | 53 +++++++++++++++++++++++++++-------------- drivers/usb/host/ohci-hub.c | 3 -- drivers/usb/host/ohci-pci.c | 44 ++++++++++++++++++++-------------- drivers/usb/host/ohci-q.c | 27 ++++++++------------ drivers/usb/host/ohci-sa1111.c | 10 ------- drivers/usb/host/ohci.h | 23 +++++++++++++++++ 7 files changed, 112 insertions(+), 74 deletions(-) diff -Nru a/drivers/usb/host/ohci-dbg.c b/drivers/usb/host/ohci-dbg.c --- a/drivers/usb/host/ohci-dbg.c Fri Feb 28 14:52:14 2003 +++ b/drivers/usb/host/ohci-dbg.c Fri Feb 28 14:52:14 2003 @@ -5,7 +5,6 @@ * (C) Copyright 2000-2002 David Brownell * * This file is licenced under the GPL. - * $Id: ohci-dbg.c,v 1.4 2002/03/27 20:40:40 dbrownell Exp $ */ /*-------------------------------------------------------------------------*/ @@ -318,8 +317,6 @@ } } -#define DRIVERFS_DEBUG_FILES /* only on 2.5 versions */ - #else static inline void ohci_dump (struct ohci_hcd *controller, int verbose) {} @@ -327,7 +324,19 @@ /*-------------------------------------------------------------------------*/ -#ifdef DRIVERFS_DEBUG_FILES +#ifdef STUB_DEBUG_FILES + +static inline void create_debug_files (struct ohci_hcd *bus) { } +static inline void remove_debug_files (struct ohci_hcd *bus) { } + +#else + +static inline struct ohci_hcd *dev_to_ohci (struct device *dev) +{ + struct usb_hcd *hcd = dev_get_drvdata (dev); + + return hcd_to_ohci (hcd); +} static ssize_t show_list (struct ohci_hcd *ohci, char *buf, size_t count, struct ed *ed) @@ -513,7 +522,7 @@ device_create_file (bus->hcd.controller, &dev_attr_async); device_create_file (bus->hcd.controller, &dev_attr_periodic); // registers - dev_dbg (bus->hcd.controller, "created debug files\n"); + ohci_dbg (bus, "created debug files\n"); } static inline void remove_debug_files (struct ohci_hcd *bus) @@ -522,12 +531,7 @@ device_remove_file (bus->hcd.controller, &dev_attr_periodic); } -#else /* empty stubs for creating those files */ - -static inline void create_debug_files (struct ohci_hcd *bus) { } -static inline void remove_debug_files (struct ohci_hcd *bus) { } - -#endif /* DRIVERFS_DEBUG_FILES */ +#endif /*-------------------------------------------------------------------------*/ diff -Nru a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c --- a/drivers/usb/host/ohci-hcd.c Fri Feb 28 14:52:14 2003 +++ b/drivers/usb/host/ohci-hcd.c Fri Feb 28 14:52:14 2003 @@ -125,6 +125,8 @@ /*-------------------------------------------------------------------------*/ +static const char hcd_name [] = "ohci-hcd"; + #include "ohci.h" static inline void disable (struct ohci_hcd *ohci) @@ -381,9 +383,12 @@ { u32 temp; - /* SMM owns the HC? not for long! */ + /* SMM owns the HC? not for long! + * On PA-RISC, PDC can leave IR set incorrectly; ignore it there. + */ +#ifndef __hppa__ if (readl (&ohci->regs->control) & OHCI_CTRL_IR) { - dev_dbg (ohci->hcd.controller, "USB HC TakeOver from BIOS/SMM\n"); + ohci_dbg (ohci, "USB HC TakeOver from BIOS/SMM\n"); /* this timeout is arbitrary. we make it long, so systems * depending on usb keyboards may be usable even if the @@ -396,17 +401,18 @@ while (readl (&ohci->regs->control) & OHCI_CTRL_IR) { wait_ms (10); if (--temp == 0) { - dev_err (ohci->hcd.controller, "USB HC TakeOver failed!\n"); + ohci_err (ohci, "USB HC TakeOver failed!\n"); return -1; } } } +#endif /* Disable HC interrupts */ writel (OHCI_INTR_MIE, &ohci->regs->intrdisable); - dev_dbg (ohci->hcd.controller, "USB HC reset_hc %s: ctrl = 0x%x ;\n", - ohci->hcd.self.bus_name, + ohci_dbg (ohci, "USB HC reset_hc %s: ctrl = 0x%x ;\n", + hcd_to_bus (&ohci->hcd)->bus_name, readl (&ohci->regs->control)); /* Reset USB (needed by some controllers); RemoteWakeupConnected @@ -451,8 +457,9 @@ */ static int hc_start (struct ohci_hcd *ohci) { - u32 mask; + u32 mask, tmp; struct usb_device *udev; + struct usb_bus *bus; spin_lock_init (&ohci->lock); ohci->disabled = 1; @@ -493,9 +500,20 @@ writel (mask, &ohci->regs->intrstatus); writel (mask, &ohci->regs->intrenable); - /* hub power always on: required for AMD-756 and some Mac platforms */ - writel ((roothub_a (ohci) | RH_A_NPS) & ~(RH_A_PSM | RH_A_OCPM), - &ohci->regs->roothub.a); + /* handle root hub init quirks ... */ + tmp = roothub_a (ohci); + tmp &= ~(RH_A_PSM | RH_A_OCPM); + if (ohci->flags & OHCI_QUIRK_SUPERIO) { + /* NSC 87560 and maybe others */ + tmp |= RH_A_NOCP; + tmp &= ~(RH_A_POTPGT | RH_A_NPS); + } else { + /* hub power always on; required for AMD-756 and some + * Mac platforms, use this mode everywhere by default + */ + tmp |= RH_A_NPS; + } + writel (tmp, &ohci->regs->roothub.a); writel (RH_HS_LPSC, &ohci->regs->roothub.status); writel (0, &ohci->regs->roothub.b); @@ -503,7 +521,8 @@ mdelay ((roothub_a (ohci) >> 23) & 0x1fe); /* connect the virtual root hub */ - ohci->hcd.self.root_hub = udev = usb_alloc_dev (NULL, &ohci->hcd.self); + bus = hcd_to_bus (&ohci->hcd); + bus->root_hub = udev = usb_alloc_dev (NULL, bus); ohci->hcd.state = USB_STATE_READY; if (!udev) { disable (ohci); @@ -514,9 +533,9 @@ usb_connect (udev); udev->speed = USB_SPEED_FULL; - if (usb_register_root_hub (udev, ohci->hcd.controller) != 0) { + if (hcd_register_root (&ohci->hcd) != 0) { usb_put_dev (udev); - ohci->hcd.self.root_hub = NULL; + bus->root_hub = NULL; disable (ohci); ohci->hc_control &= ~OHCI_CTRL_HCFS; writel (ohci->hc_control, &ohci->regs->control); @@ -629,8 +648,8 @@ ohci->disabled = 1; ohci->sleeping = 0; - if (ohci->hcd.self.root_hub) - usb_disconnect (&ohci->hcd.self.root_hub); + if (hcd_to_bus (&ohci->hcd)->root_hub) + usb_disconnect (&hcd_to_bus (&ohci->hcd)->root_hub); /* empty the interrupt branches */ for (i = 0; i < NUM_INTS; i++) ohci->load [i] = 0; @@ -644,17 +663,15 @@ ohci->ed_bulktail = NULL; if ((temp = hc_reset (ohci)) < 0 || (temp = hc_start (ohci)) < 0) { - err ("can't restart %s, %d", ohci->hcd.self.bus_name, temp); + ohci_err (ohci, "can't restart, %d\n", temp); return temp; } else - dbg ("restart %s completed", ohci->hcd.self.bus_name); + ohci_dbg (ohci, "restart complete\n"); return 0; } #endif /*-------------------------------------------------------------------------*/ - -static const char hcd_name [] = "ohci-hcd"; #define DRIVER_INFO DRIVER_VERSION " " DRIVER_DESC diff -Nru a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c --- a/drivers/usb/host/ohci-hub.c Fri Feb 28 14:52:14 2003 +++ b/drivers/usb/host/ohci-hub.c Fri Feb 28 14:52:14 2003 @@ -5,7 +5,6 @@ * (C) Copyright 2000-2002 David Brownell * * This file is licenced under GPL - * $Id: ohci-hub.c,v 1.3 2002/03/22 16:04:54 dbrownell Exp $ */ /*-------------------------------------------------------------------------*/ @@ -159,7 +158,7 @@ u16 wLength ) { struct ohci_hcd *ohci = hcd_to_ohci (hcd); - int ports = hcd->self.root_hub->maxchild; + int ports = hcd_to_bus (hcd)->root_hub->maxchild; u32 temp; int retval = 0; diff -Nru a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c --- a/drivers/usb/host/ohci-pci.c Fri Feb 28 14:52:14 2003 +++ b/drivers/usb/host/ohci-pci.c Fri Feb 28 14:52:14 2003 @@ -29,17 +29,6 @@ /*-------------------------------------------------------------------------*/ -struct ohci_hcd *dev_to_ohci(struct device *dev) { - struct pci_dev *pdev = - container_of (dev, struct pci_dev, dev); - struct ohci_hcd *ohci = - container_of (pci_get_drvdata (pdev), struct ohci_hcd, hcd); - - return ohci; -} - -/*-------------------------------------------------------------------------*/ - static int __devinit ohci_pci_start (struct usb_hcd *hcd) { @@ -55,22 +44,43 @@ /* AMD 756, for most chips (early revs), corrupts register * values on read ... so enable the vendor workaround. */ - if (hcd->pdev->vendor == 0x1022 + if (hcd->pdev->vendor == PCI_VENDOR_ID_AMD && hcd->pdev->device == 0x740c) { ohci->flags = OHCI_QUIRK_AMD756; - info ("%s: AMD756 erratum 4 workaround", - hcd->self.bus_name); + ohci_info (ohci, "AMD756 erratum 4 workaround\n"); } + /* FIXME for some of the early AMD 760 southbridges, OHCI + * won't work at all. blacklist them. + */ + /* Apple's OHCI driver has a lot of bizarre workarounds * for this chip. Evidently control and bulk lists * can get confused. (B&W G3 models, and ...) */ - else if (hcd->pdev->vendor == 0x1045 + else if (hcd->pdev->vendor == PCI_VENDOR_ID_OPTI && hcd->pdev->device == 0xc861) { - info ("%s: WARNING: OPTi workarounds unavailable", - hcd->self.bus_name); + ohci_info (ohci, + "WARNING: OPTi workarounds unavailable\n"); + } + + /* Check for NSC87560. We have to look at the bridge (fn1) to + * identify the USB (fn2). This quirk might apply to more or + * even all NSC stuff. + */ + else if (hcd->pdev->vendor == PCI_VENDOR_ID_NS) { + struct pci_dev *b, *hc; + + hc = hcd->pdev; + b = pci_find_slot (hc->bus->number, + PCI_DEVFN (PCI_SLOT (hc->devfn), 1)); + if (b && b->device == PCI_DEVICE_ID_NS_87560_LIO + && b->vendor == PCI_VENDOR_ID_NS) { + ohci->flags |= OHCI_QUIRK_SUPERIO; + ohci_info (ohci, "Using NSC SuperIO setup\n"); + } } + } memset (ohci->hcca, 0, sizeof (struct ohci_hcca)); diff -Nru a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c --- a/drivers/usb/host/ohci-q.c Fri Feb 28 14:52:14 2003 +++ b/drivers/usb/host/ohci-q.c Fri Feb 28 14:52:14 2003 @@ -49,10 +49,10 @@ // what lock protects these? switch (usb_pipetype (urb->pipe)) { case PIPE_ISOCHRONOUS: - ohci->hcd.self.bandwidth_isoc_reqs--; + hcd_to_bus (&ohci->hcd)->bandwidth_isoc_reqs--; break; case PIPE_INTERRUPT: - ohci->hcd.self.bandwidth_int_reqs--; + hcd_to_bus (&ohci->hcd)->bandwidth_int_reqs--; break; } @@ -143,7 +143,7 @@ } ohci->load [i] += ed->load; } - ohci->hcd.self.bandwidth_allocated += ed->load / ed->interval; + hcd_to_bus (&ohci->hcd)->bandwidth_allocated += ed->load / ed->interval; } /* link an ed into one of the HC chains */ @@ -244,14 +244,11 @@ } ohci->load [i] -= ed->load; } - ohci->hcd.self.bandwidth_allocated -= ed->load / ed->interval; + hcd_to_bus (&ohci->hcd)->bandwidth_allocated -= ed->load / ed->interval; -#ifdef OHCI_VERBOSE_DEBUG - dbg ("%s: unlink %sed %p branch %d [%dus.], interval %d", - ohci->hcd.self.bus_name, + ohci_vdbg (ohci, "unlink %sed %p branch %d [%dus.], interval %d\n", (ed->hwINFO & ED_ISO) ? "iso " : "", ed, ed->branch, ed->load, ed->interval); -#endif } /* unlink an ed from one of the HC chains. @@ -576,7 +573,7 @@ */ case PIPE_INTERRUPT: /* ... and periodic urbs have extra accounting */ - ohci->hcd.self.bandwidth_int_reqs++; + hcd_to_bus (&ohci->hcd)->bandwidth_int_reqs++; /* FALLTHROUGH */ case PIPE_BULK: info = is_out @@ -644,7 +641,7 @@ data + urb->iso_frame_desc [cnt].offset, urb->iso_frame_desc [cnt].length, urb, cnt); } - ohci->hcd.self.bandwidth_isoc_reqs++; + hcd_to_bus (&ohci->hcd)->bandwidth_isoc_reqs++; break; } // ASSERT (urb_priv->length == cnt); @@ -687,11 +684,10 @@ urb->iso_frame_desc [td->index].actual_length = dlen; urb->iso_frame_desc [td->index].status = cc_to_error [cc]; -#ifdef VERBOSE_DEBUG if (cc != TD_CC_NOERROR) - dbg (" urb %p iso TD %p (%d) len %d CC %d", + ohci_vdbg (ohci, + "urb %p iso td %p (%d) len %d cc %d\n", urb, td, 1 + td->index, dlen, cc); -#endif /* BULK, INT, CONTROL ... drivers see aggregate length/status, * except that "setup" bytes aren't counted and "short" transfers @@ -730,13 +726,12 @@ - td->data_dma; } -#ifdef VERBOSE_DEBUG if (cc != TD_CC_NOERROR && cc < 0x0E) - dbg (" urb %p TD %p (%d) CC %d, len=%d/%d", + ohci_vdbg (ohci, + "urb %p td %p (%d) cc %d, len=%d/%d\n", urb, td, 1 + td->index, cc, urb->actual_length, urb->transfer_buffer_length); -#endif } } diff -Nru a/drivers/usb/host/ohci-sa1111.c b/drivers/usb/host/ohci-sa1111.c --- a/drivers/usb/host/ohci-sa1111.c Fri Feb 28 14:52:14 2003 +++ b/drivers/usb/host/ohci-sa1111.c Fri Feb 28 14:52:14 2003 @@ -3,7 +3,7 @@ * * (C) Copyright 1999 Roman Weissgaerber * (C) Copyright 2000-2002 David Brownell - * (C) Hewlett-Packard Company + * (C) Copyright 2002 Hewlett-Packard Company * * SA1111 Bus Glue * @@ -24,14 +24,6 @@ #endif extern int usb_disabled(void); - -/*-------------------------------------------------------------------------*/ - -struct ohci_hcd *dev_to_ohci(struct device *dev) { - struct usb_hcd *hcd = dev->driver_data; - - return hcd_to_ohci(hcd); -} /*-------------------------------------------------------------------------*/ diff -Nru a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h --- a/drivers/usb/host/ohci.h Fri Feb 28 14:52:14 2003 +++ b/drivers/usb/host/ohci.h Fri Feb 28 14:52:14 2003 @@ -372,6 +372,7 @@ unsigned long flags; /* for HC bugs */ #define OHCI_QUIRK_AMD756 0x01 /* erratum #4 */ +#define OHCI_QUIRK_SUPERIO 0x02 /* natsemi */ // there are also chip quirks/bugs in init logic /* @@ -382,4 +383,24 @@ #define hcd_to_ohci(hcd_ptr) container_of(hcd_ptr, struct ohci_hcd, hcd) -struct ohci_hcd *dev_to_ohci(struct device *); +/*-------------------------------------------------------------------------*/ + +#ifndef DEBUG +#define STUB_DEBUG_FILES +#endif /* DEBUG */ + +#define ohci_dbg(ohci, fmt, args...) \ + dev_dbg ((ohci)->hcd.controller , fmt , ## args ) +#define ohci_err(ohci, fmt, args...) \ + dev_err ((ohci)->hcd.controller , fmt , ## args ) +#define ohci_info(ohci, fmt, args...) \ + dev_info ((ohci)->hcd.controller , fmt , ## args ) +#define ohci_warn(ohci, fmt, args...) \ + dev_warn ((ohci)->hcd.controller , fmt , ## args ) + +#ifdef OHCI_VERBOSE_DEBUG +# define ohci_vdbg ohci_dbg +#else +# define ohci_vdbg(ohci, fmt, args...) do { } while (0) +#endif +