# Original is at linux-pm ML. Cross posting...
Here is swsusp for ARM architecture. It is still target specific.
Anyone doing similar work?
I managed to hibernate/wakeup on OSK on simple case, but when running
mplayer or when mmap'ed and image got bigger, kernel panic'ed on
wakeup, possibly due to pagedir table miss.
Here is log:
>>>
Unable to handle kernel paging request at virtual address 80000000
pgd = c1054000
[80000000] *pgd=00000000
<<<
c1054000 was just after c03ff000. Until up to c03ff000,
pagedir_nosave.orig_address was a constant increase from c0000000 by
0x00001000.
This is at arch/arm/power/swsusp.S:swsusp_arch_resume()
Below are my trial & errors.
* increase entries of pagedir table
I increased entry in arch/arm/kernel/head.S:__create_page_tables() from
4MB to 8MB. This didn't fix the problem.
* copy swapper_pg_dir and use at resume
arch/i386/power/swsusp.S:swsusp_arch_resume() set pagedir table base at
inst: movl %ecx,%cr3. So I attempted similar process, memcpy swapper_pg_dir
to swsusp_pg_dir, and issued: mcr p15, 0, r0, c2, c0, 0, invalidating
cache, drain buffer before & invalidate TLB after this inst.
This caused a crach at mcr inst. After translating from VA to PA, it
was still the same.
Next, I overwrote swapper_pg_dir with swsusp_pg_dir. It didn't crash,
but result was still the same.
(works on simple case, fails with mplayer/mmap)
* applying to 2.6.12
I got bigger image (about 2600 pages), and failed hibernate/wakeup
even on simple case. It was about 1350 pages on simple case, and about
2400 page with mplayer running. The fail status was the same.
Any advice?
I'm confused with the page table usase. On wakeup, kernel create table
(call it A). This table is used when copying swsusp image to mem.
However, there was also table before hibernate (call it B). To some
point, they are similar, so wakeup works. But at some point, wrong
table is used, or table gets corrupted, and result in above kernel
panic. This is my assumption.
Perhaps I have to turn off MMU while copying pagedir_nosave, and turn
on later?
Regards,
HK.
--
diff -uNrp linux-2.6.11.12-orig/arch/arm/Kconfig linux-2.6.11.12/arch/arm/Kconfig
--- linux-2.6.11.12-orig/arch/arm/Kconfig 2005-07-05 14:09:26.000000000 +0900
+++ linux-2.6.11.12/arch/arm/Kconfig 2005-07-05 14:50:37.000000000 +0900
@@ -504,25 +504,7 @@ source "fs/Kconfig.binfmt"
source "drivers/base/Kconfig"
-config PM
- bool "Power Management support"
- ---help---
- "Power Management" means that parts of your computer are shut
- off or put into a power conserving "sleep" mode if they are not
- being used. There are two competing standards for doing this: APM
- and ACPI. If you want to use either one, say Y here and then also
- to the requisite support below.
-
- Power Management is most important for battery powered laptop
- computers; if you have a laptop, check out the Linux Laptop home
- page on the WWW at <http://www.linux-on-laptops.com/> or
- Tuxmobil - Linux on Mobile Computers at <http://www.tuxmobil.org/>
- and the Battery Powered Linux mini-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
-
- Note that, even if you say N here, Linux on the x86 architecture
- will issue the hlt instruction if nothing is to be done, thereby
- sending the processor to sleep and saving power.
+source "kernel/power/Kconfig"
config PREEMPT
bool "Preemptible Kernel (EXPERIMENTAL)"
diff -uNrp linux-2.6.11.12-orig/arch/arm/Makefile linux-2.6.11.12/arch/arm/Makefile
--- linux-2.6.11.12-orig/arch/arm/Makefile 2005-06-12 11:45:37.000000000 +0900
+++ linux-2.6.11.12/arch/arm/Makefile 2005-07-05 14:50:51.000000000 +0900
@@ -146,6 +146,7 @@ core-$(CONFIG_VFP) += arch/arm/vfp/
drivers-$(CONFIG_OPROFILE) += arch/arm/oprofile/
drivers-$(CONFIG_ARCH_CLPS7500) += drivers/acorn/char/
drivers-$(CONFIG_ARCH_L7200) += drivers/acorn/char/
+drivers-$(CONFIG_PM) += arch/arm/power/
libs-y += arch/arm/lib/
diff -uNrp linux-2.6.11.12-orig/arch/arm/kernel/vmlinux.lds.S linux-2.6.11.12/arch/arm/kernel/vmlinux.lds.S
--- linux-2.6.11.12-orig/arch/arm/kernel/vmlinux.lds.S 2005-06-12 11:45:37.000000000 +0900
+++ linux-2.6.11.12/arch/arm/kernel/vmlinux.lds.S 2005-07-05 14:50:51.000000000 +0900
@@ -75,6 +75,7 @@ SECTIONS
}
.text : { /* Real text segment */
+ _kern_text_start = .;
_text = .; /* Text and read-only data */
*(.text)
SCHED_TEXT
@@ -98,6 +99,7 @@ SECTIONS
RODATA
_etext = .; /* End of text and rodata section */
+ _kern_text_end = .;
#ifdef CONFIG_XIP_KERNEL
__data_loc = ALIGN(4); /* location in binary */
@@ -124,12 +126,6 @@ SECTIONS
__init_end = .;
#endif
- . = ALIGN(4096);
- __nosave_begin = .;
- *(.data.nosave)
- . = ALIGN(4096);
- __nosave_end = .;
-
/*
* then the cacheline aligned data
*/
@@ -145,6 +141,12 @@ SECTIONS
_edata = .;
}
+ . = ALIGN(4096);
+ __nosave_begin = .;
+ .data.nosave : { *(.data.nosave) }
+ . = ALIGN(4096);
+ __nosave_end = .;
+
.bss : {
__bss_start = .; /* BSS */
*(.bss)
diff -uNrp linux-2.6.11.12-orig/arch/arm/mm/init.c linux-2.6.11.12/arch/arm/mm/init.c
--- linux-2.6.11.12-orig/arch/arm/mm/init.c 2005-06-12 11:45:37.000000000 +0900
+++ linux-2.6.11.12/arch/arm/mm/init.c 2005-07-05 15:16:52.000000000 +0900
@@ -530,6 +530,20 @@ static inline void free_area(unsigned lo
printk(KERN_INFO "Freeing %s memory: %dK\n", s, size);
}
+#if defined(CONFIG_PM_DISK) || defined(CONFIG_SOFTWARE_SUSPEND)
+/*
+ * Swap suspend & friends need this for resume.
+ */
+/* pgd_t is unsigned long [2], so 2 * 4 (byte/word) */
+char __nosavedata swsusp_pg_dir[PTRS_PER_PGD * 2 * 4]
+/* Translation Table Base must be on 16KB boundary. */
+__attribute__ ((aligned (1UL << 14)));
+void swsusp_save_pg_dir(void)
+{
+ memcpy(swsusp_pg_dir, swapper_pg_dir, PTRS_PER_PGD * 2 * 4);
+}
+#endif
+
/*
* mem_init() marks the free areas in the mem_map and tells us how much
* memory is free. This is done after various parts of the system have
diff -uNrp linux-2.6.11.12-orig/arch/arm/power/Makefile linux-2.6.11.12/arch/arm/power/Makefile
--- linux-2.6.11.12-orig/arch/arm/power/Makefile 1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.11.12/arch/arm/power/Makefile 2005-07-05 14:50:51.000000000 +0900
@@ -0,0 +1 @@
+obj-$(CONFIG_SOFTWARE_SUSPEND) += cpu.o swsusp.o
diff -uNrp linux-2.6.11.12-orig/arch/arm/power/cpu.c linux-2.6.11.12/arch/arm/power/cpu.c
--- linux-2.6.11.12-orig/arch/arm/power/cpu.c 1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.11.12/arch/arm/power/cpu.c 2005-07-05 19:59:58.000000000 +0900
@@ -0,0 +1,100 @@
+/*
+ * cpu.c - Suspend support specific for ARM.
+ * based on arch/i386/power/cpu.c
+ *
+ * Distribute under GPLv2
+ *
+ * Copyright (c) 2002 Pavel Machek <[email protected]>
+ * Copyright (c) 2001 Patrick Mochel <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <linux/poll.h>
+#include <linux/delay.h>
+#include <linux/sysrq.h>
+#include <linux/proc_fs.h>
+#include <linux/pm.h>
+#include <linux/device.h>
+#include <linux/suspend.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/tlbflush.h>
+
+static struct saved_context saved_context;
+
+extern void enable_sep_cpu(void *);
+
+void __save_processor_state(struct saved_context *ctxt)
+{
+ /* save preempt state and disable it */
+ preempt_disable();
+
+ /* save coprocessor 15 registers */
+ asm volatile ("mrc p15, 0, %0, c1, c0, 0" : "=r" (ctxt->CR));
+ asm volatile ("mrc p15, 0, %0, c3, c0, 0" : "=r" (ctxt->DACR));
+ asm volatile ("mrc p15, 0, %0, c5, c0, 0" : "=r" (ctxt->D_FSR));
+ asm volatile ("mrc p15, 0, %0, c5, c0, 1" : "=r" (ctxt->I_FSR));
+ asm volatile ("mrc p15, 0, %0, c6, c0, 0" : "=r" (ctxt->FAR));
+ asm volatile ("mrc p15, 0, %0, c9, c0, 0" : "=r" (ctxt->D_CLR));
+ asm volatile ("mrc p15, 0, %0, c9, c0, 1" : "=r" (ctxt->I_CLR));
+ asm volatile ("mrc p15, 0, %0, c9, c1, 0" : "=r" (ctxt->D_TCMRR));
+ asm volatile ("mrc p15, 0, %0, c9, c1, 1" : "=r" (ctxt->I_TCMRR));
+ asm volatile ("mrc p15, 0, %0, c10, c0, 0" : "=r" (ctxt->TLBLR));
+ asm volatile ("mrc p15, 0, %0, c13, c0, 0" : "=r" (ctxt->FCSE));
+ asm volatile ("mrc p15, 0, %0, c13, c0, 1" : "=r" (ctxt->CID));
+ asm volatile ("mrc p15, 0, %0, c2, c0, 0" : "=r" (ctxt->TTBR));
+
+}
+
+extern void swsusp_save_pg_dir(void);
+void save_processor_state(void)
+{
+ __save_processor_state(&saved_context);
+}
+
+void __restore_processor_state(struct saved_context *ctxt)
+{
+ /* restore coprocessor 15 registers */
+ asm volatile ("mcr p15, 0, %0, c2, c0, 0" : : "r" (ctxt->TTBR));
+ asm volatile ("mcr p15, 0, %0, c13, c0, 1" : : "r" (ctxt->CID));
+ asm volatile ("mcr p15, 0, %0, c13, c0, 0" : : "r" (ctxt->FCSE));
+ asm volatile ("mcr p15, 0, %0, c10, c0, 0" : : "r" (ctxt->TLBLR));
+ asm volatile ("mcr p15, 0, %0, c9, c1, 1" : : "r" (ctxt->I_TCMRR));
+ asm volatile ("mcr p15, 0, %0, c9, c1, 0" : : "r" (ctxt->D_TCMRR));
+ asm volatile ("mcr p15, 0, %0, c9, c0, 1" : : "r" (ctxt->I_CLR));
+ asm volatile ("mcr p15, 0, %0, c9, c0, 0" : : "r" (ctxt->D_CLR));
+ asm volatile ("mcr p15, 0, %0, c6, c0, 0" : : "r" (ctxt->FAR));
+ asm volatile ("mcr p15, 0, %0, c5, c0, 1" : : "r" (ctxt->I_FSR));
+ asm volatile ("mcr p15, 0, %0, c5, c0, 0" : : "r" (ctxt->D_FSR));
+ asm volatile ("mcr p15, 0, %0, c3, c0, 0" : : "r" (ctxt->DACR));
+ asm volatile ("mcr p15, 0, %0, c1, c0, 0" : : "r" (ctxt->CR));
+
+ /* restore preempt state */
+ preempt_enable();
+}
+
+void restore_processor_state(void)
+{
+ __restore_processor_state(&saved_context);
+}
+
+
+EXPORT_SYMBOL(save_processor_state);
+EXPORT_SYMBOL(restore_processor_state);
diff -uNrp linux-2.6.11.12-orig/arch/arm/power/swsusp.S linux-2.6.11.12/arch/arm/power/swsusp.S
--- linux-2.6.11.12-orig/arch/arm/power/swsusp.S 1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.11.12/arch/arm/power/swsusp.S 2005-07-05 19:52:48.000000000 +0900
@@ -0,0 +1,321 @@
+/*
+ * swsusp.S - This file is based on arch/i386/power/swsusp.S;
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * This may not use any stack, nor any variable that is not "NoSave":
+ *
+ * Its rewriting one kernel image with another. What is stack in "old"
+ * image could very well be data page in "new" image, and overwriting
+ * your own stack under you is bad idea.
+ */
+
+/*
+ * FIXME: Work needs to be done for core with fp.
+ */
+
+#include <linux/linkage.h>
+#include <asm/segment.h>
+#include <asm/page.h>
+
+ .text
+
+#define LOCAL_WORD(x) \
+ .data ; \
+ .p2align 2 ; \
+ .type x, #object ; \
+ .size x, 4 ; \
+x: ; \
+ .long 1
+
+#define WORD_ADDR(x) \
+ .align 2 ; \
+.L##x: ; \
+ .word x
+
+#define FUNC(x) \
+ .text ; \
+ .p2align 2 ; \
+ .globl x ; \
+ .type x, #function ; \
+x:
+
+#define FUNC_END(x) \
+ .size x, .-x
+
+#define CHANGE_MODE(x) \
+ mov r1, r0 ; \
+ bic r1, r1, #0x1f ; \
+ orr r1, r1, #0x##x ; \
+ msr cpsr_c, r1
+
+/* nonvolatile int registers */
+#ifdef DEBUG
+ .globl saved_context_r0 // for debug
+#endif
+ LOCAL_WORD(saved_context_r0)
+ LOCAL_WORD(saved_context_r1)
+ LOCAL_WORD(saved_context_r2)
+ LOCAL_WORD(saved_context_r3)
+ LOCAL_WORD(saved_context_r4)
+ LOCAL_WORD(saved_context_r5)
+ LOCAL_WORD(saved_context_r6)
+ LOCAL_WORD(saved_context_r7)
+ LOCAL_WORD(saved_context_r8)
+ LOCAL_WORD(saved_context_r9)
+ LOCAL_WORD(saved_context_r10)
+ LOCAL_WORD(saved_context_r11)
+ LOCAL_WORD(saved_context_r12)
+ LOCAL_WORD(saved_context_r13)
+ LOCAL_WORD(saved_context_r14)
+ LOCAL_WORD(saved_cpsr)
+
+ LOCAL_WORD(saved_context_r8_fiq)
+ LOCAL_WORD(saved_context_r9_fiq)
+ LOCAL_WORD(saved_context_r10_fiq)
+ LOCAL_WORD(saved_context_r11_fiq)
+ LOCAL_WORD(saved_context_r12_fiq)
+ LOCAL_WORD(saved_context_r13_fiq)
+ LOCAL_WORD(saved_context_r14_fiq)
+ LOCAL_WORD(saved_spsr_fiq)
+
+ LOCAL_WORD(saved_context_r13_irq)
+ LOCAL_WORD(saved_context_r14_irq)
+ LOCAL_WORD(saved_spsr_irq)
+
+ LOCAL_WORD(saved_context_r13_svc)
+ LOCAL_WORD(saved_context_r14_svc)
+ LOCAL_WORD(saved_spsr_svc)
+
+ LOCAL_WORD(saved_context_r13_abt)
+ LOCAL_WORD(saved_context_r14_abt)
+ LOCAL_WORD(saved_spsr_abt)
+
+ LOCAL_WORD(saved_context_r13_und)
+ LOCAL_WORD(saved_context_r14_und)
+ LOCAL_WORD(saved_spsr_und)
+
+/*
+ * non volatile fpu registers
+ * s16 - s31
+ */
+ /* XXX:TBD */
+
+FUNC(swsusp_arch_suspend)
+
+ /* save current program status register */
+ ldr r3, .Lsaved_cpsr
+ mrs r1, cpsr
+ str r1, [r3]
+
+ /* hold current mode */
+ mrs r0, cpsr
+
+ CHANGE_MODE(1f) /* change to system(user) mode */
+ /* save nonvolatile int register */
+ ldr r3, .Lsaved_context_r0
+ stmia r3, {r0-r14}
+
+ CHANGE_MODE(11) /* change to fiq mode */
+ /* save nonvolatile int register */
+ ldr r3, .Lsaved_context_r8_fiq
+ stmia r3, {r8-r14}
+ /* save spsr_fiq register */
+ ldr r3, .Lsaved_spsr_fiq
+ mrs r1, spsr
+ str r1, [r3]
+
+ CHANGE_MODE(12) /* change to irq mode */
+ /* save nonvolatile int register */
+ ldr r3, .Lsaved_context_r13_irq
+ stmia r3, {r13-r14}
+ /* save spsr_irq register */
+ ldr r3, .Lsaved_spsr_irq
+ mrs r1, spsr
+ str r1, [r3]
+
+ CHANGE_MODE(13) /* change to svc mode */
+ /* save nonvolatile int register */
+ ldr r3, .Lsaved_context_r13_svc
+ stmia r3, {r13-r14}
+ /* save spsr_svc register */
+ ldr r3, .Lsaved_spsr_svc
+ mrs r1, spsr
+ str r1, [r3]
+
+ CHANGE_MODE(17) /* change to abt mode */
+ /* save nonvolatile int register */
+ ldr r3, .Lsaved_context_r13_abt
+ stmia r3, {r13-r14}
+ /* save spsr_abt register */
+ ldr r3, .Lsaved_spsr_abt
+ mrs r1, spsr
+ str r1, [r3]
+
+ CHANGE_MODE(1b) /* change to und mode */
+ /* save nonvolatile int register */
+ ldr r3, .Lsaved_context_r13_und
+ stmia r3, {r13-r14}
+ /* save spsr_und register */
+ ldr r3, .Lsaved_spsr_und
+ mrs r1, spsr
+ str r1, [r3]
+
+ /* go back to original mode */
+ msr cpsr_c, r0
+
+ /*
+ * save nonvolatile fp registers
+ * and fp status/system registers, if needed
+ */
+ /* XXX:TBD */
+
+ /* call swsusp_save */
+ bl swsusp_save
+
+ /* restore return address */
+ ldr r3, .Lsaved_context_r14_svc
+ ldr lr, [r3]
+ mov pc, lr
+
+ WORD_ADDR(saved_context_r0)
+ WORD_ADDR(saved_cpsr)
+ WORD_ADDR(saved_context_r8_fiq)
+ WORD_ADDR(saved_spsr_fiq)
+ WORD_ADDR(saved_context_r13_irq)
+ WORD_ADDR(saved_spsr_irq)
+ WORD_ADDR(saved_context_r13_svc)
+ WORD_ADDR(saved_context_r14_svc)
+ WORD_ADDR(saved_spsr_svc)
+ WORD_ADDR(saved_context_r13_abt)
+ WORD_ADDR(saved_spsr_abt)
+ WORD_ADDR(saved_context_r13_und)
+ WORD_ADDR(saved_spsr_und)
+
+FUNC_END(swsusp_arch_suspend)
+
+FUNC(swsusp_arch_resume)
+ /* set page table if needed */
+
+ /*
+ * retore "nr_copy_pages" pages which are saved and specified
+ * at "pagedir_nosave"
+ */
+
+ ldr r0, .Lpagedir_nosave
+ ldr r6, [r0]
+ ldr r0, .Lnr_copy_pages
+ ldr r7, [r0]
+
+.Lcopy_loop:
+ ldr r4, [r6] /* src */
+ ldr r5, [r6, #4] /* dst */
+ mov r9, #1024
+
+ /* this loop could be optimized by using stm and ldm. */
+.Lcopy_one_page:
+ ldr r8, [r4]
+ str r8, [r5]
+
+ add r4, r4, #4
+ add r5, r5, #4
+ sub r9, r9, #1
+ cmp r9, #0
+ bne .Lcopy_one_page
+
+ add r6, r6, #16 /* 16 means sizeof(suspend_pagedir_t) */
+ sub r7, r7, #1
+ cmp r7, #0
+ bne .Lcopy_loop
+
+ /* hold current mode */
+ mrs r0, cpsr
+
+ CHANGE_MODE(1f) /* change to system(user) mode */
+ /* restore nonvolatile int register */
+ ldr r3, .Lsaved_context_r0
+ ldmia r3, {r0-r14}
+ /* restore current program status register */
+ ldr r3, .Lsaved_cpsr
+ ldr r1, [r3]
+ msr cpsr_cxsf, r1
+
+ CHANGE_MODE(11) /* change to fiq mode */
+ /* restore nonvolatile int register */
+ ldr r3, .Lsaved_context_r8_fiq
+ ldmia r3, {r8-r14}
+ /* restore spsr_fiq register */
+ ldr r3, .Lsaved_spsr_fiq
+ ldr r1, [r3]
+ msr spsr_cxsf, r1
+
+ CHANGE_MODE(12) /* change to irq mode */
+ /* restore nonvolatile int register */
+ ldr r3, .Lsaved_context_r13_irq
+ ldmia r3, {r13-r14}
+ /* restore spsr_irq register */
+ ldr r3, .Lsaved_spsr_irq
+ ldr r1, [r3]
+ msr spsr_cxsf, r1
+
+ CHANGE_MODE(13) /* change to svc mode */
+ /* restore nonvolatile int register */
+ ldr r3, .Lsaved_context_r13_svc
+ ldmia r3, {r13-r14}
+ /* restore spsr_svc register */
+ ldr r3, .Lsaved_spsr_svc
+ ldr r1, [r3]
+ msr spsr_cxsf, r1
+
+ CHANGE_MODE(17) /* change to abt mode */
+ /* restore nonvolatile int register */
+ ldr r3, .Lsaved_context_r13_abt
+ ldmia r3, {r13-r14}
+ /* restore spsr_abt register */
+ ldr r3, .Lsaved_spsr_abt
+ ldr r1, [r3]
+ msr spsr_cxsf, r1
+
+ CHANGE_MODE(1b) /* change to und mode */
+ /* restore nonvolatile int register */
+ ldr r3, .Lsaved_context_r13_und
+ ldmia r3, {r13-r14}
+ /* restore spsr_und register */
+ ldr r3, .Lsaved_spsr_und
+ ldr r1, [r3]
+ msr spsr_cxsf, r1
+
+ /* go back to original mode */
+ msr cpsr_c, r0
+
+ /*
+ * restore nonvolatile fp registers
+ * and fp status/system registers, if needed
+ */
+ /* XXX:TBD */
+
+ /* call swsusp_restore */
+ bl swsusp_restore
+
+ /* restore return address */
+ ldr r3, .Lsaved_context_r14_svc
+ ldr lr, [r3]
+ mov pc, lr
+
+ WORD_ADDR(nr_copy_pages)
+ WORD_ADDR(pagedir_nosave)
+
+FUNC_END(swsusp_arch_resume)
diff -uNrp linux-2.6.11.12-orig/include/asm-arm/suspend.h linux-2.6.11.12/include/asm-arm/suspend.h
--- linux-2.6.11.12-orig/include/asm-arm/suspend.h 2005-06-12 11:45:37.000000000 +0900
+++ linux-2.6.11.12/include/asm-arm/suspend.h 2005-07-05 14:52:20.000000000 +0900
@@ -1,4 +1,45 @@
#ifndef _ASMARM_SUSPEND_H
#define _ASMARM_SUSPEND_H
+/*
+ * Based on code include/asm-i386/suspend.h
+ * Copyright 2001-2002 Pavel Machek <[email protected]>
+ * Copyright 2001 Patrick Mochel <[email protected]>
+ */
+
+
+static inline int
+arch_prepare_suspend(void)
+{
+ return 0;
+}
+
+/* image of the saved processor state */
+struct saved_context {
+ /*
+ * Structure saved_context would be used to hold processor state
+ * except caller and callee registers, just before suspending.
+ */
+
+ /* coprocessor 15 registers */
+// __u32 ID_code; /* read only reg */
+// __u32 cache_type; /* read only reg */
+// __u32 TCM_stat; /* read only reg */
+ __u32 CR;
+ __u32 TTBR;
+ __u32 DACR;
+ __u32 D_FSR;
+ __u32 I_FSR;
+ __u32 FAR;
+// __u32 COR; /*write only reg */
+// __u32 TLBOR; /*write only reg */
+ __u32 D_CLR;
+ __u32 I_CLR;
+ __u32 D_TCMRR;
+ __u32 I_TCMRR;
+ __u32 TLBLR;
+ __u32 FCSE;
+ __u32 CID;
+};
+
#endif
diff -uNrp linux-2.6.11.12-orig/include/asm-arm/tlbflush.h linux-2.6.11.12/include/asm-arm/tlbflush.h
--- linux-2.6.11.12-orig/include/asm-arm/tlbflush.h 2005-06-12 11:45:37.000000000 +0900
+++ linux-2.6.11.12/include/asm-arm/tlbflush.h 2005-07-05 14:50:51.000000000 +0900
@@ -253,6 +253,9 @@ static inline void flush_tlb_all(void)
asm("mcr%? p15, 0, %0, c8, c5, 0" : : "r" (zero));
}
+#define __flush_tlb_all flush_tlb_all
+#define __flush_tlb_global flush_tlb_all
+
static inline void flush_tlb_mm(struct mm_struct *mm)
{
const int zero = 0;
diff -uNrp linux-2.6.11.12-orig/include/linux/suspend.h linux-2.6.11.12/include/linux/suspend.h
--- linux-2.6.11.12-orig/include/linux/suspend.h 2005-06-12 11:45:37.000000000 +0900
+++ linux-2.6.11.12/include/linux/suspend.h 2005-07-05 15:04:10.000000000 +0900
@@ -1,7 +1,7 @@
#ifndef _LINUX_SWSUSP_H
#define _LINUX_SWSUSP_H
-#if defined(CONFIG_X86) || defined(CONFIG_FRV)
+#if defined(CONFIG_PM_DISK) || defined(CONFIG_SOFTWARE_SUSPEND)
#include <asm/suspend.h>
#endif
#include <linux/swap.h>
diff -uNrp linux-2.6.11.12-orig/arch/arm/mach-omap/common.c linux-2.6.11.12/arch/arm/mach-omap/common.c
--- linux-2.6.11.12-orig/arch/arm/mach-omap/common.c 2005-07-05 14:09:26.000000000 +0900
+++ linux-2.6.11.12/arch/arm/mach-omap/common.c 2005-07-05 14:50:37.000000000 +0900
@@ -442,8 +442,16 @@ void __init omap_serial_init(int ports[O
}
}
+static void omap_power_off(void)
+{
+ printk("System Halted\n");
+ local_irq_disable();
+ while (1) ;
+}
+
static int __init omap_init(void)
{
+ pm_power_off = omap_power_off;
return platform_device_register(&serial_device);
}
arch_initcall(omap_init);
diff -uNrp linux-2.6.11.12-orig/drivers/mtd/mtdblock.c linux-2.6.11.12/drivers/mtd/mtdblock.c
--- linux-2.6.11.12-orig/drivers/mtd/mtdblock.c 2005-06-12 11:45:37.000000000 +0900
+++ linux-2.6.11.12/drivers/mtd/mtdblock.c 2005-07-05 14:49:01.000000000 +0900
@@ -321,6 +321,24 @@ static int mtdblock_release(struct mtd_b
return 0;
}
+#if defined(CONFIG_SWSUSP_MTDBLOCK_FLUSH)
+/* XXXX: quick hack, need to be rewrite later */
+int swsusp_mtdblock_flush(void)
+{
+#if defined CONFIG_MACH_OMAP_OSK
+ struct mtdblk_dev *mtdblk = mtdblks[3];
+#endif
+
+ down(&mtdblk->cache_sem);
+ write_cached_data(mtdblk);
+ up(&mtdblk->cache_sem);
+
+ if (mtdblk->mtd->sync)
+ mtdblk->mtd->sync(mtdblk->mtd);
+ return 0;
+}
+#endif
+
static int mtdblock_flush(struct mtd_blktrans_dev *dev)
{
struct mtdblk_dev *mtdblk = mtdblks[dev->devnum];
+ * Based on code
diff -uNrp linux-2.6.11.12-orig/kernel/power/Kconfig linux-2.6.11.12/kernel/power/Kconfig
--- linux-2.6.11.12-orig/kernel/power/Kconfig 2005-06-12 11:45:37.000000000 +0900
+++ linux-2.6.11.12/kernel/power/Kconfig 2005-07-05 14:49:01.000000000 +0900
@@ -72,3 +72,10 @@ config PM_STD_PARTITION
suspended image to. It will simply pick the first available swap
device.
+config SWSUSP_MTDBLOCK_FLUSH
+ bool "Flush MTD block"
+ depends on SOFTWARE_SUSPEND
+ default "y"
+ ---help---
+ When suspend to disk (software suspend), flush the MTD block.
+
diff -uNrp linux-2.6.11.12-orig/kernel/power/disk.c linux-2.6.11.12/kernel/power/disk.c
--- linux-2.6.11.12-orig/kernel/power/disk.c 2005-06-12 11:45:37.000000000 +0900
+++ linux-2.6.11.12/kernel/power/disk.c 2005-07-05 14:49:01.000000000 +0900
@@ -48,6 +48,11 @@ static void power_down(suspend_disk_meth
unsigned long flags;
int error = 0;
+#if defined(CONFIG_SWSUSP_MTDBLOCK_FLUSH)
+/* XXXX: quick hack, need to be rewrite later */
+ printk(KERN_CRIT "flush MTD\n");
+ swsusp_mtdblock_flush();
+#endif
local_irq_save(flags);
switch(mode) {
case PM_DISK_PLATFORM:
[Index of Archives]
[Kernel Newbies]
[Netfilter]
[Bugtraq]
[Photo]
[Gimp]
[Yosemite News]
[MIPS Linux]
[ARM Linux]
[Linux Security]
[Linux RAID]
[Video 4 Linux]
[Linux for the blind]
|
|