summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/usb/host/ohci-hcd.c23
1 files changed, 13 insertions, 10 deletions
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index 704f33fdd2f1..ecfe800fd720 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -732,24 +732,27 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
struct ohci_regs __iomem *regs = ohci->regs;
int ints;
- /* we can eliminate a (slow) ohci_readl()
- * if _only_ WDH caused this irq
+ /* Read interrupt status (and flush pending writes). We ignore the
+ * optimization of checking the LSB of hcca->done_head; it doesn't
+ * work on all systems (edge triggering for OHCI can be a factor).
*/
- if ((ohci->hcca->done_head != 0)
- && ! (hc32_to_cpup (ohci, &ohci->hcca->done_head)
- & 0x01)) {
- ints = OHCI_INTR_WDH;
+ ints = ohci_readl(ohci, &regs->intrstatus);
- /* cardbus/... hardware gone before remove() */
- } else if ((ints = ohci_readl (ohci, &regs->intrstatus)) == ~(u32)0) {
+ /* Check for an all 1's result which is a typical consequence
+ * of dead, unclocked, or unplugged (CardBus...) devices
+ */
+ if (ints == ~(u32)0) {
disable (ohci);
ohci_dbg (ohci, "device removed!\n");
return IRQ_HANDLED;
+ }
+
+ /* We only care about interrupts that are enabled */
+ ints &= ohci_readl(ohci, &regs->intrenable);
/* interrupt for some other device? */
- } else if ((ints &= ohci_readl (ohci, &regs->intrenable)) == 0) {
+ if (ints == 0)
return IRQ_NOTMINE;
- }
if (ints & OHCI_INTR_UE) {
// e.g. due to PCI Master/Target Abort