Re: FW: ehci->watchdog timer panic

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Mon, 29 Jun 2009, Yang Fei-AFY095 wrote:

> Hello All,
> 
> I am looking for some advice on the correct method for utlising the
> ehci_bus_suspend() function on an OMAP3 device. On the OMAP3 device the
> usbhost controller is in a separate internal power-domain. So when the
> usbhost is inactive or suspend is called, we can disable clocks and
> power-down the usbhost to save power.
> 
> Recently we found that after calling ehci_bus_suspend() and disabling
> the usbhost clocks we would see the ehci watchdog timer event fire. This
> was causing a kernel panic because the usbhost controllers clocks were
> disabled and inside the watchdog timer function the clocks were not
> being re-enabled, so when the ehci registers were accessed this resulted
> in a CPU data-abort. 
> 
> From reviewing the ehci_bus_suspend() function, I do see that after
> deleting any pending watchdog timer events, there is a called made to
> ehci_work() (see below code snippet). From looking at the ehci_work()
> function it does appear to be possible that another watchdog timer event
> could be scheduled, but I have been unable to confirm this.

ehci_work can enable the watchdog timer.

> Unfortunately, this failure is not easily reproduced. 
> 
>  --- snip --- 
> 
> static int ehci_bus_suspend (struct usb_hcd *hcd) {
>         struct ehci_hcd         *ehci = hcd_to_ehci (hcd);
>         int                     port;
>         int                     mask;
> 
>         ehci_dbg(ehci, "suspend root hub\n");
> 
>         if (time_before (jiffies, ehci->next_statechange))
>                 msleep(5);
>         del_timer_sync(&ehci->watchdog);
>         del_timer_sync(&ehci->iaa_watchdog);
> 
>         port = HCS_N_PORTS (ehci->hcs_params);
>         spin_lock_irq (&ehci->lock);
> 
>         /* stop schedules, clean any completed work */
>         if (HC_IS_RUNNING(hcd->state)) {
>                 ehci_quiesce (ehci);
>                 hcd->state = HC_STATE_QUIESCING;
>         }
>         ehci->command = ehci_readl(ehci, &ehci->regs->command);
>         ehci_work(ehci);
> 
>  --- snip ---
> 
> Hence, I wanted to ask the following questions:
> 
> 1). Theoretically is it possible that a call to ehci_work() during the
> suspend could cause another watchdog timer event to be scheduled?

In theory, maybe.  It's hard to examine all the possible code paths to 
tell for sure.  But whatever timer event is pending, it can't be 
important.

> 2). If there is a watchdog event pending after calling
> ehci_bus_suspend(), should we:
> a). Make the function, ehci_bus_suspend, return an error code -EBUSY to
> indicate there is still work pending? See below.

No.

> b). Make the function calling the ehci_bus_suspend, returns an error to
> indicate that we could not disable the clocks and suspend failed?

No.  Simply add another call to del_timer_sync at the very end of 
ehci_bus_suspend (after the spin_unlock_irq).  Include a comment 
explaining that ehci_work may have re-enabled the timer, so it has to 
be turned off again.

Alan Stern

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux