arm64 switch_mm improvements
Subsystems (3)
v2 cover arm64 switch_mm improvements
Hi all,
This is version two of the patches previously posted here:
http://lists.infradead.org/pipermail/linux-arm-kernel/2015-September/370720.html
Changes since v1 include:
* More comments
* Added reviewed-by tags
Cheers,
Will
--->8
Will Deacon (10):
arm64: mm: remove unused cpu_set_idmap_tcr_t0sz function
arm64: proc: de-scope TLBI operation during cold boot
arm64: flush: use local TLB and I-cache invalidation
arm64: mm: rewrite ASID allocator and MM context-switching code
arm64: tlbflush: remove redundant ASID casts to (unsigned long)
arm64: tlbflush: avoid flushing when fullmm == 1
arm64: switch_mm: simplify mm and CPU checks
arm64: mm: kill mm_cpumask usage
arm64: tlb: remove redundant barrier from __flush_tlb_pgtable
arm64: mm: remove dsb from update_mmu_cache
arch/arm64/include/asm/cacheflush.h | 7 ++ arch/arm64/include/asm/mmu.h | 15 +-- arch/arm64/include/asm/mmu_context.h | 113 ++++------------- arch/arm64/include/asm/pgtable.h | 6 +- arch/arm64/include/asm/thread_info.h | 1 - arch/arm64/include/asm/tlb.h | 26 ++-- arch/arm64/include/asm/tlbflush.h | 18 ++- arch/arm64/kernel/asm-offsets.c | 2 +- arch/arm64/kernel/efi.c | 5 +- arch/arm64/kernel/smp.c | 9 +- arch/arm64/kernel/suspend.c | 2 +- arch/arm64/mm/context.c | 236 +++++++++++++++++++++-------------- arch/arm64/mm/mmu.c | 2 +- arch/arm64/mm/proc.S | 6 +- 14 files changed, 222 insertions(+), 226 deletions(-)
Signature · 1 line
2.1.4
PATCH v2 1/10 arm64: mm: remove unused cpu_set_idmap_tcr_t0sz function
With commit b08d4640a3dc ("arm64: remove dead code"), cpu_set_idmap_tcr_t0sz is no longer called and can therefore be removed from the kernel.
This patch removes the function and effectively inlines the helper function __cpu_set_tcr_t0sz into cpu_set_default_tcr_t0sz.
--- arch/arm64/include/asm/mmu_context.h | 35 ++++++++++++----------------------- 1 file changed, 12 insertions(+), 23 deletions(-)
arch/arm64/include/asm/mmu_context.h +12 -23
@@ -77,34 +77,23 @@ static inline bool __cpu_uses_extended_idmap(void) unlikely(idmap_t0sz != TCR_T0SZ(VA_BITS))); } -static inline void __cpu_set_tcr_t0sz (u64 t0sz) -{ -unsigned long tcr; - -if (__cpu_uses_extended_idmap ()) - asmvolatile ( -" mrs %0, tcr_el1 ;" -" bfi %0, %1, %2, %3 ;" -" msr tcr_el1, %0 ;" -" isb" - :"=&r" (tcr) - :"r" (t0sz),"I" (TCR_T0SZ_OFFSET ),"I" (TCR_TxSZ_WIDTH)); -} - -/* -* Set TCR.T0SZ to the value appropriate for activating the identity map. -*/ -static inline void cpu_set_idmap_tcr_t0sz (void ) -{ -__cpu_set_tcr_t0sz (idmap_t0sz); -} -/* * Set TCR.T0SZ to its default value (based on VA_BITS) */ static inline void cpu_set_default_tcr_t0sz (void ) { -__cpu_set_tcr_t0sz (TCR_T0SZ (VA_BITS )); +unsigned long tcr; + +if (!__cpu_uses_extended_idmap ()) +return ; + + asmvolatile ( +" mrs %0, tcr_el1 ;" +" bfi %0, %1, %2, %3 ;" +" msr tcr_el1, %0 ;" +" isb" + :"=&r" (tcr) + :"r" (TCR_T0SZ (VA_BITS )),"I" (TCR_T0SZ_OFFSET ),"I" (TCR_TxSZ_WIDTH)); }static inline void switch_new_context (struct mm_struct *mm)
Signature · 1 line
2.1.4
PATCH v2 1/10 arm64: mm: remove unused cpu_set_idmap_tcr_t0sz function
Quoted 9 lines · Will Deacon
With commit
b08d4640a3dc("arm64: remove dead code"),cpu_set_idmap_tcr_t0szis no longer called and can therefore be removed from the kernel.This patch removes the function and effectively inlines the helper function
__cpu_set_tcr_t0szintocpu_set_default_tcr_t0sz.Reviewed-by Catalin Marinas <[email protected]>Signed-off-by Will Deacon <[email protected]>
Quoted 63 lines
--- arch/arm64/include/asm/mmu_context.h | 35 ++++++++++++----------------------- 1 file changed, 12 insertions(+), 23 deletions(-)arch/arm64/include/asm/mmu_context.h +12
-24@@ -77,34 +77,23 @@ static inline bool __cpu_uses_extended_idmap(void) unlikely(idmap_t0sz != TCR_T0SZ(VA_BITS))); } -static inline void __cpu_set_tcr_t0sz (u64 t0sz) -{ -unsigned long tcr; - -if (__cpu_uses_extended_idmap ()) - asmvolatile ( -" mrs %0, tcr_el1 ;" -" bfi %0, %1, %2, %3 ;" -" msr tcr_el1, %0 ;" -" isb" - :"=&r" (tcr) - :"r" (t0sz),"I" (TCR_T0SZ_OFFSET ),"I" (TCR_TxSZ_WIDTH)); -} - -/* -* Set TCR.T0SZ to the value appropriate for activating the identity map. -*/ -static inline void cpu_set_idmap_tcr_t0sz (void ) -{ -__cpu_set_tcr_t0sz (idmap_t0sz); -} -/* * Set TCR.T0SZ to its default value (based on VA_BITS) */ static inline void cpu_set_default_tcr_t0sz (void ) { -__cpu_set_tcr_t0sz (TCR_T0SZ (VA_BITS )); +unsigned long tcr; + +if (!__cpu_uses_extended_idmap ()) +return ; + + asmvolatile ( +" mrs %0, tcr_el1 ;" +" bfi %0, %1, %2, %3 ;" +" msr tcr_el1, %0 ;" +" isb" + :"=&r" (tcr) + :"r" (TCR_T0SZ (VA_BITS )),"I" (TCR_T0SZ_OFFSET ),"I" (TCR_TxSZ_WIDTH)); }static inline void switch_new_context (struct mm_struct *mm) --2.1.4
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel at lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
PATCH v2 2/10 arm64: proc: de-scope TLBI operation during cold boot
In reply to Will DeaconWhen cold-booting a CPU, we must invalidate any junk entries from the local TLB prior to enabling the MMU. This doesn't require broadcasting within the inner-shareable domain, so de-scope the operation to apply only to the local CPU.
--- arch/arm64/mm/proc.S | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
arch/arm64/mm/proc.S +2 -2
@@ -146,8 +146,8 @@ ENDPROC(cpu_do_switch_mm) * value of the SCTLR_EL1 register. */ ENTRY(__cpu_setup) - tlbi vmalle1is // invalidate I + D TLBs - dsb ish + tlbi vmalle1 // Invalidate local TLB + dsb nsh mov x0, #3 << 20 msr cpacr_el1, x0 // Enable FP/ASIMD
Signature · 1 line
2.1.4
PATCH v2 3/10 arm64: flush: use local TLB and I-cache invalidation
In reply to Will DeaconThere are a number of places where a single CPU is running with a private page-table and we need to perform maintenance on the TLB and I-cache in order to ensure correctness, but do not require the operation to be broadcast to other CPUs.
This patch adds local variants of tlb_flush_all and __flush_icache_all to support these use-cases and updates the callers respectively. __local_flush_icache_all also implies an isb, since it is intended to be used synchronously.
--- arch/arm64/include/asm/cacheflush.h | 7 +++++++ arch/arm64/include/asm/tlbflush.h | 8 ++++++++ arch/arm64/kernel/efi.c | 4 ++-- arch/arm64/kernel/smp.c | 2 +- arch/arm64/kernel/suspend.c | 2 +- arch/arm64/mm/context.c | 4 ++-- arch/arm64/mm/mmu.c | 2 +- 7 files changed, 22 insertions(+), 7 deletions(-)
arch/arm64/include/asm/cacheflush.h +7 -0
@@ -115,6 +115,13 @@ extern void copy_to_user_page(struct vm_area_struct *, struct page *,#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1extern void flush_dcache_page (struct page *); +static inline void __local_flush_icache_all (void ) +{ + asm("ic iallu" ); +dsb (nsh); +isb (); +} +static inline void __flush_icache_all (void ) { asm("ic ialluis" );
arch/arm64/include/asm/tlbflush.h +8 -0
@@ -63,6 +63,14 @@* only require the D-TLB to be invalidated. * - kaddr - Kernel virtual memory address */ +static inline void local_flush_tlb_all (void ) +{ +dsb (nshst); + asm("tlbi vmalle1" ); +dsb (nsh); +isb (); +} +static inline void flush_tlb_all (void ) {dsb (ishst);
arch/arm64/kernel/efi.c +2 -2
@@ -344,9 +344,9 @@ static void efi_set_pgd(struct mm_struct *mm)else cpu_switch_mm (mm->pgd, mm); -flush_tlb_all (); +local_flush_tlb_all ();if (icache_is_aivivt ()) -__flush_icache_all (); +__local_flush_icache_all (); }void efi_virtmap_load (void )
arch/arm64/kernel/smp.c +1 -1
@@ -152,7 +152,7 @@ asmlinkage void secondary_start_kernel(void)* point to zero page to avoid speculatively fetching new entries. */ cpu_set_reserved_ttbr0 (); -flush_tlb_all (); +local_flush_tlb_all ();cpu_set_default_tcr_t0sz ();preempt_disable ();
arch/arm64/kernel/suspend.c +1 -1
@@ -90,7 +90,7 @@ int cpu_suspend(unsigned long arg, int (*fn)(unsigned long))else cpu_switch_mm (mm->pgd, mm); -flush_tlb_all (); +local_flush_tlb_all ();/* * Restore per-cpu offset before any kernel
arch/arm64/mm/context.c +2 -2
@@ -48,9 +48,9 @@ static void flush_context(void) {/* set the reserved TTBR0 before flushing the TLB */ cpu_set_reserved_ttbr0 (); -flush_tlb_all (); +local_flush_tlb_all ();if (icache_is_aivivt ()) -__flush_icache_all (); +__local_flush_icache_all (); }static void set_mm_context (struct mm_struct *mm,unsigned int asid)
arch/arm64/mm/mmu.c +1 -1
@@ -456,7 +456,7 @@ void __init paging_init(void)* point to zero page to avoid speculatively fetching new entries. */ cpu_set_reserved_ttbr0 (); -flush_tlb_all (); +local_flush_tlb_all ();cpu_set_default_tcr_t0sz (); }
Signature · 1 line
2.1.4
PATCH v2 3/10 arm64: flush: use local TLB and I-cache invalidation
Quoted 5 lines · Will Deacon
There are a number of places where a single CPU is running with a private page-table and we need to perform maintenance on the TLB and I-cache in order to ensure correctness, but do not require the operation to be broadcast to other CPUs.
Quoted 7 lines
This patch adds local variants of
tlb_flush_alland__flush_icache_allto support these use-cases and updates the callers respectively.__local_flush_icache_allalso implies an isb, since it is intended to be used synchronously.Reviewed-by Catalin Marinas <[email protected]>Signed-off-by Will Deacon <[email protected]>
I like this one. It is similar to what some of my earlier patches did.
Quoted 10 lines
--- arch/arm64/include/asm/cacheflush.h | 7 +++++++ arch/arm64/include/asm/tlbflush.h | 8 ++++++++ arch/arm64/kernel/efi.c | 4 ++-- arch/arm64/kernel/smp.c | 2 +- arch/arm64/kernel/suspend.c | 2 +- arch/arm64/mm/context.c | 4 ++-- arch/arm64/mm/mmu.c | 2 +- 7 files changed, 22 insertions(+), 7 deletions(-)
[...]
PATCH v2 3/10 arm64: flush: use local TLB and I-cache invalidation
In reply to Will DeaconQuoted 5 lines · Will Deacon
There are a number of places where a single CPU is running with a private page-table and we need to perform maintenance on the TLB and I-cache in order to ensure correctness, but do not require the operation to be broadcast to other CPUs.
Quoted 7 lines
This patch adds local variants of
tlb_flush_alland__flush_icache_allto support these use-cases and updates the callers respectively.__local_flush_icache_allalso implies an isb, since it is intended to be used synchronously.Reviewed-by Catalin Marinas <[email protected]>Signed-off-by Will Deacon <[email protected]>
Quoted 126 lines
--- arch/arm64/include/asm/cacheflush.h | 7 +++++++ arch/arm64/include/asm/tlbflush.h | 8 ++++++++ arch/arm64/kernel/efi.c | 4 ++-- arch/arm64/kernel/smp.c | 2 +- arch/arm64/kernel/suspend.c | 2 +- arch/arm64/mm/context.c | 4 ++-- arch/arm64/mm/mmu.c | 2 +- 7 files changed, 22 insertions(+), 7 deletions(-)arch/arm64/include/asm/cacheflush.h +7
-0@@ -115,6 +115,13 @@ extern void copy_to_user_page(struct vm_area_struct *, struct page *,#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1extern void flush_dcache_page (struct page *); +static inline void __local_flush_icache_all (void ) +{ + asm("ic iallu" ); +dsb (nsh); +isb (); +} +static inline void __flush_icache_all (void ) { asm("ic ialluis" );arch/arm64/include/asm/tlbflush.h +8
-0@@ -63,6 +63,14 @@* only require the D-TLB to be invalidated. * - kaddr - Kernel virtual memory address */ +static inline void local_flush_tlb_all (void ) +{ +dsb (nshst); + asm("tlbi vmalle1" ); +dsb (nsh); +isb (); +} +static inline void flush_tlb_all (void ) {dsb (ishst);arch/arm64/kernel/efi.c +2
-2@@ -344,9 +344,9 @@ static void efi_set_pgd(struct mm_struct *mm)else cpu_switch_mm (mm->pgd, mm); -flush_tlb_all (); +local_flush_tlb_all ();if (icache_is_aivivt ()) -__flush_icache_all (); +__local_flush_icache_all (); }void efi_virtmap_load (void )arch/arm64/kernel/smp.c +1
-1@@ -152,7 +152,7 @@ asmlinkage void secondary_start_kernel(void)* point to zero page to avoid speculatively fetching new entries. */ cpu_set_reserved_ttbr0 (); -flush_tlb_all (); +local_flush_tlb_all ();cpu_set_default_tcr_t0sz ();preempt_disable ();arch/arm64/kernel/suspend.c +1
-1@@ -90,7 +90,7 @@ int cpu_suspend(unsigned long arg, int (*fn)(unsigned long))else cpu_switch_mm (mm->pgd, mm); -flush_tlb_all (); +local_flush_tlb_all ();/* * Restore per-cpu offset before any kernel arch/arm64/mm/context.c +2
-2@@ -48,9 +48,9 @@ static void flush_context(void) {/* set the reserved TTBR0 before flushing the TLB */ cpu_set_reserved_ttbr0 (); -flush_tlb_all (); +local_flush_tlb_all ();if (icache_is_aivivt ()) -__flush_icache_all (); +__local_flush_icache_all (); }static void set_mm_context (struct mm_struct *mm,unsigned int asid)arch/arm64/mm/mmu.c +1
-2@@ -456,7 +456,7 @@ void __init paging_init(void)* point to zero page to avoid speculatively fetching new entries. */ cpu_set_reserved_ttbr0 (); -flush_tlb_all (); +local_flush_tlb_all ();cpu_set_default_tcr_t0sz (); } --2.1.4
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel at lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
PATCH v2 4/10 arm64: mm: rewrite ASID allocator and MM context-switching code
In reply to Will DeaconOur current switch_mm implementation suffers from a number of problems:
(1) The ASID allocator relies on IPIs to synchronise the CPUs on a rollover event
(2) Because of (1), we cannot allocate ASIDs with interrupts disabled and therefore make use of a TIF_SWITCH_MM flag to postpone the actual switch to finish_arch_post_lock_switch
(3) We run context switch with a reserved (invalid) TTBR0 value, even though the ASID and pgd are updated atomically
(4) We take a global spinlock (cpu_asid_lock) during context-switch
(5) We use h/w broadcast TLB operations when they are not required (e.g. in flush_context)
This patch addresses these problems by rewriting the ASID algorithm to match the bitmap-based arch/arm/ implementation more closely. This in turn allows us to remove much of the complications surrounding switch_mm, including the ugly thread flag.
--- arch/arm64/include/asm/mmu.h | 15 +-- arch/arm64/include/asm/mmu_context.h | 76 ++--------- arch/arm64/include/asm/thread_info.h | 1 - arch/arm64/kernel/asm-offsets.c | 2 +- arch/arm64/kernel/efi.c | 1 - arch/arm64/mm/context.c | 238 +++++++++++++++++++++-------------- arch/arm64/mm/proc.S | 2 +- 7 files changed, 166 insertions(+), 169 deletions(-)
arch/arm64/include/asm/mmu.h +8 -7
@@ -17,15 +17,16 @@#define __ASM_MMU_Htypedef struct { -unsigned int id; -raw_spinlock_t id_lock; -void *vdso; +atomic64_t id; +void *vdso; }mm_context_t ; -#define INIT_MM_CONTEXT (name) \ - .context.id_lock = __RAW_SPIN_LOCK_UNLOCKED(name.context.id_lock), - -#define ASID (mm) ((mm)->context.id & 0xffff) +/* +* This macro is only used by the TLBI code, which cannot race with an +* ASID change and therefore doesn't need to reload the counter using +* atomic64_read. +*/ +#define ASID (mm) ((mm)->context.id.counter & 0xffff)extern void paging_init (void );extern void __iomem *early_io_map (phys_addr_t phys,unsigned long virt);
arch/arm64/include/asm/mmu_context.h +11 -65
90 lines not on this page · raw message
arch/arm64/include/asm/thread_info.h +0 -1
@@ -111,7 +111,6 @@ static inline struct thread_info *current_thread_info(void)#define TIF_RESTORE_SIGMASK 20#define TIF_SINGLESTEP 21#define TIF_32BIT 22/* 32bit process */ -#define TIF_SWITCH_MM 23/* deferred switch_mm */ #define _TIF_SIGPENDING (1 << TIF_SIGPENDING)#define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED)
arch/arm64/kernel/asm-offsets.c +1 -1
@@ -60,7 +60,7 @@ int main(void)DEFINE (S_SYSCALLNO , offsetof(struct pt_regs , syscallno));DEFINE (S_FRAME_SIZE ,sizeof (struct pt_regs ));BLANK (); - DEFINE(MM_CONTEXT_ID, offsetof(struct mm_struct, context.id)); + DEFINE(MM_CONTEXT_ID, offsetof(struct mm_struct, context.id.counter));BLANK ();DEFINE (VMA_VM_MM , offsetof(struct vm_area_struct , vm_mm));DEFINE (VMA_VM_FLAGS , offsetof(struct vm_area_struct , vm_flags));
arch/arm64/kernel/efi.c +0 -1
@@ -48,7 +48,6 @@ static struct mm_struct efi_mm = { .mmap_sem = __RWSEM_INITIALIZER(efi_mm.mmap_sem), .page_table_lock = __SPIN_LOCK_UNLOCKED(efi_mm.page_table_lock), .mmlist = LIST_HEAD_INIT(efi_mm.mmlist), - INIT_MM_CONTEXT(efi_mm) };static int uefi_debug__initdata ;
arch/arm64/mm/context.c +145 -93
280 lines not on this page · raw message
arch/arm64/mm/proc.S +1 -1
@@ -130,7 +130,7 @@ ENDPROC(cpu_do_resume) * - pgd_phys - physical address of new TTB */ ENTRY(cpu_do_switch_mm) - mmid w1, x1 // get mm->context.id + mmid x1, x1 // get mm->context.id bfi x0, x1, #48, #16 // set the ASID msr ttbr0_el1, x0 // set TTBR0 isb
Signature · 1 line
2.1.4
PATCH v2 5/10 arm64: tlbflush: remove redundant ASID casts to (unsigned long)
In reply to Will DeaconThe ASID macro returns a 64-bit (long long) value, so there is no need to cast to (unsigned long) before shifting prior to a TLBI operation.
--- arch/arm64/include/asm/tlbflush.h | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-)
arch/arm64/include/asm/tlbflush.h +4 -5
@@ -81,7 +81,7 @@ static inline void flush_tlb_all(void)static inline void flush_tlb_mm (struct mm_struct *mm) { -unsigned long asid = (unsigned long )ASID (mm) <<48 ; +unsigned long asid =ASID (mm) <<48 ;dsb (ishst); asm("tlbi aside1is, %0" : :"r" (asid));
@@ -91,8 +91,7 @@ static inline void flush_tlb_mm(struct mm_struct *mm)static inline void flush_tlb_page (struct vm_area_struct *vma,unsigned long uaddr) { -unsigned long addr = uaddr >>12 | - ((unsigned long )ASID (vma->vm_mm) <<48 ); +unsigned long addr = uaddr >>12 | (ASID (vma->vm_mm) <<48 );dsb (ishst); asm("tlbi vale1is, %0" : :"r" (addr));
@@ -109,7 +108,7 @@ static inline void __flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end, bool last_level) { - unsigned long asid = (unsigned long)ASID(vma->vm_mm) << 48; + unsigned long asid = ASID(vma->vm_mm) << 48;unsigned long addr;if ((end - start) >MAX_TLB_RANGE ) {
@@ -162,7 +161,7 @@ static inline void flush_tlb_kernel_range(unsigned long start, unsigned long endstatic inline void __flush_tlb_pgtable (struct mm_struct *mm,unsigned long uaddr) { -unsigned long addr = uaddr >>12 | ((unsigned long )ASID (mm) <<48 ); +unsigned long addr = uaddr >>12 | (ASID (mm) <<48 );dsb (ishst); asm("tlbi vae1is, %0" : :"r" (addr));
Signature · 1 line
2.1.4
PATCH v2 6/10 arm64: tlbflush: avoid flushing when fullmm == 1
In reply to Will DeaconThe TLB gather code sets fullmm=1 when tearing down the entire address space for an mm_struct on exit or execve. Given that the ASID allocator will never re-allocate a dirty ASID, this flushing is not needed and can simply be avoided in the flushing code.
--- arch/arm64/include/asm/tlb.h | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-)
arch/arm64/include/asm/tlb.h +15 -11
@@ -37,17 +37,21 @@ static inline void __tlb_remove_table(void *_table)static inline void tlb_flush (struct mmu_gather *tlb) { -if (tlb->fullmm) { -flush_tlb_mm (tlb->mm); - }else { -struct vm_area_struct vma = { .vm_mm = tlb->mm, }; -/* -* The intermediate page table levels are already handled by -* the __(pte|pmd|pud)_free_tlb() functions, so last level -* TLBI is sufficient here. -*/ -__flush_tlb_range (&vma, tlb->start, tlb->end, true); - } +struct vm_area_struct vma = { .vm_mm = tlb->mm, }; + +/* +* The ASID allocator will either invalidate the ASID or mark +* it as used. +*/ +if (tlb->fullmm) +return ; + +/* +* The intermediate page table levels are already handled by +* the __(pte|pmd|pud)_free_tlb() functions, so last level +* TLBI is sufficient here. +*/ +__flush_tlb_range (&vma, tlb->start, tlb->end, true); } static inline void __pte_free_tlb(struct mmu_gather *tlb, pgtable_t pte,
Signature · 1 line
2.1.4
PATCH v2 7/10 arm64: switch_mm: simplify mm and CPU checks
In reply to Will Deaconswitch_mm performs some checks to try and avoid entering the ASID allocator:
(1) If we're switching to the init_mm (no user mappings), then simply set a reserved TTBR0 value with no page table (the zero page)
(2) If prev == next *and* the mm_cpumask indicates that we've run on this CPU before, then we can skip the allocator.
However, there is plenty of redundancy here. With the new ASID allocator, if prev == next, then we know that our ASID is valid and do not need to worry about re-allocation. Consequently, we can drop the mm_cpumask check in (2) and move the prev == next check before the init_mm check, since if prev == next == init_mm then there's nothing to do.
--- arch/arm64/include/asm/mmu_context.h | 6 ++++-- arch/arm64/mm/context.c | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-)
arch/arm64/include/asm/mmu_context.h +4 -2
@@ -129,6 +129,9 @@ switch_mm(struct mm_struct *prev, struct mm_struct *next, {unsigned int cpu =smp_processor_id (); +if (prev == next) +return ; +/* * init_mm.pgd does not contain any user mappings and it is always * active for kernel addresses in TTBR1. Just set the reserved TTBR0.
@@ -138,8 +141,7 @@ switch_mm(struct mm_struct *prev, struct mm_struct *next,return ; } -if (!cpumask_test_and_set_cpu (cpu,mm_cpumask (next)) || prev != next) -check_and_switch_context (next, tsk); +check_and_switch_context (next, cpu); }#define deactivate_mm (tsk,mm) do { } while (0)
arch/arm64/mm/context.c +1 -1
@@ -166,10 +166,10 @@ void check_and_switch_context(struct mm_struct *mm, unsigned int cpu)local_flush_tlb_all ();atomic64_set (&per_cpu (active_asids, cpu), asid); -cpumask_set_cpu (cpu,mm_cpumask (mm));raw_spin_unlock_irqrestore (&cpu_asid_lock, flags); switch_mm_fastpath: +cpumask_set_cpu (cpu,mm_cpumask (mm));cpu_switch_mm (mm->pgd, mm); }
Signature · 1 line
2.1.4
PATCH v2 8/10 arm64: mm: kill mm_cpumask usage
In reply to Will Deaconmm_cpumask isn't actually used for anything on arm64, so remove all the code trying to keep it up-to-date.
--- arch/arm64/kernel/smp.c | 7 ------- arch/arm64/mm/context.c | 2 -- 2 files changed, 9 deletions(-)
arch/arm64/kernel/smp.c +0 -7
@@ -142,7 +142,6 @@ asmlinkage void secondary_start_kernel(void)*/ atomic_inc (&mm->mm_count); current->active_mm = mm; -cpumask_set_cpu (cpu,mm_cpumask (mm));set_my_cpu_offset (per_cpu_offset (smp_processor_id ()));printk ("CPU%u: Booted secondary processor\n" , cpu);
@@ -233,12 +232,6 @@ int __cpu_disable(void)* OK - migrate IRQs away from this CPU */ migrate_irqs (); - -/* -* Remove this CPU from the vm mask set of all processes. -*/ -clear_tasks_mm_cpumask (cpu); -return 0 ; }
arch/arm64/mm/context.c +0 -2
@@ -132,7 +132,6 @@ set_asid: bump_gen: asid |= generation; -cpumask_clear (mm_cpumask (mm));return asid; }
@@ -169,7 +168,6 @@ void check_and_switch_context(struct mm_struct *mm, unsigned int cpu)raw_spin_unlock_irqrestore (&cpu_asid_lock, flags); switch_mm_fastpath: -cpumask_set_cpu (cpu,mm_cpumask (mm));cpu_switch_mm (mm->pgd, mm); }
Signature · 1 line
2.1.4
PATCH v2 9/10 arm64: tlb: remove redundant barrier from __flush_tlb_pgtable
In reply to Will Deacon__flush_tlb_pgtable is used to invalidate intermediate page table entries after they have been cleared and are about to be freed. Since pXd_clear imply memory barriers, we don't need the extra one here.
--- arch/arm64/include/asm/tlbflush.h | 1 - 1 file changed, 1 deletion(-)
arch/arm64/include/asm/tlbflush.h +0 -1
@@ -163,7 +163,6 @@ static inline void __flush_tlb_pgtable(struct mm_struct *mm, {unsigned long addr = uaddr >>12 | (ASID (mm) <<48 ); -dsb (ishst); asm("tlbi vae1is, %0" : :"r" (addr));dsb (ish); }
Signature · 1 line
2.1.4
PATCH v2 10/10 arm64: mm: remove dsb from update_mmu_cache
In reply to Will Deaconupdate_mmu_cache() consists of a dsb(ishst) instruction so that new user mappings are guaranteed to be visible to the page table walker on exception return.
In reality this can be a very expensive operation which is rarely needed. Removing this barrier shows a modest improvement in hackbench scores and , in the worst case, we re-take the user fault and establish that there was nothing to do.
--- arch/arm64/include/asm/pgtable.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
arch/arm64/include/asm/pgtable.h +3 -3
@@ -646,10 +646,10 @@ static inline void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr, pte_t *ptep) {/* -* set_pte() does not have a DSB for user mappings, so make sure that -* the page table write is visible. +* We don't do anything here, so there's a very small chance of +* us retaking a user fault which we just fixed up. The alternative +* is doing a dsb(ishst), but that penalises the fastpath. */ -dsb (ishst ); }#define update_mmu_cache_pmd (vma, address, pmd) do { } while (0)
Signature · 1 line
2.1.4
Catalin Marinas
maintainerv2 cover arm64 switch_mm improvements
In reply to Will DeaconQuoted 11 lines · Will Deacon
Will Deacon (10):
arm64: mm: remove unusedcpu_set_idmap_tcr_t0szfunction
arm64: proc: de-scope TLBI operation during cold boot
arm64: flush: use local TLB and I-cache invalidation
arm64: mm: rewrite ASID allocator and MM context-switching code
arm64: tlbflush: remove redundant ASID casts to (unsigned long)
arm64: tlbflush: avoid flushing when fullmm == 1
arm64:switch_mm: simplify mm and CPU checks
arm64: mm: killmm_cpumaskusage
arm64: tlb: remove redundant barrier from__flush_tlb_pgtable
arm64: mm: remove dsb fromupdate_mmu_cache
Series queued for 4.4. Thanks.
Signature · 1 line
Catalin