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