USB: EHCI: fix handling of dead controllers

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>
This commit is contained in:
Alan Stern 2008-11-12 17:04:53 -05:00 committed by Greg Kroah-Hartman
parent 5863964608
commit 67b2e02974

View File

@ -643,7 +643,7 @@ static int ehci_run (struct usb_hcd *hcd)
static irqreturn_t ehci_irq (struct usb_hcd *hcd) static irqreturn_t ehci_irq (struct usb_hcd *hcd)
{ {
struct ehci_hcd *ehci = hcd_to_ehci (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; int bh;
spin_lock (&ehci->lock); spin_lock (&ehci->lock);
@ -656,14 +656,14 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
goto dead; goto dead;
} }
status &= INTR_MASK; masked_status = status & INTR_MASK;
if (!status) { /* irq sharing? */ if (!masked_status) { /* irq sharing? */
spin_unlock(&ehci->lock); spin_unlock(&ehci->lock);
return IRQ_NONE; return IRQ_NONE;
} }
/* clear (just) interrupts */ /* 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); cmd = ehci_readl(ehci, &ehci->regs->command);
bh = 0; bh = 0;
@ -734,18 +734,17 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
/* PCI errors [4.15.2.4] */ /* PCI errors [4.15.2.4] */
if (unlikely ((status & STS_FATAL) != 0)) { if (unlikely ((status & STS_FATAL) != 0)) {
ehci_err(ehci, "fatal error\n");
dbg_cmd(ehci, "fatal", cmd); dbg_cmd(ehci, "fatal", cmd);
dbg_status(ehci, "fatal", status); dbg_status(ehci, "fatal", status);
if (status & STS_HALT) { ehci_halt(ehci);
ehci_err (ehci, "fatal error\n");
dead: dead:
ehci_reset (ehci); ehci_reset(ehci);
ehci_writel(ehci, 0, &ehci->regs->configured_flag); ehci_writel(ehci, 0, &ehci->regs->configured_flag);
/* generic layer kills/unlinks all urbs, then /* generic layer kills/unlinks all urbs, then
* uses ehci_stop to clean up the rest * uses ehci_stop to clean up the rest
*/ */
bh = 1; bh = 1;
}
} }
if (bh) if (bh)