Re: Lost remote wakeup

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

 



On Tue, 14 Jul 2009, Yang Fei-AFY095 wrote:

> Time0: Suspend one port - selective suspend. By calling ehci_control
> with typeReq=SetPortFeature and wValue=USB_PORT_FEAT_SUSPEND;
> 
> Time1: Remote wakeup from device triggers an STS_PCD interrupt , handled
> by ehci_irq;
> 
> Time2: The ISR falls into if (status & STS_PCD), at this moment EHCI is
> still running (global suspend is expected to come shortly after
> selective suspend), so usb_hcd_resume_root_hub doesn't get called;
> 
> Time3: In the while loop, since PORT_RESUME is set for the port being
> waked up, rh_timer is set to fire 20ms later;
> 
> Time4: At the end of ehci_irq, usb_hcd_poll_rh_status is called, nothing
> happens here because ehci_hub_status_data returns 0, reason being
> time_after_eq(jiffies, ehci->reset_done) is false as ehci->reset_done
> has been set to 20ms later in Time3;
> 
> Time5: EHCI is halted - global suspend scheduled by the host driver.
> Time between Time0 and Time5 is about 20ms;
> 
> Time6: rh_timer fires. Time between Time3 and Time6 is 20ms (set in
> ehci_irq). rh_timer_func -> usb_hcd_poll_rh_status ->
> ehci_hub_status_data. Still nothing happens this time because
> ehci_hub_status_data returns 0 again as it falls into the	first if
> statement if (!HC_IS_RUNNING(hcd->state)) (EHCI has been halted in
> Time5, so hcd->state is SUSPENDED now).
> 
> The consequence is that the remote wakeup gets lost, the host doesn't
> resume the bus as expected.

What you're really saying is that we need to improve the way we handle
the race between suspending a root hub and receiving a remote wakeup on
one of its ports.  The way we do it now, the remote wakeup event can
get lost.

You are right.  I haven't had time to write a patch, but I think we 
need to do something like this at the start of ehci_bus_suspend:

	First, write 0 to the intr_enable register.  This will
	prevent us from seeing any future wakeup events.

	Next, if any ports are in the middle of a resume sequence
	(reset_done[port] is nonzero), we have to wait for the
	resumes to finish and handle all the post-resume actions.

	Then go ahead with suspending the root hub and re-enabling
	interrupt requests.

	Finally at the end, if we did encounter any in-progress
	resumes, call usb_hcd_resume_root_hub.

Probably all the host controller drivers will need similar changes.
Does that sound like it will solve your problem?

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