|
@@ -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
|