dev_pm_ops and PCMCIA sockets

Alan Stern stern at rowland.harvard.edu
Mon Mar 15 13:09:55 EDT 2010


On Mon, 15 Mar 2010, Dominik Brodowski wrote:

> Hey,
> 
> attempting to use the "new-style" dev_pm_ops to handle the suspend / resume
> needs of PCMCIA sockets gives me a headache. Maybe you can assist me in
> doing it properly?
> 
> (1) PCMCIA/CardBus sockets all share one class:
> 	 struct class pcmcia_socket_class
>     The "class" devices (which are struct *device now) are registered in
>     drivers/pcmcia/cs.c . The functional ordering is:
> 
> 
> 	struct device *dev	-- some PCMCIA/CardBus bridge

On some bus, such as PCI, right?

> 	struct device *dev	-- of class pcmcia_socket_class; represents
> 				   the socket. One bridge may have mutliple
> 				   sockets.

This is the "class" device, not registered on any bus, right?

> 	struct device *dev	-- of bus "pcmcia" or "pci"; represents the
> 				   PCMCIA/CardBus card. One card is in one
> 				   socket; but one card may have multiple
> 				   "pcmcia" or "pci" devices.
> 
> 
> (2) For suspend, we need the following order:
> 
> 	1) CardBus and PCMCIA cards themselves;
> 	   IRQs may be on.
> 
> 	   For CardBus, this is well handled by the PCI subsystem; for
> 	   PCMCIA cards, we currently rely on an old-style "suspend"
> 	   callback in struct bus_type .
> 
> 	2) the PCMCIA/CardBus socket ("class devices"); IRQs may be on
> 
> 	   Currently, we rely on an ugly, custom callback mechanism. Quoting
> 	   drivers/pcmcia/cs.c:
> 
> 	    * socket drivers are expected to use the following callbacks in
> 	    * their .drv struct:
> 	    *  - pcmcia_socket_dev_suspend
> 	    *  - pcmcia_socket_dev_resume
> 	    * These functions check for the appropriate struct pcmcia_soket arrays,
> 	    * and pass them to the low-level functions pcmcia_{suspend,resume}_socket

Okay, these callbacks could theoretically be put into a class-level
dev_pm_ops structure.

> 	3) The PCMCIA/CardBus bridge devices; both with IRQs on and off
> 
> 	   For example, yenta_socket appropriately uses "struct dev_pm_ops".
> 
> 
> (3) For resume, it's a bit more complicated:
> 
> 	1) The PCMCIA/CardBus bridge devices with IRQs off
> 
> 	2) The PCMCIA/CardBus sockets ("class devices") with IRQs off

It's a little odd that sockets need to have a noirq resume stage but
not a noirq suspend stage.

> 	3) the PCMCIA/CardBus bridge devices with IRQs on
> 
> 	4) The PCMCIA/CardBus sockets ("class devices") with IRQs on
> 
> 	5) CardBus and PCMCIA cards themselves
> 
> 
> (4) A first attempt to use struct dev_pm_ops in struct class pcmcia_socket_class
> 
> + const struct dev_pm_ops pcmcia_socket_pm_ops = {
> + 	/* dev_suspend, dev_resume may be called with IRQs enabled */
> + 	SET_SYSTEM_SLEEP_PM_OPS(pcmcia_socket_classdev_suspend,
> + 				pcmcia_socket_classdev_resume)
> + 
> + 	/* early resume must be called with IRQs disabled */
> + 	.resume_noirq = pcmcia_socket_classdev_resume_noirq,
> + 	.thaw_noirq = pcmcia_socket_classdev_resume_noirq,
> + 	.restore_noirq = pcmcia_socket_classdev_resume_noirq,
> + };
> 
>     lead to the following issues:
> 
>      a) resume_noirq never got called. Haven't tried thaw_noirq and
> 	restore_noirq so far.

They won't be called either.  I don't know whether this counts as a bug 
or a feature, but the fact is that currently the PM core doesn't invoke 
the noirq callbacks for classes or types -- only for buses.

If Rafael agrees that it is a bug, then it should be easy enough to 
fix.

>      b) If I read the information about ordering in Documentation/power/devices.txt
>         correctly, even a functioning _noirq callback for classes would
> 	cause the order for suspend to be:
> 
> 	- IRQs on, classes first, devices next:
> 		PCMCIA/CardBus socket (is 1, should be 2)
> 		PCMCIA/CardBus cards (is 2, should be 1)
> 
> 		PCMCIA/CardBus bridge devices (is 3)
> 
> 	- IRQs off:
> 		PCMCIA/CardBus bridge devices (is 3)
> 
>         and for resume to be:
> 
> 	- IRQs off, devices first, classes next:
> 
> 		PCMCIA/CardBus bridge devices (is 1)
> 		PCMCIA/CardBus socket         (is 2)
> 
> 	- IRQs on, devices first, classes next:
> 
> 		PCMCIA/CardBus bridge	      (is 3)
> 		PCMCIA/CardBus cards	      (is 4, should be 5)
> 		PCMCIA/CardBus socket	      (is 5, should be 4)

No, that's not how it works.  For suspend, each phase (IRQs off and
IRQs on) goes up the device tree.  And for each device during the IRQs
on phase, the PM core invokes class callbacks, then type, then bus, so
you'd get:

	IRQs on:
		cards (class, type, bus),
		then sockets (class, type, bus),
		then bridges (class, type, bus)

	IRQs off:
		cards (bus only),
		then sockets (bus only),
		then bridges (bus only).

Note that in the IRQs-on phase, there can be legacy callbacks for the 
class and bus, but not for the type.

Resume works exactly the same as this, but in the reverse order.  
According to your description, this should be what you need.

> Any ideas on how to resolve these issues using the new-stlye dev_pm_ops?

Assuming you don't want to put the socket devices on a bus (there 
probably is no suitable bus anyway), the answer is to add class and 
type noirq callbacks.  Take a look at device_suspend_noirq() and 
device_resume_noirq() in drivers/base/power/main.c to see what's 
involved.

Alan Stern




More information about the linux-pcmcia mailing list