diff options
Diffstat (limited to 'arch/arm/kernel/suspend.c')
-rw-r--r-- | arch/arm/kernel/suspend.c | 76 |
1 files changed, 52 insertions, 24 deletions
diff --git a/arch/arm/kernel/suspend.c b/arch/arm/kernel/suspend.c index c59c97ea8268..41cf3cbf756d 100644 --- a/arch/arm/kernel/suspend.c +++ b/arch/arm/kernel/suspend.c | |||
@@ -1,15 +1,54 @@ | |||
1 | #include <linux/init.h> | 1 | #include <linux/init.h> |
2 | #include <linux/slab.h> | ||
2 | 3 | ||
4 | #include <asm/cacheflush.h> | ||
3 | #include <asm/idmap.h> | 5 | #include <asm/idmap.h> |
4 | #include <asm/pgalloc.h> | 6 | #include <asm/pgalloc.h> |
5 | #include <asm/pgtable.h> | 7 | #include <asm/pgtable.h> |
6 | #include <asm/memory.h> | 8 | #include <asm/memory.h> |
9 | #include <asm/smp_plat.h> | ||
7 | #include <asm/suspend.h> | 10 | #include <asm/suspend.h> |
8 | #include <asm/tlbflush.h> | 11 | #include <asm/tlbflush.h> |
9 | 12 | ||
10 | extern int __cpu_suspend(unsigned long, int (*)(unsigned long)); | 13 | extern int __cpu_suspend(unsigned long, int (*)(unsigned long)); |
11 | extern void cpu_resume_mmu(void); | 14 | extern void cpu_resume_mmu(void); |
12 | 15 | ||
16 | #ifdef CONFIG_MMU | ||
17 | /* | ||
18 | * Hide the first two arguments to __cpu_suspend - these are an implementation | ||
19 | * detail which platform code shouldn't have to know about. | ||
20 | */ | ||
21 | int cpu_suspend(unsigned long arg, int (*fn)(unsigned long)) | ||
22 | { | ||
23 | struct mm_struct *mm = current->active_mm; | ||
24 | int ret; | ||
25 | |||
26 | if (!idmap_pgd) | ||
27 | return -EINVAL; | ||
28 | |||
29 | /* | ||
30 | * Provide a temporary page table with an identity mapping for | ||
31 | * the MMU-enable code, required for resuming. On successful | ||
32 | * resume (indicated by a zero return code), we need to switch | ||
33 | * back to the correct page tables. | ||
34 | */ | ||
35 | ret = __cpu_suspend(arg, fn); | ||
36 | if (ret == 0) { | ||
37 | cpu_switch_mm(mm->pgd, mm); | ||
38 | local_flush_bp_all(); | ||
39 | local_flush_tlb_all(); | ||
40 | } | ||
41 | |||
42 | return ret; | ||
43 | } | ||
44 | #else | ||
45 | int cpu_suspend(unsigned long arg, int (*fn)(unsigned long)) | ||
46 | { | ||
47 | return __cpu_suspend(arg, fn); | ||
48 | } | ||
49 | #define idmap_pgd NULL | ||
50 | #endif | ||
51 | |||
13 | /* | 52 | /* |
14 | * This is called by __cpu_suspend() to save the state, and do whatever | 53 | * This is called by __cpu_suspend() to save the state, and do whatever |
15 | * flushing is required to ensure that when the CPU goes to sleep we have | 54 | * flushing is required to ensure that when the CPU goes to sleep we have |
@@ -47,30 +86,19 @@ void __cpu_suspend_save(u32 *ptr, u32 ptrsz, u32 sp, u32 *save_ptr) | |||
47 | virt_to_phys(save_ptr) + sizeof(*save_ptr)); | 86 | virt_to_phys(save_ptr) + sizeof(*save_ptr)); |
48 | } | 87 | } |
49 | 88 | ||
50 | /* | 89 | extern struct sleep_save_sp sleep_save_sp; |
51 | * Hide the first two arguments to __cpu_suspend - these are an implementation | ||
52 | * detail which platform code shouldn't have to know about. | ||
53 | */ | ||
54 | int cpu_suspend(unsigned long arg, int (*fn)(unsigned long)) | ||
55 | { | ||
56 | struct mm_struct *mm = current->active_mm; | ||
57 | int ret; | ||
58 | |||
59 | if (!idmap_pgd) | ||
60 | return -EINVAL; | ||
61 | 90 | ||
62 | /* | 91 | static int cpu_suspend_alloc_sp(void) |
63 | * Provide a temporary page table with an identity mapping for | 92 | { |
64 | * the MMU-enable code, required for resuming. On successful | 93 | void *ctx_ptr; |
65 | * resume (indicated by a zero return code), we need to switch | 94 | /* ctx_ptr is an array of physical addresses */ |
66 | * back to the correct page tables. | 95 | ctx_ptr = kcalloc(mpidr_hash_size(), sizeof(u32), GFP_KERNEL); |
67 | */ | ||
68 | ret = __cpu_suspend(arg, fn); | ||
69 | if (ret == 0) { | ||
70 | cpu_switch_mm(mm->pgd, mm); | ||
71 | local_flush_bp_all(); | ||
72 | local_flush_tlb_all(); | ||
73 | } | ||
74 | 96 | ||
75 | return ret; | 97 | if (WARN_ON(!ctx_ptr)) |
98 | return -ENOMEM; | ||
99 | sleep_save_sp.save_ptr_stash = ctx_ptr; | ||
100 | sleep_save_sp.save_ptr_stash_phys = virt_to_phys(ctx_ptr); | ||
101 | sync_cache_w(&sleep_save_sp); | ||
102 | return 0; | ||
76 | } | 103 | } |
104 | early_initcall(cpu_suspend_alloc_sp); | ||