diff options
| author | Catalin Marinas <catalin.marinas@arm.com> | 2013-07-23 11:15:36 -0400 |
|---|---|---|
| committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2013-07-26 07:02:09 -0400 |
| commit | bdae73cd374e28db544fdd9b77de689a36e3c129 (patch) | |
| tree | aa22b6e3e1232f27fa50c24a2144daa65d61d7c6 | |
| parent | 1f49856bb029779d8f1b63517a3a3b34ffe672c7 (diff) | |
ARM: 7790/1: Fix deferred mm switch on VIVT processors
As of commit b9d4d42ad9 (ARM: Remove __ARCH_WANT_INTERRUPTS_ON_CTXSW on
pre-ARMv6 CPUs), the mm switching on VIVT processors is done in the
finish_arch_post_lock_switch() function to avoid whole cache flushing
with interrupts disabled. The need for deferred mm switch is stored as a
thread flag (TIF_SWITCH_MM). However, with preemption enabled, we can
have another thread switch before finish_arch_post_lock_switch(). If the
new thread has the same mm as the previous 'next' thread, the scheduler
will not call switch_mm() and the TIF_SWITCH_MM flag won't be set for
the new thread.
This patch moves the switch pending flag to the mm_context_t structure
since this is specific to the mm rather than thread.
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
Reported-by: Marc Kleine-Budde <mkl@pengutronix.de>
Tested-by: Marc Kleine-Budde <mkl@pengutronix.de>
Cc: <stable@vger.kernel.org> # 3.5+
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
| -rw-r--r-- | arch/arm/include/asm/mmu.h | 2 | ||||
| -rw-r--r-- | arch/arm/include/asm/mmu_context.h | 20 | ||||
| -rw-r--r-- | arch/arm/include/asm/thread_info.h | 1 |
3 files changed, 18 insertions, 5 deletions
diff --git a/arch/arm/include/asm/mmu.h b/arch/arm/include/asm/mmu.h index e3d55547e755..d1b4998e4f43 100644 --- a/arch/arm/include/asm/mmu.h +++ b/arch/arm/include/asm/mmu.h | |||
| @@ -6,6 +6,8 @@ | |||
| 6 | typedef struct { | 6 | typedef struct { |
| 7 | #ifdef CONFIG_CPU_HAS_ASID | 7 | #ifdef CONFIG_CPU_HAS_ASID |
| 8 | atomic64_t id; | 8 | atomic64_t id; |
| 9 | #else | ||
| 10 | int switch_pending; | ||
| 9 | #endif | 11 | #endif |
| 10 | unsigned int vmalloc_seq; | 12 | unsigned int vmalloc_seq; |
| 11 | } mm_context_t; | 13 | } mm_context_t; |
diff --git a/arch/arm/include/asm/mmu_context.h b/arch/arm/include/asm/mmu_context.h index b5792b7fd8d3..9b32f76bb0dd 100644 --- a/arch/arm/include/asm/mmu_context.h +++ b/arch/arm/include/asm/mmu_context.h | |||
| @@ -56,7 +56,7 @@ static inline void check_and_switch_context(struct mm_struct *mm, | |||
| 56 | * on non-ASID CPUs, the old mm will remain valid until the | 56 | * on non-ASID CPUs, the old mm will remain valid until the |
| 57 | * finish_arch_post_lock_switch() call. | 57 | * finish_arch_post_lock_switch() call. |
| 58 | */ | 58 | */ |
| 59 | set_ti_thread_flag(task_thread_info(tsk), TIF_SWITCH_MM); | 59 | mm->context.switch_pending = 1; |
| 60 | else | 60 | else |
| 61 | cpu_switch_mm(mm->pgd, mm); | 61 | cpu_switch_mm(mm->pgd, mm); |
| 62 | } | 62 | } |
| @@ -65,9 +65,21 @@ static inline void check_and_switch_context(struct mm_struct *mm, | |||
| 65 | finish_arch_post_lock_switch | 65 | finish_arch_post_lock_switch |
| 66 | static inline void finish_arch_post_lock_switch(void) | 66 | static inline void finish_arch_post_lock_switch(void) |
| 67 | { | 67 | { |
| 68 | if (test_and_clear_thread_flag(TIF_SWITCH_MM)) { | 68 | struct mm_struct *mm = current->mm; |
| 69 | struct mm_struct *mm = current->mm; | 69 | |
| 70 | cpu_switch_mm(mm->pgd, mm); | 70 | if (mm && mm->context.switch_pending) { |
| 71 | /* | ||
| 72 | * Preemption must be disabled during cpu_switch_mm() as we | ||
| 73 | * have some stateful cache flush implementations. Check | ||
| 74 | * switch_pending again in case we were preempted and the | ||
| 75 | * switch to this mm was already done. | ||
| 76 | */ | ||
| 77 | preempt_disable(); | ||
| 78 | if (mm->context.switch_pending) { | ||
| 79 | mm->context.switch_pending = 0; | ||
| 80 | cpu_switch_mm(mm->pgd, mm); | ||
| 81 | } | ||
| 82 | preempt_enable_no_resched(); | ||
| 71 | } | 83 | } |
| 72 | } | 84 | } |
| 73 | 85 | ||
diff --git a/arch/arm/include/asm/thread_info.h b/arch/arm/include/asm/thread_info.h index 214d4158089a..2b8114fcba09 100644 --- a/arch/arm/include/asm/thread_info.h +++ b/arch/arm/include/asm/thread_info.h | |||
| @@ -156,7 +156,6 @@ extern int vfp_restore_user_hwstate(struct user_vfp __user *, | |||
| 156 | #define TIF_USING_IWMMXT 17 | 156 | #define TIF_USING_IWMMXT 17 |
| 157 | #define TIF_MEMDIE 18 /* is terminating due to OOM killer */ | 157 | #define TIF_MEMDIE 18 /* is terminating due to OOM killer */ |
| 158 | #define TIF_RESTORE_SIGMASK 20 | 158 | #define TIF_RESTORE_SIGMASK 20 |
| 159 | #define TIF_SWITCH_MM 22 /* deferred switch_mm */ | ||
| 160 | 159 | ||
| 161 | #define _TIF_SIGPENDING (1 << TIF_SIGPENDING) | 160 | #define _TIF_SIGPENDING (1 << TIF_SIGPENDING) |
| 162 | #define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) | 161 | #define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) |
