Platform-specific suspend/resume code in drivers

Alan Stern stern at rowland.harvard.edu
Tue Jun 7 08:06:50 PDT 2016


On Tue, 7 Jun 2016, Mason wrote:

> Hello everyone,
> 
> I want to implement system-wide suspend-to-RAM on my platform
> (an ARM Cortex A9 based SoC).
> 
> I'm hoping some of you can clear some of my confusion :-(
> 
> AFAIU, what happens to the hardware in the suspended state is
> very board/platform specific. The SoC may stop some clocks;
> it may even cut the power to some parts of the chip.
> 
> AFAIU, once power is cut, the value of internal and visible
> registers (called "state" or "context" IIUC) is lost.
> 
> Therefore, each driver is supposed to either
> 
> 1) save context on suspend & restore it on resume, or
> 2) re-initialize the device on resume (if context is unimportant)
> 
> Is that correct?

Yes.

> (Note: Kevin Hilman mentioned using a feature called "regmap" to
> help in saving/restoring context.)
> 
> Documentation/power/devices.txt mentions putting such save/restore
> code in suspend_late/resume_early callbacks. Is that the preferred
> solution today?

It depends on the device's requirements.  If you require interrupts to
be enabled while you do the save/restore then you can't use
suspend_late/resume_early; you have to use suspend/resume.

> Should these routines be guarded by #ifdef CONFIG_PM or #ifdef CONFIG_SUSPEND ?

CONFIG_SUSPEND.

> Another point of confusion for me is this: drivers are supposed to
> be shared among platforms, right? So my platform-specific suspend
> code should be enabled only if my platform is detected at run-time?

Is your device platform-specific?  If it is then the driver is also
platform-specific, and so no part of the driver will be called at
runtime unless your platform is detected.

If the device isn't platform-specific then the driver has to work on a 
bunch of different platforms.  It should be written to be 
platform-independent as much as possible.

> So this means I need to add in the probe function, for every driver
> my platform uses:
> 
>   if (platform == MY_PLATFORM) {
>     ops.suspend = my_suspend;
>     ops.resume  = my_resume;
>   }
> 
> Is that correct?

No.  For one thing, you only have to worry about the 
platform-independent drivers -- you know that the platform-specific 
ones won't get used unless your platform is present.

For another, the driver should be written in a way that doesn't require
this sort of code.  The ops pointer (not any of the structure's members
-- a pointer to the structure) should be set by the platform-dependent
part of the driver that handles initialization.

> While I'm listing the points I don't understand... It seems Linux
> handles suspend/resume "transparently". I mean the CPU calls all
> the functions leading to the suspend action, then when the system
> comes back online, it continues at the next instruction, as if
> nothing had happened. So the stack and registers need to be exactly
> in the same state.
> 
> But on my system, the firmware expects a return address for *where*
> to return on resume. Should I pass it the next instruction pointer?
> The address of the resume function?

You should pass it the address of a function you write, one that will 
clean things up and jump into the normal system resume code.

Alan Stern




More information about the linux-arm-kernel mailing list