aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/arm/include/asm/mmu.h2
-rw-r--r--arch/arm/include/asm/mmu_context.h72
-rw-r--r--arch/arm/include/asm/thread_info.h1
-rw-r--r--arch/arm/mm/context.c4
-rw-r--r--arch/arm/mm/proc-v7-2level.S3
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
50void __init_new_context(struct task_struct *tsk, struct mm_struct *mm); 50void __init_new_context(struct task_struct *tsk, struct mm_struct *mm);
51void __new_context(struct mm_struct *mm); 51void __new_context(struct mm_struct *mm);
52void cpu_set_reserved_ttbr0(void);
52 53
53static inline void check_context(struct mm_struct *mm) 54static 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
65static 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
103static 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
74static inline void check_context(struct mm_struct *mm) 109#else /* !CONFIG_CPU_HAS_ASID */
110
111static 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
26static void cpu_set_reserved_ttbr0(void) 26void 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
42static void cpu_set_reserved_ttbr0(void) 42void 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