[RFC PATCH] Current status, suspend-to-disk support on ARM

Rafael J. Wysocki rjw at sisk.pl
Wed Apr 13 17:38:02 EDT 2011


On Wednesday, April 13, 2011, Frank Hofmann wrote:
> 
> On Tue, 12 Apr 2011, Pavel Machek wrote:
> 
> > Hi!
> [ ... ]
> >> But then on all architectures in kernels as far back as 2.6.32 it
> >> doesn't look like save/restore_processor state are actually
> >> adjusting the preempt count; nowhere do they call
> >> preempt_enable/disable.
> >
> > You might need to dig a bit more. IIRC it manipulated FPU or something
> > long time ago.
> 
> Actually, it's the other way round - kernel_fpu_begin/end are users of 
> preempt_disable/enable, quote Documentation/preempt-locking.txt:
> 
>  	Note, some FPU functions are already explicitly preempt safe.  For example,
>  	kernel_fpu_begin and kernel_fpu_end will disable and enable preemption.
>  	However, math_state_restore must be called with preemption disabled.
> 
> But kernel_fpu_begin/end functions are x86-specific. At best, that makes 
> the comment in hibernate.c (which refers to "needing" preempt_dis/enable) 
> misleading.

This comment is outright wrong in fact, sorry about that.  Evidently,
restore_processor_state() is called right after the "restore control flow
magically appears here" comment and it _does_ use the saved state.

I'll remove that comment.

> x86, in this, is an odd one out, though, in ; On ARM, for example, saving 
> the FP context happens through a PM notifier.
> 
> In addition, it seems that the code (at least in hibernate.c, 
> create_image) does anyway:
> 
>  	- go single-cpu (disables all but current)
>  	- switch interrupts off (local_irq_disable)
> 
> before going into save_processor_state - wouldn't that mean all conditions 
> for nonpreemptable (or all conditions for a stable FP state) are already 
> met by that time ?

Yes, it does.

> >> Finally, on things like e.g. the floating point context saves:
> >> Wouldn't this happen as part of freezing processes (in the early
> >> stages of suspend), and/or as part of device quiesce ?
> >
> > Are you sure? I thought we have (had?) concept of lazy FPU
> > saving... and occassionaly kernel uses FPU too (with some
> > precautions).
> 
> speaking in particular for ARM, I'd deflect the answer to:
> 
>  	http://www.spinics.net/lists/linux-pm/msg22839.html
> 
> It's lazy but it does happen ... without any specific need to have the 
> "bracketing" that save/restore_processor_state are doing.

save/restore_processor_state() are arch-specific and do whatever is necessary
or useful for the given architecture.  The saving/restoring of the FPU state
at those points happens to be useful for x86 IIRC.

> Food for thought:
> 
> I mean, the code in hibernate.c really looks like this (quote):
> 
> 
> static int create_image(int platform_mode)
> {
>          int error;
> 
>          error = arch_prepare_suspend();				<===== platform hook 1

Architecture hook rather and it would have been one if there had been any
architecture actually providing anything different from a NOP.  IOW, to be
removed (forgot about it last time I did a code cleanup).

> [ ... ]
>          error = dpm_suspend_noirq(PMSG_FREEZE);			<===== platform hook 2

Not really.  This is a device core callback for the last stage of device freeze.

> [ ... ]
>          error = platform_pre_snapshot(platform_mode);		<===== platform hook 3

This is a platform hook.

> [ ... ]
>          error = disable_nonboot_cpus();				<===== platform hook 4

Not a platform hook.  This one disables the nonboot CPUs using hotplug and this
mechanism is supposed to work that way on all platforms.

> [ ... ]
>          error = sysdev_suspend(PMSG_FREEZE);			<===== ...
>          if (!error)
>                  error = syscore_suspend();			<===== ...
> [ ... ]

These suspend things that are "below" devices (like interrupt controllers
and such stuff) and by no means are platform hooks.

>          in_suspend = 1;
>          save_processor_state();					<===== platform hook N-1

This is an architecture hook for saving the state of the boot CPU.

>          error = swsusp_arch_suspend();				<===== platform hook N

This one is needed on x86 so that we can point the CPU to the original
page tables after we've restored the target kernel from the image.

> [ ... ]
>          restore_processor_state();				<===== platform hook N+1
> [ ... ]
> 
> And that's _without_ the platform hibernation ops hooks code in 
> hibernate(), which calls this one.

Actually not without, platform_pre_snapshot() is one of those.

> This code is full of places where to plug save/restore code (or any sort 
> of "bracketing" begin/finish hooks) into.
> It's surprising that with all these hooks existing already, "bracketing" 
> of swsusp_arch_suspend() by save/restore_processor state is so sacrosanct.
> 
> These are _three_ arch-dependent hooks in three consecutive lines of code.
> 
> If a platform requires the bracketing, why can it not do that part in 
> syscore_suspend() ? Or why not simply embed it in swsusp_arch_suspend() ?

save/restore_processor_state() are also used by the x86's suspend to RAM code.
Of course, you can argue that they should be kept x86-specific, but since
those features were originally developed on x86, the code still remains
x86-centric in that respect.

> As said, wrt. to save/restore_processor_state, x86 is definitely the odd 
> one out (and not a good example) with the monstrosity of code; all other 
> architectures either have trivial or even completely empty code for
> save/restore_processor_state().
> 
> Should we really force everyone to provide an (as good as) empty hook just 
> because x86 at one point had chosen to have it ?

I don't see much reason for that, but since none of the guys who implemented
those empty hooks has ever complained and/or attempted to change things, there
has not been much reason to work in that direction. :-)

> >>>> @@ -195,6 +195,14 @@ config VECTORS_BASE
> >>>> 	help
> >>>> 	  The base address of exception vectors.
> >>>>
> >>>> +config ARCH_HIBERNATION_POSSIBLE
> >>>> +	bool
> >>>> +	help
> >>>> +	  If the machine architecture supports suspend-to-disk
> >>>> +	  it should select this automatically for you.
> >>>> +	  Otherwise, say 'Y' at your own peril.
> >>>> +
> >>>
> >>> Good for debugging, but not good for mainline.
> >>
> >> How would this be done better ?
> >
> > Just set the ARCH_HIBERNATION_POSSIBLE=y in the ARM code now that ARM
> > can do it. No need to ask user.
> 
> I.e. preferrably:
> 
>  	config ARCH_HIBERNATION_POSSIBLE
>  		def_bool n

You don't need to use "def_bool n", "bool" alone will do just fine.

> plus the "select" within the actual platform config subsection for those 
> that have it.
> 
> To stress the point: "ARM can do it" would be an exaggeration even if 
> those changes went in, because only some ARM types will have it.
> 
> The situation on ARM is identical to e.g. SuperH, see arch/sh/Kconfig,
> 
> config SUPERH32
>          def_bool ARCH = "sh"
> [ ... various ... ]
>          select ARCH_HIBERNATION_POSSIBLE if MMU
> 
> config ARCH_HIBERNATION_POSSIBLE
>          def_bool n
> 

Yes, something like this.

> >> @@ -412,8 +413,7 @@ static int resume_target_kernel(bool platform_mode)
> >>  	if (error)
> >>  		goto Enable_irqs;
> >>
> >> -	/* We'll ignore saved state, but this gets preempt count (etc) right */
> >> -	save_processor_state();
> >> +	preempt_disable();

Why do you need that preempt_disable() here?

> >>  	error = restore_highmem();
> >>  	if (!error) {
> >>  		error = swsusp_arch_resume();
> >
> > Yep. save_processor_state() on x86 does kernel_fpu_begin(), and than
> > one needs to be balanced IIRC.
> 
> 
> The needs of x86 force generic kernel changes ;-)

Not necessarily.  In fact, implementing that feature on different architectures
is a good opportunity to clean up the code if necessary.

Thanks,
Rafael



More information about the linux-arm-kernel mailing list