Fixed
Created: Jan 17, 2018
Updated: Dec 3, 2018
Resolved Date: Mar 2, 2018
Found In Version: 9.0.0.4
Fix Version: 9.0.0.15
Severity: Standard
Applicable for: Wind River Linux 9
Component/s: Kernel
We encountered following logs when tested USB devices:
ohci-platform 664a0800.usb: frame counter not updating; disabled
ohci-platform 664a0800.usb: HC died; cleaning up
As a result of further investigation, we found ohci->prev_frame_no in io_watchdog_func() is overwritten.
I checked the source code and found that following scenario can occur if ohci_urb_enqueue() and io_watchdog_func() run concurrently:
ohci_urb_enqueue()
...
spin_lock_irqsave (&ohci->lock, flags);
...
io_watchdog_func()
spin_lock_irqsave(&ohci->lock, flags);
...
<waiting for spin lock>
...
if (!timer_pending(&ohci->io_watchdog) &&
list_empty(&ohci->eds_in_use)) {
ohci->prev_frame_no = ohci_frame_no(ohci);
mod_timer(&ohci->io_watchdog,
jiffies + IO_WATCHDOG_DELAY);
}
...
spin_unlock_irqrestore (&ohci->lock, flags);
...
<get spin lock>
...
frame_no = ohci_frame_no(ohci);
if (frame_no == ohci->prev_frame_no) {
Because timer_pending() in ohci_urb_enqueue() returns false if the timer handler, io_watchdog_func(), is running, ohci->prev_frame_no can be set before mod_timer(). On the other hand, io_watchdog_func() reads OHCI frame number into frame_no variable. This frame_no must equal ohci->prev_frame_no which is set by ohci_urb_enqueue() right before. Therefore, io_watchdog_func() detects false alarm.