Wind River Support Network

HomeDefectsLIN10-3459
Fixed

LIN10-3459 : Possible false detection of stopped frame counter in OHCI io_watdhdog_func()

Created: Mar 4, 2018    Updated: Dec 3, 2018
Resolved Date: Apr 24, 2018
Found In Version: 10.17.41.1
Fix Version: 10.17.41.7
Severity: Standard
Applicable for: Wind River Linux LTS 17
Component/s: Kernel

Description

We encountered following logs when we tested the 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.

Other Downloads


Live chat
Online