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