From: Will Deacon Date: Fri, 20 May 2011 11:19:58 +0000 (+0100) Subject: ARM: mm: fix racy ASID rollover broadcast on SMP platforms X-Git-Tag: firefly_0821_release~9595^2~130^2~4 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=3006cb821a6596d592cf43537a9b1993581a07d5;p=firefly-linux-kernel-4.4.55.git ARM: mm: fix racy ASID rollover broadcast on SMP platforms If ASID rollover is detected on a CPU in an SMP system, a synchronous IPI call is made to force the secondaries to reallocate their current ASIDs. There is a problem where a CPU may be interrupted in the cpu_switch_mm code with the context ID held in r1. After servicing the IPI, the context ID register will be updated with an ASID from the previous generation, polluting the TLB for when that ASID becomes valid in the new generation. This patch disables interrupts during cpu_switch_mm for SMP systems, preventing incoming rollover broadcasts from being serviced while the register state is inconsistent. Additionally, the context resetting code is modified to call cpu_switch_mm, rather than setting the context ID register directly, so that the TTBR always agrees with the ASID. Acked-by: Catalin Marinas Signed-off-by: Will Deacon --- diff --git a/arch/arm/include/asm/proc-fns.h b/arch/arm/include/asm/proc-fns.h index 8ec535e11fd7..35c3fc93b88f 100644 --- a/arch/arm/include/asm/proc-fns.h +++ b/arch/arm/include/asm/proc-fns.h @@ -97,8 +97,22 @@ extern void cpu_resume(void); #ifdef CONFIG_MMU +#ifdef CONFIG_SMP + +#define cpu_switch_mm(pgd, mm) \ + ({ \ + unsigned long flags; \ + local_irq_save(flags); \ + cpu_do_switch_mm(virt_to_phys(pgd), mm); \ + local_irq_restore(flags); \ + }) + +#else /* SMP */ + #define cpu_switch_mm(pgd,mm) cpu_do_switch_mm(virt_to_phys(pgd),mm) +#endif + #define cpu_get_pgd() \ ({ \ unsigned long pg; \ diff --git a/arch/arm/mm/context.c b/arch/arm/mm/context.c index b0ee9ba3cfab..131f381712c9 100644 --- a/arch/arm/mm/context.c +++ b/arch/arm/mm/context.c @@ -99,8 +99,7 @@ static void reset_context(void *info) set_mm_context(mm, asid); /* set the new ASID */ - asm("mcr p15, 0, %0, c13, c0, 1\n" : : "r" (mm->context.id)); - isb(); + cpu_switch_mm(mm->pgd, mm); } #else