On Fri, Jul 08, 2005 at 09:25:01PM +0900, Hiroki Kaminaga wrote:
> # Original is at linux-pm ML. Cross posting...
> 
> Here is swsusp for ARM architecture. It is still target specific.
> Anyone doing similar work?

What are you suspending to? If this is an external device, how is 
your bootloader resuming the kernel? does it have a reserved
area of memory to use for it's working data?
 
> 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

Hmm, I have no idea if this is correct... I assume it is not saving
the page tables over suspend/resume, and that is why you are having
trouble restoring the page table? 

> 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));

Dangerous, you could be restoring items like FastBus select without
checking what state the system is left in on return

> +     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));

I think half of these are items that do not need saving (write-only
control registers)

> +
> +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:


-- 
Ben ([EMAIL PROTECTED], http://www.fluff.org/)

  'a smiley only costs 4 bytes'
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to