diff options
| -rw-r--r-- | arch/arm/include/asm/proc-fns.h | 8 | ||||
| -rw-r--r-- | arch/arm/kernel/sleep.S | 53 | ||||
| -rw-r--r-- | arch/arm/kernel/suspend.c | 24 |
3 files changed, 46 insertions, 39 deletions
diff --git a/arch/arm/include/asm/proc-fns.h b/arch/arm/include/asm/proc-fns.h index 633d1cb84d87..9e92cb205e65 100644 --- a/arch/arm/include/asm/proc-fns.h +++ b/arch/arm/include/asm/proc-fns.h | |||
| @@ -81,6 +81,10 @@ extern void cpu_dcache_clean_area(void *, int); | |||
| 81 | extern void cpu_do_switch_mm(unsigned long pgd_phys, struct mm_struct *mm); | 81 | extern void cpu_do_switch_mm(unsigned long pgd_phys, struct mm_struct *mm); |
| 82 | extern void cpu_set_pte_ext(pte_t *ptep, pte_t pte, unsigned int ext); | 82 | extern void cpu_set_pte_ext(pte_t *ptep, pte_t pte, unsigned int ext); |
| 83 | extern void cpu_reset(unsigned long addr) __attribute__((noreturn)); | 83 | extern void cpu_reset(unsigned long addr) __attribute__((noreturn)); |
| 84 | |||
| 85 | /* These three are private to arch/arm/kernel/suspend.c */ | ||
| 86 | extern void cpu_do_suspend(void *); | ||
| 87 | extern void cpu_do_resume(void *); | ||
| 84 | #else | 88 | #else |
| 85 | #define cpu_proc_init processor._proc_init | 89 | #define cpu_proc_init processor._proc_init |
| 86 | #define cpu_proc_fin processor._proc_fin | 90 | #define cpu_proc_fin processor._proc_fin |
| @@ -89,6 +93,10 @@ extern void cpu_reset(unsigned long addr) __attribute__((noreturn)); | |||
| 89 | #define cpu_dcache_clean_area processor.dcache_clean_area | 93 | #define cpu_dcache_clean_area processor.dcache_clean_area |
| 90 | #define cpu_set_pte_ext processor.set_pte_ext | 94 | #define cpu_set_pte_ext processor.set_pte_ext |
| 91 | #define cpu_do_switch_mm processor.switch_mm | 95 | #define cpu_do_switch_mm processor.switch_mm |
| 96 | |||
| 97 | /* These three are private to arch/arm/kernel/suspend.c */ | ||
| 98 | #define cpu_do_suspend processor.do_suspend | ||
| 99 | #define cpu_do_resume processor.do_resume | ||
| 92 | #endif | 100 | #endif |
| 93 | 101 | ||
| 94 | extern void cpu_resume(void); | 102 | extern void cpu_resume(void); |
diff --git a/arch/arm/kernel/sleep.S b/arch/arm/kernel/sleep.S index c9a43caaea80..020e99c845e7 100644 --- a/arch/arm/kernel/sleep.S +++ b/arch/arm/kernel/sleep.S | |||
| @@ -8,54 +8,35 @@ | |||
| 8 | .text | 8 | .text |
| 9 | 9 | ||
| 10 | /* | 10 | /* |
| 11 | * Save CPU state for a suspend | 11 | * Save CPU state for a suspend. This saves the CPU general purpose |
| 12 | * r0 = phys addr of temporary page tables | 12 | * registers, and allocates space on the kernel stack to save the CPU |
| 13 | * r1 = v:p offset | 13 | * specific registers and some other data for resume. |
| 14 | * r2 = suspend function arg0 | 14 | * r0 = suspend function arg0 |
| 15 | * r3 = suspend function | 15 | * r1 = suspend function |
| 16 | */ | 16 | */ |
| 17 | ENTRY(__cpu_suspend) | 17 | ENTRY(__cpu_suspend) |
| 18 | stmfd sp!, {r4 - r11, lr} | 18 | stmfd sp!, {r4 - r11, lr} |
| 19 | mov r4, r0 | ||
| 20 | #ifdef MULTI_CPU | 19 | #ifdef MULTI_CPU |
| 21 | ldr r10, =processor | 20 | ldr r10, =processor |
| 22 | ldr r5, [r10, #CPU_SLEEP_SIZE] @ size of CPU sleep state | 21 | ldr r4, [r10, #CPU_SLEEP_SIZE] @ size of CPU sleep state |
| 23 | ldr ip, [r10, #CPU_DO_RESUME] @ virtual resume function | ||
| 24 | #else | 22 | #else |
| 25 | ldr r5, =cpu_suspend_size | 23 | ldr r4, =cpu_suspend_size |
| 26 | ldr ip, =cpu_do_resume | ||
| 27 | #endif | 24 | #endif |
| 28 | mov r6, sp @ current virtual SP | 25 | mov r5, sp @ current virtual SP |
| 29 | sub sp, sp, r5 @ allocate CPU state on stack | 26 | add r4, r4, #12 @ Space for pgd, virt sp, phys resume fn |
| 30 | mov r0, sp @ save pointer to CPU save block | 27 | sub sp, sp, r4 @ allocate CPU state on stack |
| 31 | add ip, ip, r1 @ convert resume fn to phys | 28 | stmfd sp!, {r0, r1} @ save suspend func arg and pointer |
| 32 | stmfd sp!, {r4, r6, ip} @ save phys pgd, virt SP, phys resume fn | 29 | add r0, sp, #8 @ save pointer to save block |
| 33 | ldr r5, =sleep_save_sp | 30 | mov r1, r4 @ size of save block |
| 34 | add r6, sp, r1 @ convert SP to phys | 31 | mov r2, r5 @ virtual SP |
| 35 | stmfd sp!, {r2, r3} @ save suspend func arg and pointer | 32 | ldr r3, =sleep_save_sp |
| 36 | #ifdef CONFIG_SMP | 33 | #ifdef CONFIG_SMP |
| 37 | ALT_SMP(mrc p15, 0, lr, c0, c0, 5) | 34 | ALT_SMP(mrc p15, 0, lr, c0, c0, 5) |
| 38 | ALT_UP(mov lr, #0) | 35 | ALT_UP(mov lr, #0) |
| 39 | and lr, lr, #15 | 36 | and lr, lr, #15 |
| 40 | str r6, [r5, lr, lsl #2] @ save phys SP | 37 | add r3, r3, lr, lsl #2 |
| 41 | #else | ||
| 42 | str r6, [r5] @ save phys SP | ||
| 43 | #endif | ||
| 44 | #ifdef MULTI_CPU | ||
| 45 | mov lr, pc | ||
| 46 | ldr pc, [r10, #CPU_DO_SUSPEND] @ save CPU state | ||
| 47 | #else | ||
| 48 | bl cpu_do_suspend | ||
| 49 | #endif | ||
| 50 | |||
| 51 | @ flush data cache | ||
| 52 | #ifdef MULTI_CACHE | ||
| 53 | ldr r10, =cpu_cache | ||
| 54 | mov lr, pc | ||
| 55 | ldr pc, [r10, #CACHE_FLUSH_KERN_ALL] | ||
| 56 | #else | ||
| 57 | bl __cpuc_flush_kern_all | ||
| 58 | #endif | 38 | #endif |
| 39 | bl __cpu_suspend_save | ||
| 59 | adr lr, BSYM(cpu_suspend_abort) | 40 | adr lr, BSYM(cpu_suspend_abort) |
| 60 | ldmfd sp!, {r0, pc} @ call suspend fn | 41 | ldmfd sp!, {r0, pc} @ call suspend fn |
| 61 | ENDPROC(__cpu_suspend) | 42 | ENDPROC(__cpu_suspend) |
diff --git a/arch/arm/kernel/suspend.c b/arch/arm/kernel/suspend.c index ed4160b64e66..2d60f1903206 100644 --- a/arch/arm/kernel/suspend.c +++ b/arch/arm/kernel/suspend.c | |||
| @@ -8,10 +8,29 @@ | |||
| 8 | 8 | ||
| 9 | static pgd_t *suspend_pgd; | 9 | static pgd_t *suspend_pgd; |
| 10 | 10 | ||
| 11 | extern int __cpu_suspend(int, long, unsigned long, int (*)(unsigned long)); | 11 | extern int __cpu_suspend(unsigned long, int (*)(unsigned long)); |
| 12 | extern void cpu_resume_mmu(void); | 12 | extern void cpu_resume_mmu(void); |
| 13 | 13 | ||
| 14 | /* | 14 | /* |
| 15 | * This is called by __cpu_suspend() to save the state, and do whatever | ||
| 16 | * flushing is required to ensure that when the CPU goes to sleep we have | ||
| 17 | * the necessary data available when the caches are not searched. | ||
| 18 | */ | ||
| 19 | void __cpu_suspend_save(u32 *ptr, u32 ptrsz, u32 sp, u32 *save_ptr) | ||
| 20 | { | ||
| 21 | *save_ptr = virt_to_phys(ptr); | ||
| 22 | |||
| 23 | /* This must correspond to the LDM in cpu_resume() assembly */ | ||
| 24 | *ptr++ = virt_to_phys(suspend_pgd); | ||
| 25 | *ptr++ = sp; | ||
| 26 | *ptr++ = virt_to_phys(cpu_do_resume); | ||
| 27 | |||
| 28 | cpu_do_suspend(ptr); | ||
| 29 | |||
| 30 | flush_cache_all(); | ||
| 31 | } | ||
| 32 | |||
| 33 | /* | ||
| 15 | * Hide the first two arguments to __cpu_suspend - these are an implementation | 34 | * Hide the first two arguments to __cpu_suspend - these are an implementation |
| 16 | * detail which platform code shouldn't have to know about. | 35 | * detail which platform code shouldn't have to know about. |
| 17 | */ | 36 | */ |
| @@ -29,8 +48,7 @@ int cpu_suspend(unsigned long arg, int (*fn)(unsigned long)) | |||
| 29 | * resume (indicated by a zero return code), we need to switch | 48 | * resume (indicated by a zero return code), we need to switch |
| 30 | * back to the correct page tables. | 49 | * back to the correct page tables. |
| 31 | */ | 50 | */ |
| 32 | ret = __cpu_suspend(virt_to_phys(suspend_pgd), | 51 | ret = __cpu_suspend(arg, fn); |
| 33 | PHYS_OFFSET - PAGE_OFFSET, arg, fn); | ||
| 34 | if (ret == 0) { | 52 | if (ret == 0) { |
| 35 | cpu_switch_mm(mm->pgd, mm); | 53 | cpu_switch_mm(mm->pgd, mm); |
| 36 | local_flush_tlb_all(); | 54 | local_flush_tlb_all(); |
