diff options
-rw-r--r-- | arch/arm/include/asm/mmu.h | 2 | ||||
-rw-r--r-- | arch/arm/include/asm/mmu_context.h | 72 | ||||
-rw-r--r-- | arch/arm/include/asm/thread_info.h | 1 | ||||
-rw-r--r-- | arch/arm/mm/context.c | 4 | ||||
-rw-r--r-- | arch/arm/mm/proc-v7-2level.S | 3 |
5 files changed, 61 insertions, 21 deletions
diff --git a/arch/arm/include/asm/mmu.h b/arch/arm/include/asm/mmu.h index b8e580a297e4..20b43d6f23b3 100644 --- a/arch/arm/include/asm/mmu.h +++ b/arch/arm/include/asm/mmu.h | |||
@@ -39,6 +39,8 @@ typedef struct { | |||
39 | * so enable interrupts over the context switch to avoid high | 39 | * so enable interrupts over the context switch to avoid high |
40 | * latency. | 40 | * latency. |
41 | */ | 41 | */ |
42 | #ifndef CONFIG_CPU_HAS_ASID | ||
42 | #define __ARCH_WANT_INTERRUPTS_ON_CTXSW | 43 | #define __ARCH_WANT_INTERRUPTS_ON_CTXSW |
44 | #endif | ||
43 | 45 | ||
44 | #endif | 46 | #endif |
diff --git a/arch/arm/include/asm/mmu_context.h b/arch/arm/include/asm/mmu_context.h index a0b3cac0547c..94e265cb5146 100644 --- a/arch/arm/include/asm/mmu_context.h +++ b/arch/arm/include/asm/mmu_context.h | |||
@@ -49,39 +49,80 @@ DECLARE_PER_CPU(struct mm_struct *, current_mm); | |||
49 | 49 | ||
50 | void __init_new_context(struct task_struct *tsk, struct mm_struct *mm); | 50 | void __init_new_context(struct task_struct *tsk, struct mm_struct *mm); |
51 | void __new_context(struct mm_struct *mm); | 51 | void __new_context(struct mm_struct *mm); |
52 | void cpu_set_reserved_ttbr0(void); | ||
52 | 53 | ||
53 | static inline void check_context(struct mm_struct *mm) | 54 | static inline void switch_new_context(struct mm_struct *mm) |
54 | { | 55 | { |
55 | /* | 56 | unsigned long flags; |
56 | * This code is executed with interrupts enabled. Therefore, | ||
57 | * mm->context.id cannot be updated to the latest ASID version | ||
58 | * on a different CPU (and condition below not triggered) | ||
59 | * without first getting an IPI to reset the context. The | ||
60 | * alternative is to take a read_lock on mm->context.id_lock | ||
61 | * (after changing its type to rwlock_t). | ||
62 | */ | ||
63 | if (unlikely((mm->context.id ^ cpu_last_asid) >> ASID_BITS)) | ||
64 | __new_context(mm); | ||
65 | 57 | ||
58 | __new_context(mm); | ||
59 | |||
60 | local_irq_save(flags); | ||
61 | cpu_switch_mm(mm->pgd, mm); | ||
62 | local_irq_restore(flags); | ||
63 | } | ||
64 | |||
65 | static inline void check_and_switch_context(struct mm_struct *mm, | ||
66 | struct task_struct *tsk) | ||
67 | { | ||
66 | if (unlikely(mm->context.kvm_seq != init_mm.context.kvm_seq)) | 68 | if (unlikely(mm->context.kvm_seq != init_mm.context.kvm_seq)) |
67 | __check_kvm_seq(mm); | 69 | __check_kvm_seq(mm); |
70 | |||
71 | /* | ||
72 | * Required during context switch to avoid speculative page table | ||
73 | * walking with the wrong TTBR. | ||
74 | */ | ||
75 | cpu_set_reserved_ttbr0(); | ||
76 | |||
77 | if (!((mm->context.id ^ cpu_last_asid) >> ASID_BITS)) | ||
78 | /* | ||
79 | * The ASID is from the current generation, just switch to the | ||
80 | * new pgd. This condition is only true for calls from | ||
81 | * context_switch() and interrupts are already disabled. | ||
82 | */ | ||
83 | cpu_switch_mm(mm->pgd, mm); | ||
84 | else if (irqs_disabled()) | ||
85 | /* | ||
86 | * Defer the new ASID allocation until after the context | ||
87 | * switch critical region since __new_context() cannot be | ||
88 | * called with interrupts disabled (it sends IPIs). | ||
89 | */ | ||
90 | set_ti_thread_flag(task_thread_info(tsk), TIF_SWITCH_MM); | ||
91 | else | ||
92 | /* | ||
93 | * That is a direct call to switch_mm() or activate_mm() with | ||
94 | * interrupts enabled and a new context. | ||
95 | */ | ||
96 | switch_new_context(mm); | ||
68 | } | 97 | } |
69 | 98 | ||
70 | #define init_new_context(tsk,mm) (__init_new_context(tsk,mm),0) | 99 | #define init_new_context(tsk,mm) (__init_new_context(tsk,mm),0) |
71 | 100 | ||
72 | #else | 101 | #define finish_arch_post_lock_switch \ |
102 | finish_arch_post_lock_switch | ||
103 | static inline void finish_arch_post_lock_switch(void) | ||
104 | { | ||
105 | if (test_and_clear_thread_flag(TIF_SWITCH_MM)) | ||
106 | switch_new_context(current->mm); | ||
107 | } | ||
73 | 108 | ||
74 | static inline void check_context(struct mm_struct *mm) | 109 | #else /* !CONFIG_CPU_HAS_ASID */ |
110 | |||
111 | static inline void check_and_switch_context(struct mm_struct *mm, | ||
112 | struct task_struct *tsk) | ||
75 | { | 113 | { |
76 | #ifdef CONFIG_MMU | 114 | #ifdef CONFIG_MMU |
77 | if (unlikely(mm->context.kvm_seq != init_mm.context.kvm_seq)) | 115 | if (unlikely(mm->context.kvm_seq != init_mm.context.kvm_seq)) |
78 | __check_kvm_seq(mm); | 116 | __check_kvm_seq(mm); |
117 | cpu_switch_mm(mm->pgd, mm); | ||
79 | #endif | 118 | #endif |
80 | } | 119 | } |
81 | 120 | ||
82 | #define init_new_context(tsk,mm) 0 | 121 | #define init_new_context(tsk,mm) 0 |
83 | 122 | ||
84 | #endif | 123 | #define finish_arch_post_lock_switch() do { } while (0) |
124 | |||
125 | #endif /* CONFIG_CPU_HAS_ASID */ | ||
85 | 126 | ||
86 | #define destroy_context(mm) do { } while(0) | 127 | #define destroy_context(mm) do { } while(0) |
87 | 128 | ||
@@ -123,8 +164,7 @@ switch_mm(struct mm_struct *prev, struct mm_struct *next, | |||
123 | struct mm_struct **crt_mm = &per_cpu(current_mm, cpu); | 164 | struct mm_struct **crt_mm = &per_cpu(current_mm, cpu); |
124 | *crt_mm = next; | 165 | *crt_mm = next; |
125 | #endif | 166 | #endif |
126 | check_context(next); | 167 | check_and_switch_context(next, tsk); |
127 | cpu_switch_mm(next->pgd, next); | ||
128 | if (cache_is_vivt()) | 168 | if (cache_is_vivt()) |
129 | cpumask_clear_cpu(cpu, mm_cpumask(prev)); | 169 | cpumask_clear_cpu(cpu, mm_cpumask(prev)); |
130 | } | 170 | } |
diff --git a/arch/arm/include/asm/thread_info.h b/arch/arm/include/asm/thread_info.h index d4c24d412a8d..9e13e33ec746 100644 --- a/arch/arm/include/asm/thread_info.h +++ b/arch/arm/include/asm/thread_info.h | |||
@@ -146,6 +146,7 @@ extern void vfp_flush_hwstate(struct thread_info *); | |||
146 | #define TIF_MEMDIE 18 /* is terminating due to OOM killer */ | 146 | #define TIF_MEMDIE 18 /* is terminating due to OOM killer */ |
147 | #define TIF_RESTORE_SIGMASK 20 | 147 | #define TIF_RESTORE_SIGMASK 20 |
148 | #define TIF_SECCOMP 21 | 148 | #define TIF_SECCOMP 21 |
149 | #define TIF_SWITCH_MM 22 /* deferred switch_mm */ | ||
149 | 150 | ||
150 | #define _TIF_SIGPENDING (1 << TIF_SIGPENDING) | 151 | #define _TIF_SIGPENDING (1 << TIF_SIGPENDING) |
151 | #define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) | 152 | #define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) |
diff --git a/arch/arm/mm/context.c b/arch/arm/mm/context.c index aaa291fc072e..06a2e7ce23c3 100644 --- a/arch/arm/mm/context.c +++ b/arch/arm/mm/context.c | |||
@@ -23,7 +23,7 @@ DEFINE_PER_CPU(struct mm_struct *, current_mm); | |||
23 | #endif | 23 | #endif |
24 | 24 | ||
25 | #ifdef CONFIG_ARM_LPAE | 25 | #ifdef CONFIG_ARM_LPAE |
26 | static void cpu_set_reserved_ttbr0(void) | 26 | void cpu_set_reserved_ttbr0(void) |
27 | { | 27 | { |
28 | unsigned long ttbl = __pa(swapper_pg_dir); | 28 | unsigned long ttbl = __pa(swapper_pg_dir); |
29 | unsigned long ttbh = 0; | 29 | unsigned long ttbh = 0; |
@@ -39,7 +39,7 @@ static void cpu_set_reserved_ttbr0(void) | |||
39 | isb(); | 39 | isb(); |
40 | } | 40 | } |
41 | #else | 41 | #else |
42 | static void cpu_set_reserved_ttbr0(void) | 42 | void cpu_set_reserved_ttbr0(void) |
43 | { | 43 | { |
44 | u32 ttb; | 44 | u32 ttb; |
45 | /* Copy TTBR1 into TTBR0 */ | 45 | /* Copy TTBR1 into TTBR0 */ |
diff --git a/arch/arm/mm/proc-v7-2level.S b/arch/arm/mm/proc-v7-2level.S index 72270482a922..42ac069c8012 100644 --- a/arch/arm/mm/proc-v7-2level.S +++ b/arch/arm/mm/proc-v7-2level.S | |||
@@ -46,9 +46,6 @@ ENTRY(cpu_v7_switch_mm) | |||
46 | #ifdef CONFIG_ARM_ERRATA_430973 | 46 | #ifdef CONFIG_ARM_ERRATA_430973 |
47 | mcr p15, 0, r2, c7, c5, 6 @ flush BTAC/BTB | 47 | mcr p15, 0, r2, c7, c5, 6 @ flush BTAC/BTB |
48 | #endif | 48 | #endif |
49 | mrc p15, 0, r2, c2, c0, 1 @ load TTB 1 | ||
50 | mcr p15, 0, r2, c2, c0, 0 @ into TTB 0 | ||
51 | isb | ||
52 | #ifdef CONFIG_ARM_ERRATA_754322 | 49 | #ifdef CONFIG_ARM_ERRATA_754322 |
53 | dsb | 50 | dsb |
54 | #endif | 51 | #endif |