USB suspend/resume

Hans Petter Selasky hselasky at c2i.net
Sat Jun 4 20:13:37 UTC 2011


On Saturday 04 June 2011 19:08:22 Gavin Atkinson wrote:
> Hi all,
> 
> I've been trying to get a IBM ThinkPad X60 suspend/resume working
> correctly, and discovered that with uhci loaded, the machine would hang on
> resume.  This is on head, but I believe this is aslo the cause of the
> laptop not resuming on stable/8.
> 
> It turns out that this is because we sleep in the resume path.  The resume
> path appears to run with interrupts disabled, and as a result we never
> wake up.  A comment above uhci_suspend() saggests similar:
> 
> 	/* NOTE: suspend/resume is called from
> 	 * interrupt context and cannot sleep!
> 
> However, we do sleep.  We call usb_pause_mtx() several times during both
> tthe suspend and resume path, and on resume this is fatal.
> usb_pause_mtx() will use DELAY() when called before the machine has
> finished booting (ie cold != 0), but will call pause() once booted. To
> prove this, I've tested the following gross hack, which fixes
> suspend/resume on the ThinkPad X60:
> 
> Index: sys/dev/usb/controller/ehci_pci.c
> ===================================================================
> --- sys/dev/usb/controller/ehci_pci.c	(revision 222417)
> +++ sys/dev/usb/controller/ehci_pci.c	(working copy)
> @@ -118,10 +118,16 @@
>  ehci_pci_resume(device_t self)
>  {
>  	ehci_softc_t *sc = device_get_softc(self);
> +	int mycold;
> 
> +	mycold = cold;
> +	cold = 1;
> +
>  	ehci_pci_takecontroller(self);
>  	ehci_resume(sc);
> 
> +	cold = mycold;
> +
>  	bus_generic_resume(self);
> 
>  	return (0);
> Index: sys/dev/usb/controller/uhci_pci.c
> ===================================================================
> --- sys/dev/usb/controller/uhci_pci.c	(revision 222417)
> +++ sys/dev/usb/controller/uhci_pci.c	(working copy)
> @@ -104,11 +104,17 @@
>  uhci_pci_resume(device_t self)
>  {
>  	uhci_softc_t *sc = device_get_softc(self);
> +	int mycold;
> 
> +	mycold = cold;
> +	cold = 1;
> +
>  	pci_write_config(self, PCI_LEGSUP, PCI_LEGSUP_USBPIRQDEN, 2);
> 
>  	uhci_resume(sc);
> 
> +	cold = mycold;
> +
>  	bus_generic_resume(self);
>  	return (0);
>  }
> 
> 
> The above hack fixes this X60 and allows suspend/resume to work, and USB
> devices work perfectly after the suspend/resume.  Other controllers look
> like they may also be affected  - at least ohci does the same.
> 
> So, I guess my question to the USB experts is:  What is the correct fix?
> I see two possibilities:
> 
> 1) Have a variable somewhere called "suspres" or similar, which is set at
>    the start of the suspend, and cleared at the end of the resume.
>    usb_pause_mtx() then changes it's behaviour on (cold || suspres).
>    This may have to be a global variable, being incremented on suspend and
>    decremented on resume, as we don't pass a softc into usb_pause_mtx(),
>    however then we have issues relating to when one controller suspends
>    before the others, or resume before the others.
> 
> 2) Kick off a separate task to do the resume.  Problems with this is thet
>    it doesn't fix the suspend path, but also that we may need to rely on
>    USB being back before the rest of the resume completes. (What happens
>    if we have / or another filesystem mounted from a USB device?)
> 
> I guess #1 is the simplest solution, and should have fewest side effects,
> however it does mean that every attachment would need to be modified in
> order to set and clear the variable.  It sort of feels like this should be
> handled more centrally, but I'm not sure of the best way to achieve this.
> 
> Any [other] suggestions?
> 
> Gavin

Where is it documented that the resume/suspend callbacks are not run from a 
thread context?

--HPS


More information about the freebsd-usb mailing list