diff options
-rw-r--r-- | drivers/usb/host/ohci-hcd.c | 23 |
1 files changed, 13 insertions, 10 deletions
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 704f33fdd2f..ecfe800fd72 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, ®s->intrstatus); - /* cardbus/... hardware gone before remove() */ - } else if ((ints = ohci_readl (ohci, ®s->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, ®s->intrenable); /* interrupt for some other device? */ - } else if ((ints &= ohci_readl (ohci, ®s->intrenable)) == 0) { + if (ints == 0) return IRQ_NOTMINE; - } if (ints & OHCI_INTR_UE) { // e.g. due to PCI Master/Target Abort |