]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/usb/host/ehci-hcd.c
USB: EHCI: fix handling of dead controllers
[linux-2.6-omap-h63xx.git] / drivers / usb / host / ehci-hcd.c
index 8409e0705d6365c34e6db7252cc39eb60575877a..4725d15d096f559fc833d0e0f6323bcff4aa7631 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/ioport.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
+#include <linux/vmalloc.h>
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/timer.h>
@@ -59,7 +60,6 @@
  * providing early devices for those host controllers to talk to!
  */
 
-#define DRIVER_VERSION "10 Dec 2004"
 #define DRIVER_AUTHOR "David Brownell"
 #define DRIVER_DESC "USB 2.0 'Enhanced' Host Controller (EHCI) Driver"
 
@@ -620,9 +620,9 @@ static int ehci_run (struct usb_hcd *hcd)
 
        temp = HC_VERSION(ehci_readl(ehci, &ehci->caps->hc_capbase));
        ehci_info (ehci,
-               "USB %x.%x started, EHCI %x.%02x, driver %s%s\n",
+               "USB %x.%x started, EHCI %x.%02x%s\n",
                ((ehci->sbrn & 0xf0)>>4), (ehci->sbrn & 0x0f),
-               temp >> 8, temp & 0xff, DRIVER_VERSION,
+               temp >> 8, temp & 0xff,
                ignore_oc ? ", overcurrent ignored" : "");
 
        ehci_writel(ehci, INTR_MASK,
@@ -643,7 +643,7 @@ static int ehci_run (struct usb_hcd *hcd)
 static irqreturn_t ehci_irq (struct usb_hcd *hcd)
 {
        struct ehci_hcd         *ehci = hcd_to_ehci (hcd);
-       u32                     status, pcd_status = 0, cmd;
+       u32                     status, masked_status, pcd_status = 0, cmd;
        int                     bh;
 
        spin_lock (&ehci->lock);
@@ -656,14 +656,14 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
                goto dead;
        }
 
-       status &= INTR_MASK;
-       if (!status) {                  /* irq sharing? */
+       masked_status = status & INTR_MASK;
+       if (!masked_status) {           /* irq sharing? */
                spin_unlock(&ehci->lock);
                return IRQ_NONE;
        }
 
        /* clear (just) interrupts */
-       ehci_writel(ehci, status, &ehci->regs->status);
+       ehci_writel(ehci, masked_status, &ehci->regs->status);
        cmd = ehci_readl(ehci, &ehci->regs->command);
        bh = 0;
 
@@ -706,7 +706,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
                pcd_status = status;
 
                /* resume root hub? */
-               if (!(ehci_readl(ehci, &ehci->regs->command) & CMD_RUN))
+               if (!(cmd & CMD_RUN))
                        usb_hcd_resume_root_hub(hcd);
 
                while (i--) {
@@ -715,8 +715,11 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
 
                        if (pstatus & PORT_OWNER)
                                continue;
-                       if (!(pstatus & PORT_RESUME)
-                                       || ehci->reset_done [i] != 0)
+                       if (!(test_bit(i, &ehci->suspended_ports) &&
+                                       ((pstatus & PORT_RESUME) ||
+                                               !(pstatus & PORT_SUSPEND)) &&
+                                       (pstatus & PORT_PE) &&
+                                       ehci->reset_done[i] == 0))
                                continue;
 
                        /* start 20 msec resume signaling from this port,
@@ -731,19 +734,17 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
 
        /* PCI errors [4.15.2.4] */
        if (unlikely ((status & STS_FATAL) != 0)) {
-               dbg_cmd (ehci, "fatal", ehci_readl(ehci,
-                                                  &ehci->regs->command));
-               dbg_status (ehci, "fatal", status);
-               if (status & STS_HALT) {
-                       ehci_err (ehci, "fatal error\n");
+               ehci_err(ehci, "fatal error\n");
+               dbg_cmd(ehci, "fatal", cmd);
+               dbg_status(ehci, "fatal", status);
+               ehci_halt(ehci);
 dead:
-                       ehci_reset (ehci);
-                       ehci_writel(ehci, 0, &ehci->regs->configured_flag);
-                       /* generic layer kills/unlinks all urbs, then
-                        * uses ehci_stop to clean up the rest
-                        */
-                       bh = 1;
-               }
+               ehci_reset(ehci);
+               ehci_writel(ehci, 0, &ehci->regs->configured_flag);
+               /* generic layer kills/unlinks all urbs, then
+                * uses ehci_stop to clean up the rest
+                */
+               bh = 1;
        }
 
        if (bh)
@@ -994,9 +995,7 @@ static int ehci_get_frame (struct usb_hcd *hcd)
 
 /*-------------------------------------------------------------------------*/
 
-#define DRIVER_INFO DRIVER_VERSION " " DRIVER_DESC
-
-MODULE_DESCRIPTION (DRIVER_INFO);
+MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_AUTHOR (DRIVER_AUTHOR);
 MODULE_LICENSE ("GPL");
 
@@ -1020,11 +1019,6 @@ MODULE_LICENSE ("GPL");
 #define        PS3_SYSTEM_BUS_DRIVER   ps3_ehci_driver
 #endif
 
-#if defined(CONFIG_440EPX) && !defined(CONFIG_PPC_MERGE)
-#include "ehci-ppc-soc.c"
-#define        PLATFORM_DRIVER         ehci_ppc_soc_driver
-#endif
-
 #ifdef CONFIG_USB_EHCI_HCD_PPC_OF
 #include "ehci-ppc-of.c"
 #define OF_PLATFORM_DRIVER     ehci_hcd_ppc_of_driver
@@ -1049,6 +1043,16 @@ static int __init ehci_hcd_init(void)
 {
        int retval = 0;
 
+       if (usb_disabled())
+               return -ENODEV;
+
+       printk(KERN_INFO "%s: " DRIVER_DESC "\n", hcd_name);
+       set_bit(USB_EHCI_LOADED, &usb_hcds_loaded);
+       if (test_bit(USB_UHCI_LOADED, &usb_hcds_loaded) ||
+                       test_bit(USB_OHCI_LOADED, &usb_hcds_loaded))
+               printk(KERN_WARNING "Warning! ehci_hcd should always be loaded"
+                               " before uhci_hcd and ohci_hcd, not after\n");
+
        pr_debug("%s: block sizes: qh %Zd qtd %Zd itd %Zd sitd %Zd\n",
                 hcd_name,
                 sizeof(struct ehci_qh), sizeof(struct ehci_qtd),
@@ -1056,8 +1060,10 @@ static int __init ehci_hcd_init(void)
 
 #ifdef DEBUG
        ehci_debug_root = debugfs_create_dir("ehci", NULL);
-       if (!ehci_debug_root)
-               return -ENOENT;
+       if (!ehci_debug_root) {
+               retval = -ENOENT;
+               goto err_debug;
+       }
 #endif
 
 #ifdef PLATFORM_DRIVER
@@ -1104,7 +1110,9 @@ clean0:
 #ifdef DEBUG
        debugfs_remove(ehci_debug_root);
        ehci_debug_root = NULL;
+err_debug:
 #endif
+       clear_bit(USB_EHCI_LOADED, &usb_hcds_loaded);
        return retval;
 }
 module_init(ehci_hcd_init);
@@ -1126,6 +1134,7 @@ static void __exit ehci_hcd_cleanup(void)
 #ifdef DEBUG
        debugfs_remove(ehci_debug_root);
 #endif
+       clear_bit(USB_EHCI_LOADED, &usb_hcds_loaded);
 }
 module_exit(ehci_hcd_cleanup);