USB: EHCI: fix handling of dead controllers
authorAlan Stern <stern@rowland.harvard.edu>
Wed, 12 Nov 2008 22:04:53 +0000 (17:04 -0500)
committerGreg Kroah-Hartman <gregkh@suse.de>
Thu, 13 Nov 2008 22:45:05 +0000 (14:45 -0800)
This patch (as1165) makes a few small changes in the logic used by
ehci-hcd when it encounters a controller error:

Instead of printing out the masked status, it prints the
original status as read directly from the hardware.

It doesn't check for the STS_HALT status bit before taking
action.  The mere fact that the STS_FATAL bit is set means
that something bad has happened and the controller needs to
be reset.  With the old code this test could never succeed
because the STS_HALT bit was masked out from the status.

I anticipate that this will prevent the occasional "irq X: nobody cared"
problem people encounter when their EHCI controllers die.

Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Cc: David Brownell <david-b@pacbell.net>
Cc: stable <stable@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/usb/host/ehci-hcd.c

index 15a803b..4725d15 100644 (file)
@@ -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;
 
@@ -734,18 +734,17 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
 
        /* PCI errors [4.15.2.4] */
        if (unlikely ((status & STS_FATAL) != 0)) {
+               ehci_err(ehci, "fatal error\n");
                dbg_cmd(ehci, "fatal", cmd);
                dbg_status(ehci, "fatal", status);
-               if (status & STS_HALT) {
-                       ehci_err (ehci, "fatal error\n");
+               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)