csky: Use generic asid function from arm
[email protected]
maintainercover csky: Use generic asid function from arm
From: Guo Ren <[email protected]>
Julien Grall plan to seperate asid allocator into generic and vmid and other architectures could use it.
ref:
https://lore.kernel.org/linux-arm-kernel/[email protected]/
For C-SKY the first implementation is from mips and it's not implemented well for SMP in performance. Arm's asid allocator is right for us and we've tested it in our all CPUs:610/807/810/860 and it really reduce the tlb flush. We'll continue stress testing before merge into master.
It's good for all architectures in linux and let's continue the work.
@Julien
Could you give a seperate patch for add generic asid ?
Guo Ren (4):
csky: Revert mmu ASID mechanism
arch: Add generic asid implement from arm
csky: Use generic asid algorithm to implement switch_mm
csky: Improve tlb operation with help of asid
arch/csky/abiv1/inc/abi/ckmmu.h | 6 + arch/csky/abiv2/inc/abi/ckmmu.h | 10 ++ arch/csky/include/asm/asid.h | 77 ++++++++++++ arch/csky/include/asm/mmu.h | 2 +- arch/csky/include/asm/mmu_context.h | 114 ++--------------- arch/csky/include/asm/pgtable.h | 2 - arch/csky/kernel/smp.c | 2 - arch/csky/mm/Makefile | 2 + arch/csky/mm/asid.c | 185 ++++++++++++++++++++++++++++ arch/csky/mm/context.c | 46 +++++++ arch/csky/mm/init.c | 2 - arch/csky/mm/tlb.c | 238 ++++++++++++++---------------------- 12 files changed, 434 insertions(+), 252 deletions(-) create mode 100644 arch/csky/include/asm/asid.h create mode 100644 arch/csky/mm/asid.c create mode 100644 arch/csky/mm/context.c
Signature · 1 line
2.7.4
[email protected]
maintainerPATCH 1/4 csky: Revert mmu ASID mechanism
From: Guo Ren <[email protected]>
Current C-SKY ASID mechanism is from mips and it doesn't work well in a multi-core case. ASID per core mechanism is not suitable for C-SKY SMP tlb maintain operations, eg: tlbi.vas need share the same asid in all processors and it'll invalid the tlb entry in all cores with the same asid.
This patch is prepare for new ASID mechanism.
--- arch/csky/include/asm/mmu.h | 1 - arch/csky/include/asm/mmu_context.h | 112 ++------------------- arch/csky/include/asm/pgtable.h | 2 - arch/csky/kernel/smp.c | 2 - arch/csky/mm/init.c | 2 - arch/csky/mm/tlb.c | 190 ++---------------------------------- 6 files changed, 14 insertions(+), 295 deletions(-)
arch/csky/include/asm/mmu.h +0 -1
@@ -5,7 +5,6 @@#define __ASM_CSKY_MMU_Htypedef struct { -unsigned long asid[NR_CPUS ];void *vdso; }mm_context_t ;
arch/csky/include/asm/mmu_context.h +7 -105
129 lines not on this page · raw message
arch/csky/include/asm/pgtable.h +0 -2
@@ -290,8 +290,6 @@ static inline pte_t *pte_offset(pmd_t *dir, unsigned long address)extern pgd_t swapper_pg_dir[PTRS_PER_PGD ];extern void paging_init (void ); -extern void show_jtlb_table (void ); -void update_mmu_cache (struct vm_area_struct *vma,unsigned long address,pte_t *pte);
arch/csky/kernel/smp.c +0 -2
@@ -212,8 +212,6 @@ void csky_start_secondary(void)TLBMISS_HANDLER_SETUP_PGD (swapper_pg_dir);TLBMISS_HANDLER_SETUP_PGD_KERNEL (swapper_pg_dir); -asid_cache (smp_processor_id ()) =ASID_FIRST_VERSION ; -#ifdef CONFIG_CPU_HAS_FPU init_fpu ();#endif
arch/csky/mm/init.c +0 -2
@@ -114,8 +114,6 @@ void __init pre_mmu_init(void)TLBMISS_HANDLER_SETUP_PGD (swapper_pg_dir);TLBMISS_HANDLER_SETUP_PGD_KERNEL (swapper_pg_dir); -asid_cache (smp_processor_id ()) =ASID_FIRST_VERSION ; -/* Setup page mask to 4k */ write_mmu_pagemask (0 ); }
arch/csky/mm/tlb.c +7 -183
216 lines not on this page · raw message
Signature · 1 line
2.7.4
[email protected]
maintainerPATCH 2/4 arch: Add generic asid implement from arm
In reply to [email protected]From: Guo Ren <[email protected]>
The asid code is from arm64 and here is the ref link:
https://lore.kernel.org/linux-arm-kernel/[email protected]/
Seems it's good for other arch to implement asid.
--- arch/csky/include/asm/asid.h | 77 ++++++++++++++++++ arch/csky/mm/Makefile | 1 + arch/csky/mm/asid.c | 185 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 263 insertions(+) create mode 100644 arch/csky/include/asm/asid.h create mode 100644 arch/csky/mm/asid.c
arch/csky/include/asm/asid.h new file +77 -0
@@ -0,0 +1,77 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __ASM_ASM_ASID_H +#define __ASM_ASM_ASID_H + +#include <linux/atomic.h> +#include <linux/compiler.h> +#include <linux/cpumask.h> +#include <linux/percpu.h> +#include <linux/spinlock.h> + +struct asid_info +{ +atomic64_t generation; +unsigned long *map; +atomic64_t __percpu *active; +u64 __percpu *reserved; +u32 bits; +/* Lock protecting the structure */ +raw_spinlock_t lock; +/* Which CPU requires context flush on next call */ +cpumask_t flush_pending; +/* Number of ASID allocated by context (shift value) */ +unsigned int ctxt_shift; +/* Callback to locally flush the context. */ +void (*flush_cpu_ctxt_cb)(void ); +}; + +#define NUM_ASIDS (info) (1UL << ((info)->bits)) +#define NUM_CTXT_ASIDS (info) (NUM_ASIDS(info) >> (info)->ctxt_shift) + +#define active_asid (info, cpu) *per_cpu_ptr((info)->active, cpu) + +void asid_new_context (struct asid_info *info,atomic64_t *pasid, +unsigned int cpu); + +/* +* Check the ASID is still valid for the context. If not generate a new ASID. +* +* @pasid: Pointer to the current ASID batch +* @cpu: current CPU ID. Must have been acquired throught get_cpu() +*/ +static inline void asid_check_context (struct asid_info *info, +atomic64_t *pasid,unsigned int cpu) +{ +u64 asid, old_active_asid; + + asid =atomic64_read (pasid); + +/* +* The memory ordering here is subtle. +* If our active_asid is non-zero and the ASID matches the current +* generation, then we update the active_asid entry with a relaxed +* cmpxchg. Racing with a concurrent rollover means that either: +* +* - We get a zero back from the cmpxchg and end up waiting on the +* lock. Taking the lock synchronises with the rollover and so +* we are forced to see the updated generation. +* +* - We get a valid ASID back from the cmpxchg, which means the +* relaxed xchg in flush_context will treat us as reserved +* because atomic RmWs are totally ordered for a given location. +*/ + old_active_asid =atomic64_read (&active_asid (info, cpu)); +if (old_active_asid && + !((asid ^atomic64_read (&info->generation)) >> info->bits) && +atomic64_cmpxchg_relaxed (&active_asid (info, cpu), + old_active_asid, asid)) +return ; + +asid_new_context (info, pasid, cpu); +} + +int asid_allocator_init (struct asid_info *info, +u32 bits,unsigned int asid_per_ctxt, +void (*flush_cpu_ctxt_cb)(void )); + +#endif
arch/csky/mm/Makefile +1 -0
@@ -11,3 +11,4 @@ obj-y += init.o obj-y += ioremap.o obj-y += syscache.o obj-y += tlb.o +obj-y += asid.o
arch/csky/mm/asid.c new file +185 -0
185 lines not on this page · raw message
Signature · 1 line
2.7.4
[email protected]
maintainerPATCH 3/4 csky: Use generic asid algorithm to implement switch_mm
In reply to [email protected]From: Guo Ren <[email protected]>
Use linux generic asid/vmid algorithm to implement csky switch_mm function. The algorithm is from arm and it could work with SMP system. It'll help reduce tlb flush for switch_mm in task/vm switch.
--- arch/csky/abiv1/inc/abi/ckmmu.h | 6 +++++ arch/csky/abiv2/inc/abi/ckmmu.h | 10 ++++++++ arch/csky/include/asm/mmu.h | 1 + arch/csky/include/asm/mmu_context.h | 12 ++++++++-- arch/csky/mm/Makefile | 1 + arch/csky/mm/context.c | 46 +++++++++++++++++++++++++++++++++++++ 6 files changed, 74 insertions(+), 2 deletions(-) create mode 100644 arch/csky/mm/context.c
arch/csky/abiv1/inc/abi/ckmmu.h +6 -0
@@ -78,6 +78,12 @@ static inline void tlb_invalid_all(void)cpwcr ("cpcr8" ,0x04000000 ); } + +static inline void local_tlb_invalid_all (void ) +{ +tlb_invalid_all (); +} +static inline void tlb_invalid_indexed (void ) {cpwcr ("cpcr8" ,0x02000000 );
arch/csky/abiv2/inc/abi/ckmmu.h +10 -0
@@ -85,6 +85,16 @@ static inline void tlb_invalid_all(void)#endif } +static inline void local_tlb_invalid_all (void ) +{ +#ifdef CONFIG_CPU_HAS_TLBI + asmvolatile ("tlbi.all\n" :::"memory" ); +sync_is (); +#else +tlb_invalid_all (); +#endif +} +static inline void tlb_invalid_indexed (void ) {mtcr ("cr<8, 15>" ,0x02000000 );
arch/csky/include/asm/mmu.h +1 -0
@@ -5,6 +5,7 @@#define __ASM_CSKY_MMU_Htypedef struct { +atomic64_t asid;void *vdso; }mm_context_t ;
arch/csky/include/asm/mmu_context.h +10 -2
@@ -20,20 +20,28 @@#define TLBMISS_HANDLER_SETUP_PGD_KERNEL (pgd) \ setup_pgd(__pa(pgd), true) -#define init_new_context (tsk,mm) 0 +#define ASID_MASK ((1 << CONFIG_CPU_ASID_BITS) - 1) +#define cpu_asid (mm) (atomic64_read(&mm->context.asid) & ASID_MASK) + +#define init_new_context (tsk,mm) ({ atomic64_set(&(mm)->context.asid, 0); 0; })#define activate_mm (prev,next) switch_mm(prev, next, current)#define destroy_context (mm) do {} while (0)#define enter_lazy_tlb (mm, tsk) do {} while (0)#define deactivate_mm (tsk, mm) do {} while (0) +void check_and_switch_context (struct mm_struct *mm,unsigned int cpu); +static inline void switch_mm (struct mm_struct *prev,struct mm_struct *next,struct task_struct *tsk) { +unsigned int cpu =smp_processor_id (); +if (prev != next) -tlb_invalid_all (); +check_and_switch_context (next, cpu);TLBMISS_HANDLER_SETUP_PGD (next->pgd); +write_mmu_entryhi (next->context.asid.counter); }#endif /* __ASM_CSKY_MMU_CONTEXT_H */
arch/csky/mm/Makefile +1 -0
@@ -12,3 +12,4 @@ obj-y += ioremap.o obj-y += syscache.o obj-y += tlb.o obj-y += asid.o +obj-y += context.o
arch/csky/mm/context.c new file +46 -0
46 lines not on this page · raw message
Signature · 1 line
2.7.4
[email protected]
maintainerPATCH 4/4 csky: Improve tlb operation with help of asid
In reply to [email protected]From: Guo Ren <[email protected]>
There are two generations of tlb operation instruction for C-SKY. First generation is use mcr register and it need software do more things, second generation is use specific instructions, eg:
tlbi.va, tlbi.vas, tlbi.alls
We implemented the following functions:
- flush_tlb_range (a range of entries)
- flush_tlb_page (one entry)
Above functions use asid from vma->mm to invalid tlb entries and we could use tlbi.vas instruction for newest generation csky cpu.
- flush_tlb_kernel_range
- flush_tlb_one
Above functions don't care asid and it invalid the tlb entries only with vpn and we could use tlbi.vaas instruction for newest generat- ion csky cpu.
--- arch/csky/mm/tlb.c | 136 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 132 insertions(+), 4 deletions(-)
arch/csky/mm/tlb.c +132 -4
@@ -10,6 +10,13 @@#include <asm/pgtable.h> #include <asm/setup.h> +/* +* One C-SKY MMU TLB entry contain two PFN/page entry, ie: +* 1VPN -> 2PFN +*/ +#define TLB_ENTRY_SIZE (PAGE_SIZE * 2) +#define TLB_ENTRY_SIZE_MASK (PAGE_MASK << 1) +void flush_tlb_all (void ) {tlb_invalid_all ();
@@ -17,27 +24,148 @@ void flush_tlb_all(void)void flush_tlb_mm (struct mm_struct *mm) { +#ifdef CONFIG_CPU_HAS_TLBI + asmvolatile ("tlbi.asids %0" ::"r" (cpu_asid (mm))); +#else tlb_invalid_all (); +#endif } +/* +* MMU operation regs only could invalid tlb entry in jtlb and we +* need change asid field to invalid I-utlb & D-utlb. +*/ +#ifndef CONFIG_CPU_HAS_TLBI +#define restore_asid_inv_utlb (oldpid, newpid) \ +do { \ + if (oldpid == newpid) \ + write_mmu_entryhi(oldpid + 1); \ + write_mmu_entryhi(oldpid); \ +} while (0) +#endif +void flush_tlb_range (struct vm_area_struct *vma,unsigned long start,unsigned long end) { -tlb_invalid_all (); +unsigned long newpid =cpu_asid (vma->vm_mm); + + start &=TLB_ENTRY_SIZE_MASK ; + end +=TLB_ENTRY_SIZE -1 ; + end &=TLB_ENTRY_SIZE_MASK ; + +#ifdef CONFIG_CPU_HAS_TLBI +while (start < end) { + asmvolatile ("tlbi.vas %0" ::"r" (start | newpid)); + start +=2 *PAGE_SIZE ; + } +sync_is (); +#else + { +unsigned long flags, oldpid; + +local_irq_save (flags); + oldpid =read_mmu_entryhi () &ASID_MASK ; +while (start < end) { +int idx; + +write_mmu_entryhi (start | newpid); + start +=2 *PAGE_SIZE ; +tlb_probe (); + idx =read_mmu_index (); +if (idx >=0 ) +tlb_invalid_indexed (); + } +restore_asid_inv_utlb (oldpid, newpid); +local_irq_restore (flags); + } +#endif }void flush_tlb_kernel_range (unsigned long start,unsigned long end) { -tlb_invalid_all (); + start &=TLB_ENTRY_SIZE_MASK ; + end +=TLB_ENTRY_SIZE -1 ; + end &=TLB_ENTRY_SIZE_MASK ; + +#ifdef CONFIG_CPU_HAS_TLBI +while (start < end) { + asmvolatile ("tlbi.vaas %0" ::"r" (start)); + start +=2 *PAGE_SIZE ; + } +sync_is (); +#else + { +unsigned long flags, oldpid; + +local_irq_save (flags); + oldpid =read_mmu_entryhi () &ASID_MASK ; +while (start < end) { +int idx; + +write_mmu_entryhi (start | oldpid); + start +=2 *PAGE_SIZE ; +tlb_probe (); + idx =read_mmu_index (); +if (idx >=0 ) +tlb_invalid_indexed (); + } +restore_asid_inv_utlb (oldpid, oldpid); +local_irq_restore (flags); + } +#endif }void flush_tlb_page (struct vm_area_struct *vma,unsigned long addr) { -tlb_invalid_all (); +int newpid =cpu_asid (vma->vm_mm); + + addr &=TLB_ENTRY_SIZE_MASK ; + +#ifdef CONFIG_CPU_HAS_TLBI + asmvolatile ("tlbi.vas %0" ::"r" (addr | newpid)); +sync_is (); +#else + { +int oldpid, idx; +unsigned long flags; + +local_irq_save (flags); + oldpid =read_mmu_entryhi () &ASID_MASK ; +write_mmu_entryhi (addr | newpid); +tlb_probe (); + idx =read_mmu_index (); +if (idx >=0 ) +tlb_invalid_indexed (); + +restore_asid_inv_utlb (oldpid, newpid); +local_irq_restore (flags); + } +#endif }void flush_tlb_one (unsigned long addr) { -tlb_invalid_all (); + addr &=TLB_ENTRY_SIZE_MASK ; + +#ifdef CONFIG_CPU_HAS_TLBI + asmvolatile ("tlbi.vaas %0" ::"r" (addr)); +sync_is (); +#else + { +int oldpid, idx; +unsigned long flags; + +local_irq_save (flags); + oldpid =read_mmu_entryhi () &ASID_MASK ; +write_mmu_entryhi (addr | oldpid); +tlb_probe (); + idx =read_mmu_index (); +if (idx >=0 ) +tlb_invalid_indexed (); + +restore_asid_inv_utlb (oldpid, oldpid); +local_irq_restore (flags); + } +#endif }EXPORT_SYMBOL (flush_tlb_one);
Signature · 1 line
2.7.4