From 2db003a5ddee986d4bc67c069ee3aa1b1b320f1d Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Fri, 6 May 2016 14:36:24 +0100 Subject: [PATCH] MIPS: Support extended ASIDs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for extended ASIDs as determined by the Config4.AE bit. Since the only supported CPUs known to implement this are Netlogic XLP and MIPS I6400, select this variable ASID support based upon CONFIG_CPU_XLP and CONFIG_CPU_MIPSR6. Signed-off-by: Paul Burton Signed-off-by: James Hogan Cc: Jayachandran C. Cc: Paolo Bonzini Cc: Radim Krčmář Cc: linux-mips@linux-mips.org Cc: kvm@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/13211/ Signed-off-by: Ralf Baechle --- arch/mips/Kconfig | 6 ++++++ arch/mips/include/asm/cpu-info.h | 14 ++++++++++++++ arch/mips/kernel/asm-offsets.c | 10 ++++++++++ arch/mips/kernel/cpu-probe.c | 13 +++++++++++++ arch/mips/kernel/genex.S | 2 +- arch/mips/kvm/locore.S | 14 ++++++++++++++ 6 files changed, 58 insertions(+), 1 deletion(-) diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 0cab0da2ab55..5cc5b621ae69 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -1706,6 +1706,7 @@ config CPU_XLP select CPU_HAS_PREFETCH select CPU_MIPSR2 select CPU_SUPPORTS_HUGEPAGES + select MIPS_ASID_BITS_VARIABLE help Netlogic Microsystems XLP processors. endchoice @@ -2001,6 +2002,7 @@ config CPU_MIPSR6 bool default y if CPU_MIPS32_R6 || CPU_MIPS64_R6 select HAVE_ARCH_BITREVERSE + select MIPS_ASID_BITS_VARIABLE select MIPS_SPRAM config EVA @@ -2457,9 +2459,13 @@ config MIPS_ASID_SHIFT config MIPS_ASID_BITS int + default 0 if MIPS_ASID_BITS_VARIABLE default 6 if CPU_R3000 || CPU_TX39XX default 8 +config MIPS_ASID_BITS_VARIABLE + bool + # # - Highmem only makes sense for the 32-bit kernel. # - The current highmem code will only work properly on physically indexed diff --git a/arch/mips/include/asm/cpu-info.h b/arch/mips/include/asm/cpu-info.h index 1ae26a393153..392da7e6fc72 100644 --- a/arch/mips/include/asm/cpu-info.h +++ b/arch/mips/include/asm/cpu-info.h @@ -40,6 +40,9 @@ struct cache_desc { struct cpuinfo_mips { unsigned long asid_cache; +#ifdef CONFIG_MIPS_ASID_BITS_VARIABLE + unsigned long asid_mask; +#endif /* * Capability and feature descriptor structure for MIPS CPU @@ -139,7 +142,18 @@ static inline unsigned long cpu_asid_inc(void) static inline unsigned long cpu_asid_mask(struct cpuinfo_mips *cpuinfo) { +#ifdef CONFIG_MIPS_ASID_BITS_VARIABLE + return cpuinfo->asid_mask; +#endif return ((1 << CONFIG_MIPS_ASID_BITS) - 1) << CONFIG_MIPS_ASID_SHIFT; } +static inline void set_cpu_asid_mask(struct cpuinfo_mips *cpuinfo, + unsigned long asid_mask) +{ +#ifdef CONFIG_MIPS_ASID_BITS_VARIABLE + cpuinfo->asid_mask = asid_mask; +#endif +} + #endif /* __ASM_CPU_INFO_H */ diff --git a/arch/mips/kernel/asm-offsets.c b/arch/mips/kernel/asm-offsets.c index 154e2039ea5e..1ea973b2abb1 100644 --- a/arch/mips/kernel/asm-offsets.c +++ b/arch/mips/kernel/asm-offsets.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -338,6 +339,15 @@ void output_pm_defines(void) } #endif +void output_cpuinfo_defines(void) +{ + COMMENT(" MIPS cpuinfo offsets. "); + DEFINE(CPUINFO_SIZE, sizeof(struct cpuinfo_mips)); +#ifdef CONFIG_MIPS_ASID_BITS_VARIABLE + OFFSET(CPUINFO_ASID_MASK, cpuinfo_mips, asid_mask); +#endif +} + void output_kvm_defines(void) { COMMENT(" KVM/MIPS Specfic offsets. "); diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index 064ab389e964..5ca4fefb1344 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -732,6 +732,7 @@ static inline unsigned int decode_config4(struct cpuinfo_mips *c) unsigned int newcf4; unsigned int mmuextdef; unsigned int ftlb_page = MIPS_CONF4_FTLBPAGESIZE; + unsigned long asid_mask; config4 = read_c0_config4(); @@ -792,6 +793,18 @@ static inline unsigned int decode_config4(struct cpuinfo_mips *c) c->kscratch_mask = (config4 >> 16) & 0xff; + asid_mask = MIPS_ENTRYHI_ASID; + if (config4 & MIPS_CONF4_AE) + asid_mask |= MIPS_ENTRYHI_ASIDX; + set_cpu_asid_mask(c, asid_mask); + + /* + * Warn if the computed ASID mask doesn't match the mask the kernel + * is built for. This may indicate either a serious problem or an + * easy optimisation opportunity, but either way should be addressed. + */ + WARN_ON(asid_mask != cpu_asid_mask(c)); + return config4 & MIPS_CONF_M; } diff --git a/arch/mips/kernel/genex.S b/arch/mips/kernel/genex.S index 17374aef6f00..bff9644b9ad1 100644 --- a/arch/mips/kernel/genex.S +++ b/arch/mips/kernel/genex.S @@ -455,7 +455,7 @@ NESTED(nmi_handler, PT_SIZE, sp) .set noreorder /* check if TLB contains a entry for EPC */ MFC0 k1, CP0_ENTRYHI - andi k1, MIPS_ENTRYHI_ASID + andi k1, MIPS_ENTRYHI_ASID | MIPS_ENTRYHI_ASIDX MFC0 k0, CP0_EPC PTR_SRL k0, _PAGE_SHIFT + 1 PTR_SLL k0, _PAGE_SHIFT + 1 diff --git a/arch/mips/kvm/locore.S b/arch/mips/kvm/locore.S index 1f2167bc847d..3ef03009de5f 100644 --- a/arch/mips/kvm/locore.S +++ b/arch/mips/kvm/locore.S @@ -137,7 +137,14 @@ FEXPORT(__kvm_mips_load_asid) INT_SLL t2, t2, 2 /* x4 */ REG_ADDU t3, t1, t2 LONG_L k0, (t3) +#ifdef CONFIG_MIPS_ASID_BITS_VARIABLE + li t3, CPUINFO_SIZE/4 + mul t2, t2, t3 /* x sizeof(struct cpuinfo_mips)/4 */ + LONG_L t2, (cpu_data + CPUINFO_ASID_MASK)(t2) + and k0, k0, t2 +#else andi k0, k0, MIPS_ENTRYHI_ASID +#endif mtc0 k0, CP0_ENTRYHI ehb @@ -449,7 +456,14 @@ __kvm_mips_return_to_guest: INT_SLL t2, t2, 2 /* x4 */ REG_ADDU t3, t1, t2 LONG_L k0, (t3) +#ifdef CONFIG_MIPS_ASID_BITS_VARIABLE + li t3, CPUINFO_SIZE/4 + mul t2, t2, t3 /* x sizeof(struct cpuinfo_mips)/4 */ + LONG_L t2, (cpu_data + CPUINFO_ASID_MASK)(t2) + and k0, k0, t2 +#else andi k0, k0, MIPS_ENTRYHI_ASID +#endif mtc0 k0, CP0_ENTRYHI ehb