Skip to content

Commit fe81f35

Browse files
groeckgregkh
authored andcommitted
usb: ohci: Prevent missed ohci interrupts
Testing ohci functionality with qemu's pci-ohci emulation often results in ohci interface stalls, resulting in hung task timeouts. The problem is caused by lost interrupts between the emulation and the Linux kernel code. Additional interrupts raised while the ohci interrupt handler in Linux is running and before the handler clears the interrupt status are not handled. The fix for a similar problem in ehci suggests that the problem is likely caused by edge-triggered MSI interrupts. See commit 0b60557 ("usb: ehci: Prevent missed ehci interrupts with edge-triggered MSI") for details. Ensure that the ohci interrupt code handles all pending interrupts before returning to solve the problem. Cc: Gerd Hoffmann <[email protected]> Cc: David Laight <[email protected]> Cc: [email protected] Fixes: 306c54d ("usb: hcd: Try MSI interrupts on PCI devices") Signed-off-by: Guenter Roeck <[email protected]> Reviewed-by: Alan Stern <[email protected]> Reviewed-by: Gerd Hoffmann <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent f2004e8 commit fe81f35

File tree

1 file changed

+8
-0
lines changed

1 file changed

+8
-0
lines changed

drivers/usb/host/ohci-hcd.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -888,6 +888,7 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
888888
/* Check for an all 1's result which is a typical consequence
889889
* of dead, unclocked, or unplugged (CardBus...) devices
890890
*/
891+
again:
891892
if (ints == ~(u32)0) {
892893
ohci->rh_state = OHCI_RH_HALTED;
893894
ohci_dbg (ohci, "device removed!\n");
@@ -982,6 +983,13 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
982983
}
983984
spin_unlock(&ohci->lock);
984985

986+
/* repeat until all enabled interrupts are handled */
987+
if (ohci->rh_state != OHCI_RH_HALTED) {
988+
ints = ohci_readl(ohci, &regs->intrstatus);
989+
if (ints && (ints & ohci_readl(ohci, &regs->intrenable)))
990+
goto again;
991+
}
992+
985993
return IRQ_HANDLED;
986994
}
987995

0 commit comments

Comments
 (0)