Thread (6 messages) 6 messages, 3 authors, 2011-06-14
STALE5484d

[RFC PATCH v3] ARM hibernation/suspend-to-disk support

From: Frank Hofmann <hidden>
Date: 2011-05-31 11:50:55
Subsystem: arm port, the rest · Maintainers: Russell King, Linus Torvalds


On Fri, 27 May 2011, Nicolas Pitre wrote:
On Fri, 27 May 2011, Frank Hofmann wrote:
quoted
 /*
  * r0 = control register value
  * r1 = v:p offset (preserved by cpu_do_resume)
+ *      if this is zero, do not reenable MMU (it's on)
This is wrong.  It is well possible for this to be zero when the MMU is
active.

The best way to determine if MMU is on or off is:

	mrc	p15, 0, rx, c1, c0	@ load ctrl reg
	tst	rx, #1			@ test M bit
Ah, thanks. I had thought only MMU-less kernels will run on identity but 
you're right of course there's nothing to stop it as such.

This one:
==============================================================================
diff --git a/arch/arm/kernel/sleep.S b/arch/arm/kernel/sleep.S
index 6398ead..a793644 100644
--- a/arch/arm/kernel/sleep.S
+++ b/arch/arm/kernel/sleep.S
@@ -75,6 +75,9 @@ ENDPROC(cpu_suspend)
   * r3 = L1 section flags
   */
  ENTRY(cpu_resume_mmu)
+	mrc	p15, 0, r4, c1, c0, 0
+	tst	r4, #CR_M
+	bne	0f			@ return if MMU already on
  	adr	r4, cpu_resume_turn_mmu_on
  	mov	r4, r4, lsr #20
  	orr	r3, r3, r4, lsl #20
@@ -96,6 +99,7 @@ cpu_resume_turn_mmu_on:
  ENDPROC(cpu_resume_turn_mmu_on)
  cpu_resume_after_mmu:
  	str	r5, [r2, r4, lsl #2]	@ restore old mapping
+0:
  	mcr	p15, 0, r0, c1, c0, 0	@ turn on D-cache
  	mov	pc, lr
  ENDPROC(cpu_resume_after_mmu)
==============================================================================

does indeed do that part of the job.

quoted
I wonder; is there a proper/suggested way to switch MMU off (and not end in
binary nirvana), to have the reentry / reenable work ?
This is slightly complicated.  You first need to turn of and disable the
caches, and ideally set up a 1:1 mapping for the transition.  There are
cpu_proc_fin() and cpu_reset(branch_location).
Hmm, just looked through that. One of the issues with this is my usecase - 
ARM11x6 and Cortex-A8/9, for which these are cpu_v[67]_reset() - a no-op 
(in mainline / rmk devel-stable). I.e. neither cpu_proc_fin() nor 
cpu_reset() on v6/v7 currently switch the MMU off. The older chips do ...


Anyway, the setup for resume after hibernation at the moment is:

 	- swsusp_arch_resume switches to swapper_pg_dir
 	  (which is guaranteed to be kernel flat addresses ?!)

 	- image restoration
 	  [ caches should probably be flushed / turned off after this ? ]

 	- cpu_do_resume() restores pre-suspend TTBR
 	  (which in effect is a cpu_switch_mm)

 	- cpu_resume_mmu bypassed because MMU already on

But that means as part of the resume, a context switch is done anyway.

Which sort of leads to the question whether the 1:1 mapping for the switch 
off case is really required; wouldn't it be acceptable to simply turn the 
MMU off and jump to the physical address of cpu_do_resume() instead ?

Something like:

 	[ caches off ... ]

 	@ assume r0 == phys addr of restore buffer (however retrieved)

 	ldr	r1, =virt_addr_of_restore_buffer	@ known
 	sub	r2, r1, r0				@ calc v:p offset
 	ldr	r3, =cpu_do_resume			@ virt func addr
 	sub	r3, r3, r2				@ to phys
 	mrc	p15, 0, r1, cr0, cr1, 0
 	bic	r1, #CR_M
 	adr	lr, =post_resume			@ load virtual
 	mcr	r15, 0, r1, cr0, cr1, 0			@ MMU off
crit:	mov	pc, r3					@ jump phys
post_resume:
 	[ continue processing when done / returned ]

Or is it necessary to have a 1:1 mapping for 'crit:' when switching the 
MMU off, to make sure one actually reaches the jump ?

You may also investigate how kexec is handled which purpose is to let
the kernel boot another kernel.
machine_kexec() you mean ? I vaguely remember having read that to get this 
working on v6/v7 CPUs one needs non-mainline patches, is that still so ? 
The current fin / reset codepaths for v6/v7 don't turn the MMU off, 
anyway.

Thanks for the pointer. Reading that, it looks like flushing / disabling 
all caches is necessary before entering/resuming the target ?


I'm starting to wonder whether for a first-stab at hibernation support on 
ARM, the ability to resume non-identical kernels / resume not via the 
kernel hibernation restore codepaths (i.e. invocation via bootloader) is 
required.

As Rafael answered a while back, to make that work a temporary MMU 
initialization / setup is necessary for the image restoration. The 
current code assumes swapper_pg_dir has been set up, and maps the entire 
kernel heap; how true is that assumption, actually, at "kernel entry" ?


Thanks,
FrankH.


Nicolas
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help