Hi,
I've cleaned this up by the suggestions in the previous thread; this is
the result.
- now baselined against rmk/devel-stable
- didn't create the <asm/suspend.h> because Rafael is just removing
that everywhere anyway
- Fixes re prev suggestion:
local_fiq_enable/disable bracketing
save only absolutely essential regs and let cpu_init do the rest
thumb2 clean assembly
allows mach hooks (but they're not defined by this code)
- Also: uses the "generic suspend/resume support" code
(commit f6b0fa02e8b0708d17d631afce456524eadf87ff, rmk/devel-stable)
Via the latter, the previously-used hooks into machine-dependent code,
__save/__restore_processor_state, have become unnecessary.
This now simply calls the cpu_do_suspend/resume utilities provided by the
generic code.
I'm still figuring out how to best test a recent devel-stable kernel ...
Please let me know what you think,
Thanks in advance,
FrankH.
==============================================================================
Note on non-current kernels (older than 2.6.38):
==============================================================================
The use of generic CPU suspend/resume also ties the code to a
sufficiently-recent kernel - it requires the code from:
http://ftp.arm.linux.org.uk/git/gitweb.cgi?p=linux-2.6-arm.git;a=commitdiff;h=f6b0fa02e8b0708d17d631afce456524eadf87ff
Which is, for many that (want to) use the feature, a hurdle...
If you're using an older kernel (2.6.37 or below), try the "generic" part
posted via:
https://patchwork.kernel.org/patch/809212/
and add a __save/__restore_processor_state for your CPU type, as mentioned
here:
http://lists.arm.linux.org.uk/lurker/message/20110520.123937.760c528f.en.html
==============================================================================
arch/arm/include/asm/memory.h | 1 +
arch/arm/kernel/Makefile | 1 +
arch/arm/kernel/cpu.c | 70 +++++++++++++++++++++++++++++++++
arch/arm/kernel/swsusp.S | 87 +++++++++++++++++++++++++++++++++++++++++
arch/arm/mm/Kconfig | 5 ++
5 files changed, 164 insertions(+), 0 deletions(-)
diff --git a/arch/arm/include/asm/memory.h b/arch/arm/include/asm/memory.h
index 431077c..c7ef454 100644
--- a/arch/arm/include/asm/memory.h
+++ b/arch/arm/include/asm/memory.h
@@ -250,6 +250,7 @@ static inline void *phys_to_virt(phys_addr_t x)
*/
#define __pa(x) __virt_to_phys((unsigned long)(x))
#define __va(x) ((void *)__phys_to_virt((unsigned long)(x)))
+#define __pa_symbol(x) __pa(RELOC_HIDE((unsigned long)(x),0))
#define pfn_to_kaddr(pfn) __va((pfn) << PAGE_SHIFT)
/*
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index 8d95446..b76a403 100644
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -30,6 +30,7 @@ obj-$(CONFIG_ARTHUR) += arthur.o
obj-$(CONFIG_ISA_DMA) += dma-isa.o
obj-$(CONFIG_PCI) += bios32.o isa.o
obj-$(CONFIG_PM_SLEEP) += sleep.o
+obj-$(CONFIG_HIBERNATION) += cpu.o swsusp.o
obj-$(CONFIG_HAVE_SCHED_CLOCK) += sched_clock.o
obj-$(CONFIG_SMP) += smp.o smp_tlb.o
obj-$(CONFIG_HAVE_ARM_SCU) += smp_scu.o
diff --git a/arch/arm/kernel/cpu.c b/arch/arm/kernel/cpu.c
new file mode 100644
index 0000000..2dfb40b
--- /dev/null
+++ b/arch/arm/kernel/cpu.c
@@ -0,0 +1,70 @@
+/*
+ * Hibernation support specific for ARM
+ *
+ * Derived from work on ARM hibernation support by:
+ *
+ * Ubuntu project, hibernation support for mach-dove
+ * Copyright (C) 2010 Nokia Corporation (Hiroshi Doyu)
+ * Copyright (C) 2010 Texas Instruments, Inc. (Teerth Reddy et al.)
+ * https://lkml.org/lkml/2010/6/18/4
+ * https://lists.linux-foundation.org/pipermail/linux-pm/2010-June/027422.html
+ * https://patchwork.kernel.org/patch/96442/
+ *
+ * Copyright (C) 2006 Rafael J. Wysocki <rjw@xxxxxxx>
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/suspend.h>
+#include <asm/tlbflush.h>
+
+extern const void __nosave_begin, __nosave_end;
+
+int pfn_is_nosave(unsigned long pfn)
+{
+ unsigned long nosave_begin_pfn = __pa_symbol(&__nosave_begin) >> PAGE_SHIFT;
+ unsigned long nosave_end_pfn = PAGE_ALIGN(__pa_symbol(&__nosave_end)) >> PAGE_SHIFT;
+
+ return (pfn >= nosave_begin_pfn) && (pfn < nosave_end_pfn);
+}
+
+void save_processor_state(void)
+{
+ flush_thread();
+ local_fiq_disable();
+#ifdef CONFIG_ARM_MACH_HIBERNATION_HOOK
+ mach_save_state();
+#endif
+}
+
+void restore_processor_state(void)
+{
+ local_flush_tlb_all();
+#ifdef CONFIG_ARM_MACH_HIBERNATION_HOOK
+ mach_restore_state();
+#endif
+ local_fiq_enable();
+}
+
+u8 __swsusp_arch_ctx[PAGE_SIZE] __attribute__((aligned(PAGE_SIZE)));
+u8 __swsusp_resume_stk[PAGE_SIZE/2] __nosavedata;
+
+/*
+ * The framework loads the hibernation image into this linked list,
+ * for swsusp_arch_resume() to copy back to the proper destinations.
+ *
+ * To make this work if resume is triggered from initramfs, the
+ * pagetables need to be switched to allow writes to kernel mem.
+ */
+void notrace __swsusp_arch_restore_image(void)
+{
+ extern struct pbe *restore_pblist;
+ struct pbe *pbe;
+
+ cpu_switch_mm(__virt_to_phys(swapper_pg_dir), &init_mm);
+
+ for (pbe = restore_pblist; pbe; pbe = pbe->next)
+ copy_page(pbe->orig_address, pbe->address);
+}
diff --git a/arch/arm/kernel/swsusp.S b/arch/arm/kernel/swsusp.S
new file mode 100644
index 0000000..7308d6c
--- /dev/null
+++ b/arch/arm/kernel/swsusp.S
@@ -0,0 +1,87 @@
+/*
+ * Hibernation support specific for ARM
+ *
+ * Based on work by:
+ *
+ * Ubuntu project, hibernation support for mach-dove,
+ * Copyright (C) 2010 Nokia Corporation (Hiroshi Doyu)
+ * Copyright (C) 2010 Texas Instruments, Inc. (Teerth Reddy et al.)
+ * https://lkml.org/lkml/2010/6/18/4
+ * https://lists.linux-foundation.org/pipermail/linux-pm/2010-June/027422.html
+ * https://patchwork.kernel.org/patch/96442/
+ *
+ * Copyright (C) 2006 Rafael J. Wysocki <rjw@xxxxxxx>
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/linkage.h>
+#include <asm/memory.h>
+#include <asm/page.h>
+#include <asm/asm-offsets.h>
+#include <asm/glue-proc.h>
+
+
+/*
+ * Save the current CPU state before suspend / poweroff.
+ */
+ENTRY(swsusp_arch_suspend)
+ ldr r0, =__swsusp_arch_ctx
+ mrs r1, cpsr
+ mrs r2, spsr
+ stmia r0!, {r1-r11,lr} @ CPSR, SPSR, nonvolatile regs
+ str sp, [r0], #4 @ stack
+ stmfd sp!, {lr}
+#ifdef MULTI_CPU
+ ldr r1, =processor
+ mov lr, pc
+ ldr pc, [r1, #CPU_DO_SUSPEND]
+#else
+ bl cpu_do_suspend
+#endif
+ ldmfd sp!, {lr}
+ b swsusp_save @ let framework write snapshot out
+ENDPROC(swsusp_arch_suspend)
+
+/*
+ * Restore the memory image from the pagelists, and load the CPU registers
+ * from saved state.
+ */
+ENTRY(swsusp_arch_resume)
+ /*
+ * Switch stack to a nosavedata region to make sure image restore
+ * doesn't clobber it underneath itself.
+ */
+ ldr sp, =(__swsusp_resume_stk + PAGE_SIZE / 2)
+ bl __swsusp_arch_restore_image
+
+ /*
+ * Restore the CPU registers.
+ */
+ ldr r0, =__swsusp_arch_ctx
+ ldmia r0!, {r1,r2} @ CPSR / SPSR
+ msr cpsr, r1
+ msr spsr, r2
+ ldr r0, =__swsusp_arch_ctx @ reload in case regset switched
+ ldmia r0!, {r1-r11,lr} @ nonvolatile regs
+ ldr sp, [r0], #4 @ stack
+
+ /*
+ * From here on we have a valid stack again. Core state is
+ * not restored yet, redirect to the machine-specific
+ * implementation to get that done.
+ * Resume has succeeded at this point; if the machine-specific
+ * code wants to fail it needs to panic.
+ */
+ mov r1, #0
+ stmfd sp!, {r1,r4-r11,lr}
+#ifdef MULTI_CPU
+ ldr r1, =processor
+ mov lr, pc
+ ldr pc, [r1, #CPU_DO_RESUME]
+#else
+ bl cpu_do_resume
+#endif
+ bl cpu_init @ reinitialize other modes
+ ldmfd sp!, {r0,r4-r11,pc}
+ENDPROC(swsusp_arch_resume)
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
index 0074b8d..c668f8f 100644
--- a/arch/arm/mm/Kconfig
+++ b/arch/arm/mm/Kconfig
@@ -627,6 +627,11 @@ config CPU_USE_DOMAINS
config IO_36
bool
+config ARCH_HIBERNATION_POSSIBLE
+ bool
+ depends on MMU
+ default y if CPU_ARM920T || CPU_ARM926T || CPU_SA1100 || CPU_XSCALE || CPU_XSC3 || CPU_V6 || CPU_V6K || CPU_V7
+
comment "Processor Features"
config ARM_THUMB
_______________________________________________
linux-pm mailing list
linux-pm@xxxxxxxxxxxxxxxxxxxxxxxxxx
https://lists.linux-foundation.org/mailman/listinfo/linux-pm