aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/arm/include/asm/proc-fns.h8
-rw-r--r--arch/arm/kernel/sleep.S53
-rw-r--r--arch/arm/kernel/suspend.c24
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);
81extern void cpu_do_switch_mm(unsigned long pgd_phys, struct mm_struct *mm); 81extern void cpu_do_switch_mm(unsigned long pgd_phys, struct mm_struct *mm);
82extern void cpu_set_pte_ext(pte_t *ptep, pte_t pte, unsigned int ext); 82extern void cpu_set_pte_ext(pte_t *ptep, pte_t pte, unsigned int ext);
83extern void cpu_reset(unsigned long addr) __attribute__((noreturn)); 83extern void cpu_reset(unsigned long addr) __attribute__((noreturn));
84
85/* These three are private to arch/arm/kernel/suspend.c */
86extern void cpu_do_suspend(void *);
87extern 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
94extern void cpu_resume(void); 102extern 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 */
17ENTRY(__cpu_suspend) 17ENTRY(__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
61ENDPROC(__cpu_suspend) 42ENDPROC(__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
9static pgd_t *suspend_pgd; 9static pgd_t *suspend_pgd;
10 10
11extern int __cpu_suspend(int, long, unsigned long, int (*)(unsigned long)); 11extern int __cpu_suspend(unsigned long, int (*)(unsigned long));
12extern void cpu_resume_mmu(void); 12extern 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 */
19void __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();