Commit f8159fb5 authored by David Brownell's avatar David Brownell Committed by Greg Kroah-Hartman

[PATCH] USB: hcd initialization fix

This cleans up HCD initialization by adding an explicit
reset step, putting the device into a known state before
resources are allocated.  This step is implemented for
EHCI, since some BIOS firmware seems to act quirky there,
but nothing else yet.  (OHCI would be just easy too.)
parent 355581e7
......@@ -122,10 +122,9 @@ int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id)
base = (void *) resource;
}
// driver->start(), later on, will transfer device from
// driver->reset(), later on, will transfer device from
// control by SMM/BIOS to control by Linux (if needed)
pci_set_master (dev);
hcd = driver->hcd_alloc ();
if (hcd == NULL){
dbg ("hcd alloc fail");
......@@ -140,6 +139,9 @@ int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id)
return retval;
}
}
hcd->regs = base;
hcd->region = region;
pci_set_drvdata (dev, hcd);
hcd->driver = driver;
hcd->description = driver->description;
......@@ -157,22 +159,27 @@ int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id)
dev_info (hcd->controller, "%s\n", hcd->product_desc);
/* till now HC has been in an indeterminate state ... */
if (driver->reset && (retval = driver->reset (hcd)) < 0) {
dev_err (hcd->controller, "can't reset\n");
goto clean_3;
}
pci_set_master (dev);
#ifndef __sparc__
sprintf (buf, "%d", dev->irq);
#else
bufp = __irq_itoa(dev->irq);
#endif
if (request_irq (dev->irq, usb_hcd_irq, SA_SHIRQ, hcd->description, hcd)
!= 0) {
retval = request_irq (dev->irq, usb_hcd_irq, SA_SHIRQ,
hcd->description, hcd);
if (retval != 0) {
dev_err (hcd->controller,
"request interrupt %s failed\n", bufp);
retval = -EBUSY;
goto clean_3;
}
hcd->irq = dev->irq;
hcd->regs = base;
hcd->region = region;
dev_info (hcd->controller, "irq %s, %s %p\n", bufp,
(driver->flags & HCD_MEMORY) ? "pci mem" : "io base",
base);
......
......@@ -173,6 +173,7 @@ struct hc_driver {
#define HCD_USB2 0x0020 /* USB 2.0 */
/* called to init HCD and root hub */
int (*reset) (struct usb_hcd *hcd);
int (*start) (struct usb_hcd *hcd);
/* called after all devices were suspended */
......
......@@ -318,28 +318,21 @@ ehci_reboot (struct notifier_block *self, unsigned long code, void *null)
/* called by khubd or root hub init threads */
static int ehci_start (struct usb_hcd *hcd)
static int ehci_hc_reset (struct usb_hcd *hcd)
{
struct ehci_hcd *ehci = hcd_to_ehci (hcd);
u32 temp;
struct usb_device *udev;
struct usb_bus *bus;
int retval;
u32 hcc_params;
u8 tempbyte;
spin_lock_init (&ehci->lock);
ehci->caps = (struct ehci_caps *) hcd->regs;
ehci->regs = (struct ehci_regs *) (hcd->regs +
readb (&ehci->caps->length));
dbg_hcs_params (ehci, "ehci_start");
dbg_hcc_params (ehci, "ehci_start");
hcc_params = readl (&ehci->caps->hcc_params);
dbg_hcs_params (ehci, "reset");
dbg_hcc_params (ehci, "reset");
/* EHCI 0.96 and later may have "extended capabilities" */
temp = HCC_EXT_CAPS (hcc_params);
temp = HCC_EXT_CAPS (readl (&ehci->caps->hcc_params));
while (temp) {
u32 cap;
......@@ -364,8 +357,18 @@ static int ehci_start (struct usb_hcd *hcd)
ehci->hcs_params = readl (&ehci->caps->hcs_params);
/* force HC to halt state */
if ((retval = ehci_halt (ehci)) != 0)
return retval;
return ehci_halt (ehci);
}
static int ehci_start (struct usb_hcd *hcd)
{
struct ehci_hcd *ehci = hcd_to_ehci (hcd);
u32 temp;
struct usb_device *udev;
struct usb_bus *bus;
int retval;
u32 hcc_params;
u8 tempbyte;
/*
* hw default: 1K periodic list heads, one per frame.
......@@ -376,6 +379,7 @@ static int ehci_start (struct usb_hcd *hcd)
return retval;
/* controllers may cache some of the periodic schedule ... */
hcc_params = readl (&ehci->caps->hcc_params);
if (HCC_ISOC_CACHE (hcc_params)) // full frame cache
ehci->i_thresh = 8;
else // N microframes cached
......@@ -937,6 +941,7 @@ static const struct hc_driver ehci_driver = {
/*
* basic lifecycle operations
*/
.reset = ehci_hc_reset,
.start = ehci_start,
#ifdef CONFIG_PM
.suspend = ehci_suspend,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment