Skip to content

Commit

Permalink
USB: ohci-hcd.c: Add spinlock when disabling OHCI interrupts in ohci_…
Browse files Browse the repository at this point in the history
…shutdown

This patch is used for fixing 'irq nobody care' issue during reboot

How to reproduce:
1)Prepare weston enabled environment
2)Connect USB mouse
3)Read input from the mouse and reboot
$ od -tx /dev/input/event0 &
$ reboot
4)Move the mouse while system shutdown
Don't need to move the mouse after "reboot: Restarting system"
5)Repeat step 3 and step 4 until below error occurs

Error log:
usb 2-1: USB disconnect, device number 2
irq 156: nobody cared (try booting with the "irqpoll" option)
Workqueue: usb_hub_wq hub_event
Call trace:
...
usbhid_disconnect+0x4c/0x78
usb_unbind_interface+0x6c/0x2a8
device_release_driver_internal+0x174/0x208
device_release_driver+0x14/0x20
bus_remove_device+0x114/0x128
device_del+0x1ac/0x300
usb_disable_device+0x8c/0x200
usb_disconnect+0xb4/0x218
...
handlers:
usb_hcd_irq
Disabling IRQ xen-troops#156

This issue occurs due to race condition between ohci_irq()
interrupt handler and ohci_shutdown()
Adding spin_lock_irq() to prevent interrupt raising while ohci is shutting
down can fix this issue.

When host controller dies, lock will be held by io_watchdog_func before
ohci_shutdown, so locking should be skipped in this case to prevent
deadlock

Signed-off-by: Tho Vu <tho.vu.wh@rvc.renesas.com>
  • Loading branch information
thohuongtranvu authored and r-kataok committed Mar 22, 2019
1 parent 1381140 commit 42378b1
Showing 1 changed file with 10 additions and 1 deletion.
11 changes: 10 additions & 1 deletion drivers/usb/host/ohci-hcd.c
Original file line number Diff line number Diff line change
Expand Up @@ -424,15 +424,24 @@ ohci_shutdown (struct usb_hcd *hcd)
struct ohci_hcd *ohci;

ohci = hcd_to_ohci (hcd);
ohci_writel(ohci, (u32) ~0, &ohci->regs->intrdisable);

/* Locking is not necessary if HC dies */
if (!test_bit(HCD_FLAG_DEAD, &hcd->flags))
spin_lock_irq(&ohci->lock);

/* Disable HC interrupts */
ohci_writel(ohci, (u32)~0, &ohci->regs->intrdisable);
/* Software reset, after which the controller goes into SUSPEND */
ohci_writel(ohci, OHCI_HCR, &ohci->regs->cmdstatus);
ohci_readl(ohci, &ohci->regs->cmdstatus); /* flush the writes */
udelay(10);

ohci_writel(ohci, ohci->fminterval, &ohci->regs->fminterval);
ohci->rh_state = OHCI_RH_HALTED;

if (!test_bit(HCD_FLAG_DEAD, &hcd->flags))
spin_unlock_irq(&ohci->lock);

}

/*-------------------------------------------------------------------------*
Expand Down

0 comments on commit 42378b1

Please sign in to comment.