diff options
Diffstat (limited to 'arch/mips/kernel/cpu-probe.c')
| -rw-r--r-- | arch/mips/kernel/cpu-probe.c | 981 |
1 files changed, 476 insertions, 505 deletions
diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index d08afc7dc507..1e49e05ac8b1 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Processor capabilities determination functions. * @@ -5,14 +6,10 @@ * Copyright (C) 1994 - 2006 Ralf Baechle * Copyright (C) 2003, 2004 Maciej W. Rozycki * Copyright (C) 2001, 2004, 2011, 2012 MIPS Technologies, Inc. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. */ #include <linux/init.h> #include <linux/kernel.h> +#include <linux/mmu_context.h> #include <linux/ptrace.h> #include <linux/smp.h> #include <linux/stddef.h> @@ -30,33 +27,18 @@ #include <asm/elf.h> #include <asm/pgtable-bits.h> #include <asm/spram.h> +#include <asm/traps.h> #include <linux/uaccess.h> +#include "fpu-probe.h" + +#include <asm/mach-loongson64/cpucfg-emul.h> + /* Hardware capabilities */ unsigned int elf_hwcap __read_mostly; EXPORT_SYMBOL_GPL(elf_hwcap); -/* - * Get the FPU Implementation/Revision. - */ -static inline unsigned long cpu_get_fpu_id(void) -{ - unsigned long tmp, fpu_id; - - tmp = read_c0_status(); - __enable_fpu(FPU_AS_IS); - fpu_id = read_32bit_cp1_register(CP1_REVISION); - write_c0_status(tmp); - return fpu_id; -} - -/* - * Check if the CPU has an external FPU. - */ -static inline int __cpu_has_fpu(void) -{ - return (cpu_get_fpu_id() & FPIR_IMP_MASK) != FPIR_IMP_NONE; -} +static bool mmid_disabled_quirk; static inline unsigned long cpu_get_msa_id(void) { @@ -71,262 +53,7 @@ static inline unsigned long cpu_get_msa_id(void) return msa_id; } -/* - * Determine the FCSR mask for FPU hardware. - */ -static inline void cpu_set_fpu_fcsr_mask(struct cpuinfo_mips *c) -{ - unsigned long sr, mask, fcsr, fcsr0, fcsr1; - - fcsr = c->fpu_csr31; - mask = FPU_CSR_ALL_X | FPU_CSR_ALL_E | FPU_CSR_ALL_S | FPU_CSR_RM; - - sr = read_c0_status(); - __enable_fpu(FPU_AS_IS); - - fcsr0 = fcsr & mask; - write_32bit_cp1_register(CP1_STATUS, fcsr0); - fcsr0 = read_32bit_cp1_register(CP1_STATUS); - - fcsr1 = fcsr | ~mask; - write_32bit_cp1_register(CP1_STATUS, fcsr1); - fcsr1 = read_32bit_cp1_register(CP1_STATUS); - - write_32bit_cp1_register(CP1_STATUS, fcsr); - - write_c0_status(sr); - - c->fpu_msk31 = ~(fcsr0 ^ fcsr1) & ~mask; -} - -/* - * Determine the IEEE 754 NaN encodings and ABS.fmt/NEG.fmt execution modes - * supported by FPU hardware. - */ -static void cpu_set_fpu_2008(struct cpuinfo_mips *c) -{ - if (c->isa_level & (MIPS_CPU_ISA_M32R1 | MIPS_CPU_ISA_M64R1 | - MIPS_CPU_ISA_M32R2 | MIPS_CPU_ISA_M64R2 | - MIPS_CPU_ISA_M32R6 | MIPS_CPU_ISA_M64R6)) { - unsigned long sr, fir, fcsr, fcsr0, fcsr1; - - sr = read_c0_status(); - __enable_fpu(FPU_AS_IS); - - fir = read_32bit_cp1_register(CP1_REVISION); - if (fir & MIPS_FPIR_HAS2008) { - fcsr = read_32bit_cp1_register(CP1_STATUS); - - fcsr0 = fcsr & ~(FPU_CSR_ABS2008 | FPU_CSR_NAN2008); - write_32bit_cp1_register(CP1_STATUS, fcsr0); - fcsr0 = read_32bit_cp1_register(CP1_STATUS); - - fcsr1 = fcsr | FPU_CSR_ABS2008 | FPU_CSR_NAN2008; - write_32bit_cp1_register(CP1_STATUS, fcsr1); - fcsr1 = read_32bit_cp1_register(CP1_STATUS); - - write_32bit_cp1_register(CP1_STATUS, fcsr); - - if (!(fcsr0 & FPU_CSR_NAN2008)) - c->options |= MIPS_CPU_NAN_LEGACY; - if (fcsr1 & FPU_CSR_NAN2008) - c->options |= MIPS_CPU_NAN_2008; - - if ((fcsr0 ^ fcsr1) & FPU_CSR_ABS2008) - c->fpu_msk31 &= ~FPU_CSR_ABS2008; - else - c->fpu_csr31 |= fcsr & FPU_CSR_ABS2008; - - if ((fcsr0 ^ fcsr1) & FPU_CSR_NAN2008) - c->fpu_msk31 &= ~FPU_CSR_NAN2008; - else - c->fpu_csr31 |= fcsr & FPU_CSR_NAN2008; - } else { - c->options |= MIPS_CPU_NAN_LEGACY; - } - - write_c0_status(sr); - } else { - c->options |= MIPS_CPU_NAN_LEGACY; - } -} - -/* - * IEEE 754 conformance mode to use. Affects the NaN encoding and the - * ABS.fmt/NEG.fmt execution mode. - */ -static enum { STRICT, LEGACY, STD2008, RELAXED } ieee754 = STRICT; - -/* - * Set the IEEE 754 NaN encodings and the ABS.fmt/NEG.fmt execution modes - * to support by the FPU emulator according to the IEEE 754 conformance - * mode selected. Note that "relaxed" straps the emulator so that it - * allows 2008-NaN binaries even for legacy processors. - */ -static void cpu_set_nofpu_2008(struct cpuinfo_mips *c) -{ - c->options &= ~(MIPS_CPU_NAN_2008 | MIPS_CPU_NAN_LEGACY); - c->fpu_csr31 &= ~(FPU_CSR_ABS2008 | FPU_CSR_NAN2008); - c->fpu_msk31 &= ~(FPU_CSR_ABS2008 | FPU_CSR_NAN2008); - - switch (ieee754) { - case STRICT: - if (c->isa_level & (MIPS_CPU_ISA_M32R1 | MIPS_CPU_ISA_M64R1 | - MIPS_CPU_ISA_M32R2 | MIPS_CPU_ISA_M64R2 | - MIPS_CPU_ISA_M32R6 | MIPS_CPU_ISA_M64R6)) { - c->options |= MIPS_CPU_NAN_2008 | MIPS_CPU_NAN_LEGACY; - } else { - c->options |= MIPS_CPU_NAN_LEGACY; - c->fpu_msk31 |= FPU_CSR_ABS2008 | FPU_CSR_NAN2008; - } - break; - case LEGACY: - c->options |= MIPS_CPU_NAN_LEGACY; - c->fpu_msk31 |= FPU_CSR_ABS2008 | FPU_CSR_NAN2008; - break; - case STD2008: - c->options |= MIPS_CPU_NAN_2008; - c->fpu_csr31 |= FPU_CSR_ABS2008 | FPU_CSR_NAN2008; - c->fpu_msk31 |= FPU_CSR_ABS2008 | FPU_CSR_NAN2008; - break; - case RELAXED: - c->options |= MIPS_CPU_NAN_2008 | MIPS_CPU_NAN_LEGACY; - break; - } -} - -/* - * Override the IEEE 754 NaN encoding and ABS.fmt/NEG.fmt execution mode - * according to the "ieee754=" parameter. - */ -static void cpu_set_nan_2008(struct cpuinfo_mips *c) -{ - switch (ieee754) { - case STRICT: - mips_use_nan_legacy = !!cpu_has_nan_legacy; - mips_use_nan_2008 = !!cpu_has_nan_2008; - break; - case LEGACY: - mips_use_nan_legacy = !!cpu_has_nan_legacy; - mips_use_nan_2008 = !cpu_has_nan_legacy; - break; - case STD2008: - mips_use_nan_legacy = !cpu_has_nan_2008; - mips_use_nan_2008 = !!cpu_has_nan_2008; - break; - case RELAXED: - mips_use_nan_legacy = true; - mips_use_nan_2008 = true; - break; - } -} - -/* - * IEEE 754 NaN encoding and ABS.fmt/NEG.fmt execution mode override - * settings: - * - * strict: accept binaries that request a NaN encoding supported by the FPU - * legacy: only accept legacy-NaN binaries - * 2008: only accept 2008-NaN binaries - * relaxed: accept any binaries regardless of whether supported by the FPU - */ -static int __init ieee754_setup(char *s) -{ - if (!s) - return -1; - else if (!strcmp(s, "strict")) - ieee754 = STRICT; - else if (!strcmp(s, "legacy")) - ieee754 = LEGACY; - else if (!strcmp(s, "2008")) - ieee754 = STD2008; - else if (!strcmp(s, "relaxed")) - ieee754 = RELAXED; - else - return -1; - - if (!(boot_cpu_data.options & MIPS_CPU_FPU)) - cpu_set_nofpu_2008(&boot_cpu_data); - cpu_set_nan_2008(&boot_cpu_data); - - return 0; -} - -early_param("ieee754", ieee754_setup); - -/* - * Set the FIR feature flags for the FPU emulator. - */ -static void cpu_set_nofpu_id(struct cpuinfo_mips *c) -{ - u32 value; - - value = 0; - if (c->isa_level & (MIPS_CPU_ISA_M32R1 | MIPS_CPU_ISA_M64R1 | - MIPS_CPU_ISA_M32R2 | MIPS_CPU_ISA_M64R2 | - MIPS_CPU_ISA_M32R6 | MIPS_CPU_ISA_M64R6)) - value |= MIPS_FPIR_D | MIPS_FPIR_S; - if (c->isa_level & (MIPS_CPU_ISA_M32R2 | MIPS_CPU_ISA_M64R2 | - MIPS_CPU_ISA_M32R6 | MIPS_CPU_ISA_M64R6)) - value |= MIPS_FPIR_F64 | MIPS_FPIR_L | MIPS_FPIR_W; - if (c->options & MIPS_CPU_NAN_2008) - value |= MIPS_FPIR_HAS2008; - c->fpu_id = value; -} - -/* Determined FPU emulator mask to use for the boot CPU with "nofpu". */ -static unsigned int mips_nofpu_msk31; - -/* - * Set options for FPU hardware. - */ -static void cpu_set_fpu_opts(struct cpuinfo_mips *c) -{ - c->fpu_id = cpu_get_fpu_id(); - mips_nofpu_msk31 = c->fpu_msk31; - - if (c->isa_level & (MIPS_CPU_ISA_M32R1 | MIPS_CPU_ISA_M64R1 | - MIPS_CPU_ISA_M32R2 | MIPS_CPU_ISA_M64R2 | - MIPS_CPU_ISA_M32R6 | MIPS_CPU_ISA_M64R6)) { - if (c->fpu_id & MIPS_FPIR_3D) - c->ases |= MIPS_ASE_MIPS3D; - if (c->fpu_id & MIPS_FPIR_UFRP) - c->options |= MIPS_CPU_UFR; - if (c->fpu_id & MIPS_FPIR_FREP) - c->options |= MIPS_CPU_FRE; - } - - cpu_set_fpu_fcsr_mask(c); - cpu_set_fpu_2008(c); - cpu_set_nan_2008(c); -} - -/* - * Set options for the FPU emulator. - */ -static void cpu_set_nofpu_opts(struct cpuinfo_mips *c) -{ - c->options &= ~MIPS_CPU_FPU; - c->fpu_msk31 = mips_nofpu_msk31; - - cpu_set_nofpu_2008(c); - cpu_set_nan_2008(c); - cpu_set_nofpu_id(c); -} - -static int mips_fpu_disabled; - -static int __init fpu_disable(char *s) -{ - cpu_set_nofpu_opts(&boot_cpu_data); - mips_fpu_disabled = 1; - - return 1; -} - -__setup("nofpu", fpu_disable); - -int mips_dsp_disabled; +static int mips_dsp_disabled; static int __init dsp_disable(char *s) { @@ -414,6 +141,14 @@ static int __init ftlb_disable(char *s) __setup("noftlb", ftlb_disable); +/* + * Check if the CPU has per tc perf counters + */ +static inline void cpu_set_mt_per_tc_perf(struct cpuinfo_mips *c) +{ + if (read_c0_config7() & MTI_CONF7_PTC) + c->options |= MIPS_CPU_MT_PER_TC_PERF_COUNTERS; +} static inline void check_errata(void) { @@ -424,7 +159,7 @@ static inline void check_errata(void) /* * Erratum "RPS May Cause Incorrect Instruction Execution" * This code only handles VPE0, any SMP/RTOS code - * making use of VPE1 will be responsable for that VPE. + * making use of VPE1 will be responsible for that VPE. */ if ((c->processor_id & PRID_REV_MASK) <= PRID_REV_34K_V1_0_2) write_c0_config7(read_c0_config7() | MIPS_CONF7_RPS); @@ -447,7 +182,6 @@ void __init check_bugs32(void) static inline int cpu_has_confreg(void) { #ifdef CONFIG_CPU_R3000 - extern unsigned long r3k_cache_size(unsigned long); unsigned long size1, size2; unsigned long cfg = read_c0_conf(); @@ -467,6 +201,13 @@ static inline void set_elf_platform(int cpu, const char *plat) __elf_platform = plat; } +static inline void set_elf_base_platform(const char *plat) +{ + if (__elf_base_platform == NULL) { + __elf_base_platform = plat; + } +} + static inline void cpu_probe_vmbits(struct cpuinfo_mips *c) { #ifdef __NEED_VMBITS_PROBE @@ -479,31 +220,56 @@ static inline void cpu_probe_vmbits(struct cpuinfo_mips *c) static void set_isa(struct cpuinfo_mips *c, unsigned int isa) { switch (isa) { + case MIPS_CPU_ISA_M64R5: + c->isa_level |= MIPS_CPU_ISA_M32R5 | MIPS_CPU_ISA_M64R5; + set_elf_base_platform("mips64r5"); + fallthrough; case MIPS_CPU_ISA_M64R2: c->isa_level |= MIPS_CPU_ISA_M32R2 | MIPS_CPU_ISA_M64R2; + set_elf_base_platform("mips64r2"); + fallthrough; case MIPS_CPU_ISA_M64R1: c->isa_level |= MIPS_CPU_ISA_M32R1 | MIPS_CPU_ISA_M64R1; + set_elf_base_platform("mips64"); + fallthrough; case MIPS_CPU_ISA_V: c->isa_level |= MIPS_CPU_ISA_V; + set_elf_base_platform("mips5"); + fallthrough; case MIPS_CPU_ISA_IV: c->isa_level |= MIPS_CPU_ISA_IV; + set_elf_base_platform("mips4"); + fallthrough; case MIPS_CPU_ISA_III: c->isa_level |= MIPS_CPU_ISA_II | MIPS_CPU_ISA_III; + set_elf_base_platform("mips3"); break; /* R6 incompatible with everything else */ case MIPS_CPU_ISA_M64R6: c->isa_level |= MIPS_CPU_ISA_M32R6 | MIPS_CPU_ISA_M64R6; + set_elf_base_platform("mips64r6"); + fallthrough; case MIPS_CPU_ISA_M32R6: c->isa_level |= MIPS_CPU_ISA_M32R6; + set_elf_base_platform("mips32r6"); /* Break here so we don't add incompatible ISAs */ break; + case MIPS_CPU_ISA_M32R5: + c->isa_level |= MIPS_CPU_ISA_M32R5; + set_elf_base_platform("mips32r5"); + fallthrough; case MIPS_CPU_ISA_M32R2: c->isa_level |= MIPS_CPU_ISA_M32R2; + set_elf_base_platform("mips32r2"); + fallthrough; case MIPS_CPU_ISA_M32R1: c->isa_level |= MIPS_CPU_ISA_M32R1; + set_elf_base_platform("mips32"); + fallthrough; case MIPS_CPU_ISA_II: c->isa_level |= MIPS_CPU_ISA_II; + set_elf_base_platform("mips2"); break; } } @@ -550,14 +316,14 @@ static int set_ftlb_enable(struct cpuinfo_mips *c, enum ftlb_flags flags) config = read_c0_config6(); if (flags & FTLB_EN) - config |= MIPS_CONF6_FTLBEN; + config |= MTI_CONF6_FTLBEN; else - config &= ~MIPS_CONF6_FTLBEN; + config &= ~MTI_CONF6_FTLBEN; if (flags & FTLB_SET_PROB) { - config &= ~(3 << MIPS_CONF6_FTLBP_SHIFT); + config &= ~(3 << MTI_CONF6_FTLBP_SHIFT); config |= calculate_ftlb_probability(c) - << MIPS_CONF6_FTLBP_SHIFT; + << MTI_CONF6_FTLBP_SHIFT; } write_c0_config6(config); @@ -569,7 +335,7 @@ static int set_ftlb_enable(struct cpuinfo_mips *c, enum ftlb_flags flags) if (!(flags & FTLB_EN)) return 1; return 0; - case CPU_LOONGSON3: + case CPU_LOONGSON64: /* Flush ITLB, DTLB, VTLB and FTLB */ write_c0_diag(LOONGSON_DIAG_ITLB | LOONGSON_DIAG_DTLB | LOONGSON_DIAG_VTLB | LOONGSON_DIAG_FTLB); @@ -577,10 +343,10 @@ static int set_ftlb_enable(struct cpuinfo_mips *c, enum ftlb_flags flags) config = read_c0_config6(); if (flags & FTLB_EN) /* Enable FTLB */ - write_c0_config6(config & ~MIPS_CONF6_FTLBDIS); + write_c0_config6(config & ~LOONGSON_CONF6_FTLBDIS); else /* Disable FTLB */ - write_c0_config6(config | MIPS_CONF6_FTLBDIS); + write_c0_config6(config | LOONGSON_CONF6_FTLBDIS); break; default: return 1; @@ -589,6 +355,52 @@ static int set_ftlb_enable(struct cpuinfo_mips *c, enum ftlb_flags flags) return 0; } +static int mm_config(struct cpuinfo_mips *c) +{ + unsigned int config0, update, mm; + + config0 = read_c0_config(); + mm = config0 & MIPS_CONF_MM; + + /* + * It's implementation dependent what type of write-merge is supported + * and whether it can be enabled/disabled. If it is settable lets make + * the merging allowed by default. Some platforms might have + * write-through caching unsupported. In this case just ignore the + * CP0.Config.MM bit field value. + */ + switch (c->cputype) { + case CPU_24K: + case CPU_34K: + case CPU_74K: + case CPU_P5600: + case CPU_P6600: + c->options |= MIPS_CPU_MM_FULL; + update = MIPS_CONF_MM_FULL; + break; + case CPU_1004K: + case CPU_1074K: + case CPU_INTERAPTIV: + case CPU_PROAPTIV: + mm = 0; + fallthrough; + default: + update = 0; + break; + } + + if (update) { + config0 = (config0 & ~MIPS_CONF_MM) | update; + write_c0_config(config0); + } else if (mm == MIPS_CONF_MM_SYSAD) { + c->options |= MIPS_CPU_MM_SYSAD; + } else if (mm == MIPS_CONF_MM_FULL) { + c->options |= MIPS_CPU_MM_FULL; + } + + return 0; +} + static inline unsigned int decode_config0(struct cpuinfo_mips *c) { unsigned int config0; @@ -780,7 +592,7 @@ static inline unsigned int decode_config4(struct cpuinfo_mips *c) MIPS_CONF4_VTLBSIZEEXT_SHIFT) * 0x40; c->tlbsize = c->tlbsizevtlb; ftlb_page = MIPS_CONF4_VFTLBPAGESIZE; - /* fall through */ + fallthrough; case MIPS_CONF4_MMUEXTDEF_FTLBSIZEEXT: if (mips_ftlb_disabled) break; @@ -829,10 +641,19 @@ static inline unsigned int decode_config4(struct cpuinfo_mips *c) static inline unsigned int decode_config5(struct cpuinfo_mips *c) { - unsigned int config5; + unsigned int config5, max_mmid_width; + unsigned long asid_mask; config5 = read_c0_config5(); config5 &= ~(MIPS_CONF5_UFR | MIPS_CONF5_UFE); + + if (cpu_has_mips_r6) { + if (!mmid_disabled_quirk && (!__builtin_constant_p(cpu_has_mmid) || cpu_has_mmid)) + config5 |= MIPS_CONF5_MI; + else + config5 &= ~MIPS_CONF5_MI; + } + write_c0_config5(config5); if (config5 & MIPS_CONF5_EVA) @@ -848,6 +669,52 @@ static inline unsigned int decode_config5(struct cpuinfo_mips *c) if (config5 & MIPS_CONF5_CA2) c->ases |= MIPS_ASE_MIPS16E2; + if (config5 & MIPS_CONF5_CRCP) + elf_hwcap |= HWCAP_MIPS_CRC32; + + if (cpu_has_mips_r6) { + /* Ensure the write to config5 above takes effect */ + back_to_back_c0_hazard(); + + /* Check whether we successfully enabled MMID support */ + config5 = read_c0_config5(); + if (config5 & MIPS_CONF5_MI) + c->options |= MIPS_CPU_MMID; + + /* + * Warn if we've hardcoded cpu_has_mmid to a value unsuitable + * for the CPU we're running on, or if CPUs in an SMP system + * have inconsistent MMID support. + */ + WARN_ON(!!cpu_has_mmid != !!(config5 & MIPS_CONF5_MI)); + + if (cpu_has_mmid) { + write_c0_memorymapid(~0ul); + back_to_back_c0_hazard(); + asid_mask = read_c0_memorymapid(); + + /* + * We maintain a bitmap to track MMID allocation, and + * need a sensible upper bound on the size of that + * bitmap. The initial CPU with MMID support (I6500) + * supports 16 bit MMIDs, which gives us an 8KiB + * bitmap. The architecture recommends that hardware + * support 32 bit MMIDs, which would give us a 512MiB + * bitmap - that's too big in most cases. + * + * Cap MMID width at 16 bits for now & we can revisit + * this if & when hardware supports anything wider. + */ + max_mmid_width = 16; + if (asid_mask > GENMASK(max_mmid_width - 1, 0)) { + pr_info("Capping MMID width at %d bits", + max_mmid_width); + asid_mask = GENMASK(max_mmid_width - 1, 0); + } + set_cpu_asid_mask(c, asid_mask); + } + } + return config5 & MIPS_CONF_M; } @@ -919,9 +786,12 @@ static void decode_configs(struct cpuinfo_mips *c) #ifndef CONFIG_MIPS_CPS if (cpu_has_mips_r2_r6) { - c->core = get_ebase_cpunum(); + unsigned int core; + + core = get_ebase_cpunum(); if (cpu_has_mipsmt) - c->core >>= fls(core_nvpes()) - 1; + core >>= fls(core_nvpes()) - 1; + cpu_set_core(c, core); } #endif } @@ -1246,46 +1116,6 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu) MIPS_CPU_LLSC; c->tlbsize = 48; break; - case PRID_IMP_VR41XX: - set_isa(c, MIPS_CPU_ISA_III); - c->fpu_msk31 |= FPU_CSR_CONDX; - c->options = R4K_OPTS; - c->tlbsize = 32; - switch (c->processor_id & 0xf0) { - case PRID_REV_VR4111: - c->cputype = CPU_VR4111; - __cpu_name[cpu] = "NEC VR4111"; - break; - case PRID_REV_VR4121: - c->cputype = CPU_VR4121; - __cpu_name[cpu] = "NEC VR4121"; - break; - case PRID_REV_VR4122: - if ((c->processor_id & 0xf) < 0x3) { - c->cputype = CPU_VR4122; - __cpu_name[cpu] = "NEC VR4122"; - } else { - c->cputype = CPU_VR4181A; - __cpu_name[cpu] = "NEC VR4181A"; - } - break; - case PRID_REV_VR4130: - if ((c->processor_id & 0xf) < 0x4) { - c->cputype = CPU_VR4131; - __cpu_name[cpu] = "NEC VR4131"; - } else { - c->cputype = CPU_VR4133; - c->options |= MIPS_CPU_LLSC; - __cpu_name[cpu] = "NEC VR4133"; - } - break; - default: - printk(KERN_INFO "Unexpected CPU of NEC VR4100 series\n"); - c->cputype = CPU_VR41XX; - __cpu_name[cpu] = "NEC Vr41xx"; - break; - } - break; case PRID_IMP_R4300: c->cputype = CPU_R4300; __cpu_name[cpu] = "R4300"; @@ -1310,7 +1140,7 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu) * This processor doesn't have an MMU, so it's not * "real easy" to run Linux on it. It is left purely * for documentation. Commented out because it shares - * it's c0_prid id number with the TX3900. + * its c0_prid id number with the TX3900. */ c->cputype = CPU_R4650; __cpu_name[cpu] = "R4650"; @@ -1320,29 +1150,6 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu) c->tlbsize = 48; break; #endif - case PRID_IMP_TX39: - c->fpu_msk31 |= FPU_CSR_CONDX | FPU_CSR_FS; - c->options = MIPS_CPU_TLB | MIPS_CPU_TX39_CACHE; - - if ((c->processor_id & 0xf0) == (PRID_REV_TX3927 & 0xf0)) { - c->cputype = CPU_TX3927; - __cpu_name[cpu] = "TX3927"; - c->tlbsize = 64; - } else { - switch (c->processor_id & PRID_REV_MASK) { - case PRID_REV_TX3912: - c->cputype = CPU_TX3912; - __cpu_name[cpu] = "TX3912"; - c->tlbsize = 32; - break; - case PRID_REV_TX3922: - c->cputype = CPU_TX3922; - __cpu_name[cpu] = "TX3922"; - c->tlbsize = 64; - break; - } - } - break; case PRID_IMP_R4700: c->cputype = CPU_R4700; __cpu_name[cpu] = "R4700"; @@ -1370,14 +1177,6 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu) MIPS_CPU_LLSC; c->tlbsize = 48; break; - case PRID_IMP_R5432: - c->cputype = CPU_R5432; - __cpu_name[cpu] = "R5432"; - set_isa(c, MIPS_CPU_ISA_IV); - c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR | - MIPS_CPU_WATCH | MIPS_CPU_LLSC; - c->tlbsize = 48; - break; case PRID_IMP_R5500: c->cputype = CPU_R5500; __cpu_name[cpu] = "R5500"; @@ -1394,24 +1193,6 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu) MIPS_CPU_DIVEC | MIPS_CPU_LLSC; c->tlbsize = 48; break; - case PRID_IMP_R6000: - c->cputype = CPU_R6000; - __cpu_name[cpu] = "R6000"; - set_isa(c, MIPS_CPU_ISA_II); - c->fpu_msk31 |= FPU_CSR_CONDX | FPU_CSR_FS; - c->options = MIPS_CPU_TLB | MIPS_CPU_FPU | - MIPS_CPU_LLSC; - c->tlbsize = 32; - break; - case PRID_IMP_R6000A: - c->cputype = CPU_R6000A; - __cpu_name[cpu] = "R6000A"; - set_isa(c, MIPS_CPU_ISA_II); - c->fpu_msk31 |= FPU_CSR_CONDX | FPU_CSR_FS; - c->options = MIPS_CPU_TLB | MIPS_CPU_FPU | - MIPS_CPU_LLSC; - c->tlbsize = 32; - break; case PRID_IMP_RM7000: c->cputype = CPU_RM7000; __cpu_name[cpu] = "RM7000"; @@ -1428,15 +1209,6 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu) */ c->tlbsize = (read_c0_info() & (1 << 29)) ? 64 : 48; break; - case PRID_IMP_R8000: - c->cputype = CPU_R8000; - __cpu_name[cpu] = "RM8000"; - set_isa(c, MIPS_CPU_ISA_IV); - c->options = MIPS_CPU_TLB | MIPS_CPU_4KEX | - MIPS_CPU_FPU | MIPS_CPU_32FPR | - MIPS_CPU_LLSC; - c->tlbsize = 384; /* has weird TLB: 3-way x 128 */ - break; case PRID_IMP_R10000: c->cputype = CPU_R10000; __cpu_name[cpu] = "R10000"; @@ -1454,8 +1226,9 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu) c->options = MIPS_CPU_TLB | MIPS_CPU_4K_CACHE | MIPS_CPU_4KEX | MIPS_CPU_FPU | MIPS_CPU_32FPR | MIPS_CPU_COUNTER | MIPS_CPU_WATCH | - MIPS_CPU_LLSC | MIPS_CPU_BP_GHIST; + MIPS_CPU_LLSC; c->tlbsize = 64; + write_c0_r10k_diag(read_c0_r10k_diag() | R10K_DIAG_E_GHIST); break; case PRID_IMP_R14000: if (((c->processor_id >> 4) & 0x0f) > 2) { @@ -1469,37 +1242,42 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu) c->options = MIPS_CPU_TLB | MIPS_CPU_4K_CACHE | MIPS_CPU_4KEX | MIPS_CPU_FPU | MIPS_CPU_32FPR | MIPS_CPU_COUNTER | MIPS_CPU_WATCH | - MIPS_CPU_LLSC | MIPS_CPU_BP_GHIST; + MIPS_CPU_LLSC; c->tlbsize = 64; + write_c0_r10k_diag(read_c0_r10k_diag() | R10K_DIAG_E_GHIST); break; - case PRID_IMP_LOONGSON_64: /* Loongson-2/3 */ + case PRID_IMP_LOONGSON_64C: /* Loongson-2/3 */ switch (c->processor_id & PRID_REV_MASK) { case PRID_REV_LOONGSON2E: - c->cputype = CPU_LOONGSON2; + c->cputype = CPU_LOONGSON2EF; __cpu_name[cpu] = "ICT Loongson-2"; set_elf_platform(cpu, "loongson2e"); set_isa(c, MIPS_CPU_ISA_III); c->fpu_msk31 |= FPU_CSR_CONDX; break; case PRID_REV_LOONGSON2F: - c->cputype = CPU_LOONGSON2; + c->cputype = CPU_LOONGSON2EF; __cpu_name[cpu] = "ICT Loongson-2"; set_elf_platform(cpu, "loongson2f"); set_isa(c, MIPS_CPU_ISA_III); c->fpu_msk31 |= FPU_CSR_CONDX; break; case PRID_REV_LOONGSON3A_R1: - c->cputype = CPU_LOONGSON3; + c->cputype = CPU_LOONGSON64; __cpu_name[cpu] = "ICT Loongson-3"; set_elf_platform(cpu, "loongson3a"); set_isa(c, MIPS_CPU_ISA_M64R1); + c->ases |= (MIPS_ASE_LOONGSON_MMI | MIPS_ASE_LOONGSON_CAM | + MIPS_ASE_LOONGSON_EXT); break; case PRID_REV_LOONGSON3B_R1: case PRID_REV_LOONGSON3B_R2: - c->cputype = CPU_LOONGSON3; + c->cputype = CPU_LOONGSON64; __cpu_name[cpu] = "ICT Loongson-3"; set_elf_platform(cpu, "loongson3b"); set_isa(c, MIPS_CPU_ISA_M64R1); + c->ases |= (MIPS_ASE_LOONGSON_MMI | MIPS_ASE_LOONGSON_CAM | + MIPS_ASE_LOONGSON_EXT); break; } @@ -1507,16 +1285,17 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu) MIPS_CPU_FPU | MIPS_CPU_LLSC | MIPS_CPU_32FPR; c->tlbsize = 64; + set_cpu_asid_mask(c, MIPS_ENTRYHI_ASID); c->writecombine = _CACHE_UNCACHED_ACCELERATED; break; - case PRID_IMP_LOONGSON_32: /* Loongson-1 */ + case PRID_IMP_LOONGSON_32: decode_configs(c); - c->cputype = CPU_LOONGSON1; + c->cputype = CPU_LOONGSON32; switch (c->processor_id & PRID_REV_MASK) { - case PRID_REV_LOONGSON1B: - __cpu_name[cpu] = "Loongson 1B"; + case PRID_REV_LOONGSON1: + __cpu_name[cpu] = "ICT Loongson-1"; break; } @@ -1584,6 +1363,7 @@ static inline void cpu_probe_mips(struct cpuinfo_mips *c, unsigned int cpu) c->cputype = CPU_34K; c->writecombine = _CACHE_UNCACHED; __cpu_name[cpu] = "MIPS 34Kc"; + cpu_set_mt_per_tc_perf(c); break; case PRID_IMP_74K: c->cputype = CPU_74K; @@ -1604,6 +1384,7 @@ static inline void cpu_probe_mips(struct cpuinfo_mips *c, unsigned int cpu) c->cputype = CPU_1004K; c->writecombine = _CACHE_UNCACHED; __cpu_name[cpu] = "MIPS 1004Kc"; + cpu_set_mt_per_tc_perf(c); break; case PRID_IMP_1074K: c->cputype = CPU_1074K; @@ -1613,10 +1394,12 @@ static inline void cpu_probe_mips(struct cpuinfo_mips *c, unsigned int cpu) case PRID_IMP_INTERAPTIV_UP: c->cputype = CPU_INTERAPTIV; __cpu_name[cpu] = "MIPS interAptiv"; + cpu_set_mt_per_tc_perf(c); break; case PRID_IMP_INTERAPTIV_MP: c->cputype = CPU_INTERAPTIV; __cpu_name[cpu] = "MIPS interAptiv (multi)"; + cpu_set_mt_per_tc_perf(c); break; case PRID_IMP_PROAPTIV_UP: c->cputype = CPU_PROAPTIV; @@ -1656,16 +1439,35 @@ static inline void cpu_probe_mips(struct cpuinfo_mips *c, unsigned int cpu) spram_config(); + mm_config(c); + switch (__get_cpu_type(c->cputype)) { + case CPU_M5150: + case CPU_P5600: + set_isa(c, MIPS_CPU_ISA_M32R5); + break; case CPU_I6500: c->options |= MIPS_CPU_SHARED_FTLB_ENTRIES; - /* fall-through */ + fallthrough; case CPU_I6400: c->options |= MIPS_CPU_SHARED_FTLB_RAM; - /* fall-through */ + fallthrough; default: break; } + + /* Recent MIPS cores use the implementation-dependent ExcCode 16 for + * cache/FTLB parity exceptions. + */ + switch (__get_cpu_type(c->cputype)) { + case CPU_PROAPTIV: + case CPU_P5600: + case CPU_P6600: + case CPU_I6400: + case CPU_I6500: + c->options |= MIPS_CPU_FTLBPAREX; + break; + } } static inline void cpu_probe_alchemy(struct cpuinfo_mips *c, unsigned int cpu) @@ -1701,6 +1503,10 @@ static inline void cpu_probe_alchemy(struct cpuinfo_mips *c, unsigned int cpu) break; } break; + case PRID_IMP_NETLOGIC_AU13XX: + c->cputype = CPU_ALCHEMY; + __cpu_name[cpu] = "Au1300"; + break; } } @@ -1765,6 +1571,7 @@ static inline void cpu_probe_broadcom(struct cpuinfo_mips *c, unsigned int cpu) c->cputype = CPU_BMIPS3300; __cpu_name[cpu] = "Broadcom BMIPS3300"; set_elf_platform(cpu, "bmips3300"); + reserve_exception_space(0x400, VECTORSPACING * 64); break; case PRID_IMP_BMIPS43XX: { int rev = c->processor_id & PRID_REV_MASK; @@ -1775,6 +1582,7 @@ static inline void cpu_probe_broadcom(struct cpuinfo_mips *c, unsigned int cpu) __cpu_name[cpu] = "Broadcom BMIPS4380"; set_elf_platform(cpu, "bmips4380"); c->options |= MIPS_CPU_RIXI; + reserve_exception_space(0x400, VECTORSPACING * 64); } else { c->cputype = CPU_BMIPS4350; __cpu_name[cpu] = "Broadcom BMIPS4350"; @@ -1791,6 +1599,7 @@ static inline void cpu_probe_broadcom(struct cpuinfo_mips *c, unsigned int cpu) __cpu_name[cpu] = "Broadcom BMIPS5000"; set_elf_platform(cpu, "bmips5000"); c->options |= MIPS_CPU_ULRI | MIPS_CPU_RIXI; + reserve_exception_space(0x1000, VECTORSPACING * 64); break; } } @@ -1798,6 +1607,8 @@ static inline void cpu_probe_broadcom(struct cpuinfo_mips *c, unsigned int cpu) static inline void cpu_probe_cavium(struct cpuinfo_mips *c, unsigned int cpu) { decode_configs(c); + /* Octeon has different cache interface */ + c->options &= ~MIPS_CPU_4K_CACHE; switch (c->processor_id & PRID_IMP_MASK) { case PRID_IMP_CAVIUM_CN38XX: case PRID_IMP_CAVIUM_CN31XX: @@ -1838,132 +1649,186 @@ platform: } } +#ifdef CONFIG_CPU_LOONGSON64 +#include <loongson_regs.h> + +static inline void decode_cpucfg(struct cpuinfo_mips *c) +{ + u32 cfg1 = read_cpucfg(LOONGSON_CFG1); + u32 cfg2 = read_cpucfg(LOONGSON_CFG2); + u32 cfg3 = read_cpucfg(LOONGSON_CFG3); + + if (cfg1 & LOONGSON_CFG1_MMI) + c->ases |= MIPS_ASE_LOONGSON_MMI; + + if (cfg2 & LOONGSON_CFG2_LEXT1) + c->ases |= MIPS_ASE_LOONGSON_EXT; + + if (cfg2 & LOONGSON_CFG2_LEXT2) + c->ases |= MIPS_ASE_LOONGSON_EXT2; + + if (cfg2 & LOONGSON_CFG2_LSPW) { + c->options |= MIPS_CPU_LDPTE; + c->guest.options |= MIPS_CPU_LDPTE; + } + + if (cfg3 & LOONGSON_CFG3_LCAMP) + c->ases |= MIPS_ASE_LOONGSON_CAM; +} + static inline void cpu_probe_loongson(struct cpuinfo_mips *c, unsigned int cpu) { + c->cputype = CPU_LOONGSON64; + + /* All Loongson processors covered here define ExcCode 16 as GSExc. */ + decode_configs(c); + c->options |= MIPS_CPU_GSEXCEX; + switch (c->processor_id & PRID_IMP_MASK) { - case PRID_IMP_LOONGSON_64: /* Loongson-2/3 */ + case PRID_IMP_LOONGSON_64R: /* Loongson-64 Reduced */ switch (c->processor_id & PRID_REV_MASK) { - case PRID_REV_LOONGSON3A_R2: - c->cputype = CPU_LOONGSON3; + case PRID_REV_LOONGSON2K_R1_0: + case PRID_REV_LOONGSON2K_R1_1: + case PRID_REV_LOONGSON2K_R1_2: + case PRID_REV_LOONGSON2K_R1_3: + __cpu_name[cpu] = "Loongson-2K"; + set_elf_platform(cpu, "gs264e"); + set_isa(c, MIPS_CPU_ISA_M64R2); + break; + } + c->ases |= (MIPS_ASE_LOONGSON_MMI | MIPS_ASE_LOONGSON_EXT | + MIPS_ASE_LOONGSON_EXT2); + break; + case PRID_IMP_LOONGSON_64C: /* Loongson-3 Classic */ + switch (c->processor_id & PRID_REV_MASK) { + case PRID_REV_LOONGSON3A_R2_0: + case PRID_REV_LOONGSON3A_R2_1: __cpu_name[cpu] = "ICT Loongson-3"; set_elf_platform(cpu, "loongson3a"); set_isa(c, MIPS_CPU_ISA_M64R2); break; - case PRID_REV_LOONGSON3A_R3: - c->cputype = CPU_LOONGSON3; + case PRID_REV_LOONGSON3A_R3_0: + case PRID_REV_LOONGSON3A_R3_1: __cpu_name[cpu] = "ICT Loongson-3"; set_elf_platform(cpu, "loongson3a"); set_isa(c, MIPS_CPU_ISA_M64R2); break; } - - decode_configs(c); + /* + * Loongson-3 Classic did not implement MIPS standard TLBINV + * but implemented TLBINVF and EHINV. As currently we're only + * using these two features, enable MIPS_CPU_TLBINV as well. + * + * Also some early Loongson-3A2000 had wrong TLB type in Config + * register, we correct it here. + */ c->options |= MIPS_CPU_FTLB | MIPS_CPU_TLBINV | MIPS_CPU_LDPTE; - c->writecombine = _CACHE_UNCACHED_ACCELERATED; + c->ases |= (MIPS_ASE_LOONGSON_MMI | MIPS_ASE_LOONGSON_CAM | + MIPS_ASE_LOONGSON_EXT | MIPS_ASE_LOONGSON_EXT2); + c->ases &= ~MIPS_ASE_VZ; /* VZ of Loongson-3A2000/3000 is incomplete */ + change_c0_config6(LOONGSON_CONF6_EXTIMER | LOONGSON_CONF6_INTIMER, + LOONGSON_CONF6_INTIMER); + break; + case PRID_IMP_LOONGSON_64G: + __cpu_name[cpu] = "ICT Loongson-3"; + set_elf_platform(cpu, "loongson3a"); + set_isa(c, MIPS_CPU_ISA_M64R2); + decode_cpucfg(c); + change_c0_config6(LOONGSON_CONF6_EXTIMER | LOONGSON_CONF6_INTIMER, + LOONGSON_CONF6_INTIMER); break; default: panic("Unknown Loongson Processor ID!"); break; } } +#else +static inline void cpu_probe_loongson(struct cpuinfo_mips *c, unsigned int cpu) { } +#endif static inline void cpu_probe_ingenic(struct cpuinfo_mips *c, unsigned int cpu) { decode_configs(c); - /* JZRISC does not implement the CP0 counter. */ + + /* + * XBurst misses a config2 register, so config3 decode was skipped in + * decode_configs(). + */ + decode_config3(c); + + /* XBurst does not implement the CP0 counter. */ c->options &= ~MIPS_CPU_COUNTER; - BUG_ON(!__builtin_constant_p(cpu_has_counter) || cpu_has_counter); + BUG_ON(__builtin_constant_p(cpu_has_counter) && cpu_has_counter); + + /* XBurst has virtually tagged icache */ + c->icache.flags |= MIPS_CACHE_VTAG; + switch (c->processor_id & PRID_IMP_MASK) { - case PRID_IMP_JZRISC: - c->cputype = CPU_JZRISC; - c->writecombine = _CACHE_UNCACHED_ACCELERATED; - __cpu_name[cpu] = "Ingenic JZRISC"; - break; - default: - panic("Unknown Ingenic Processor ID!"); - break; - } -} -static inline void cpu_probe_netlogic(struct cpuinfo_mips *c, int cpu) -{ - decode_configs(c); + /* XBurst®1 with MXU1.0/MXU1.1 SIMD ISA */ + case PRID_IMP_XBURST_REV1: - if ((c->processor_id & PRID_IMP_MASK) == PRID_IMP_NETLOGIC_AU13XX) { - c->cputype = CPU_ALCHEMY; - __cpu_name[cpu] = "Au1300"; - /* following stuff is not for Alchemy */ - return; - } + /* + * The XBurst core by default attempts to avoid branch target + * buffer lookups by detecting & special casing loops. This + * feature will cause BogoMIPS and lpj calculate in error. + * Set cp0 config7 bit 4 to disable this feature. + */ + set_c0_config7(MIPS_CONF7_BTB_LOOP_EN); - c->options = (MIPS_CPU_TLB | - MIPS_CPU_4KEX | - MIPS_CPU_COUNTER | - MIPS_CPU_DIVEC | - MIPS_CPU_WATCH | - MIPS_CPU_EJTAG | - MIPS_CPU_LLSC); + switch (c->processor_id & PRID_COMP_MASK) { - switch (c->processor_id & PRID_IMP_MASK) { - case PRID_IMP_NETLOGIC_XLP2XX: - case PRID_IMP_NETLOGIC_XLP9XX: - case PRID_IMP_NETLOGIC_XLP5XX: - c->cputype = CPU_XLP; - __cpu_name[cpu] = "Broadcom XLPII"; - break; - - case PRID_IMP_NETLOGIC_XLP8XX: - case PRID_IMP_NETLOGIC_XLP3XX: - c->cputype = CPU_XLP; - __cpu_name[cpu] = "Netlogic XLP"; - break; - - case PRID_IMP_NETLOGIC_XLR732: - case PRID_IMP_NETLOGIC_XLR716: - case PRID_IMP_NETLOGIC_XLR532: - case PRID_IMP_NETLOGIC_XLR308: - case PRID_IMP_NETLOGIC_XLR532C: - case PRID_IMP_NETLOGIC_XLR516C: - case PRID_IMP_NETLOGIC_XLR508C: - case PRID_IMP_NETLOGIC_XLR308C: - c->cputype = CPU_XLR; - __cpu_name[cpu] = "Netlogic XLR"; - break; - - case PRID_IMP_NETLOGIC_XLS608: - case PRID_IMP_NETLOGIC_XLS408: - case PRID_IMP_NETLOGIC_XLS404: - case PRID_IMP_NETLOGIC_XLS208: - case PRID_IMP_NETLOGIC_XLS204: - case PRID_IMP_NETLOGIC_XLS108: - case PRID_IMP_NETLOGIC_XLS104: - case PRID_IMP_NETLOGIC_XLS616B: - case PRID_IMP_NETLOGIC_XLS608B: - case PRID_IMP_NETLOGIC_XLS416B: - case PRID_IMP_NETLOGIC_XLS412B: - case PRID_IMP_NETLOGIC_XLS408B: - case PRID_IMP_NETLOGIC_XLS404B: - c->cputype = CPU_XLR; - __cpu_name[cpu] = "Netlogic XLS"; + /* + * The config0 register in the XBurst CPUs with a processor ID of + * PRID_COMP_INGENIC_D0 report themselves as MIPS32r2 compatible, + * but they don't actually support this ISA. + */ + case PRID_COMP_INGENIC_D0: + c->isa_level &= ~MIPS_CPU_ISA_M32R2; + + /* FPU is not properly detected on JZ4760(B). */ + if (c->processor_id == 0x2ed0024f) + c->options |= MIPS_CPU_FPU; + + fallthrough; + + /* + * The config0 register in the XBurst CPUs with a processor ID of + * PRID_COMP_INGENIC_D0 or PRID_COMP_INGENIC_D1 has an abandoned + * huge page tlb mode, this mode is not compatible with the MIPS + * standard, it will cause tlbmiss and into an infinite loop + * (line 21 in the tlb-funcs.S) when starting the init process. + * After chip reset, the default is HPTLB mode, Write 0xa9000000 + * to cp0 register 5 sel 4 to switch back to VTLB mode to prevent + * getting stuck. + */ + case PRID_COMP_INGENIC_D1: + write_c0_page_ctrl(XBURST_PAGECTRL_HPTLB_DIS); + break; + + default: + break; + } + fallthrough; + + /* XBurst®1 with MXU2.0 SIMD ISA */ + case PRID_IMP_XBURST_REV2: + /* Ingenic uses the WA bit to achieve write-combine memory writes */ + c->writecombine = _CACHE_CACHABLE_WA; + c->cputype = CPU_XBURST; + __cpu_name[cpu] = "Ingenic XBurst"; break; - default: - pr_info("Unknown Netlogic chip id [%02x]!\n", - c->processor_id); - c->cputype = CPU_XLR; + /* XBurst®2 with MXU2.1 SIMD ISA */ + case PRID_IMP_XBURST2: + c->cputype = CPU_XBURST; + __cpu_name[cpu] = "Ingenic XBurst II"; break; - } - if (c->cputype == CPU_XLP) { - set_isa(c, MIPS_CPU_ISA_M64R2); - c->options |= (MIPS_CPU_FPU | MIPS_CPU_ULRI | MIPS_CPU_MCHECK); - /* This will be updated again after all threads are woken up */ - c->tlbsize = ((read_c0_config6() >> 16) & 0xffff) + 1; - } else { - set_isa(c, MIPS_CPU_ISA_M64R1); - c->tlbsize = ((read_c0_config1() >> 25) & 0x3f) + 1; + default: + panic("Unknown Ingenic Processor ID!"); + break; } - c->kscratch_mask = 0xf; } #ifdef CONFIG_64BIT @@ -1974,6 +1839,7 @@ EXPORT_SYMBOL(__ua_limit); const char *__cpu_name[NR_CPUS]; const char *__elf_platform; +const char *__elf_base_platform; void cpu_probe(void) { @@ -2003,6 +1869,7 @@ void cpu_probe(void) cpu_probe_mips(c, cpu); break; case PRID_COMP_ALCHEMY: + case PRID_COMP_NETLOGIC: cpu_probe_alchemy(c, cpu); break; case PRID_COMP_SIBYTE: @@ -2023,14 +1890,12 @@ void cpu_probe(void) case PRID_COMP_LOONGSON: cpu_probe_loongson(c, cpu); break; + case PRID_COMP_INGENIC_13: case PRID_COMP_INGENIC_D0: case PRID_COMP_INGENIC_D1: case PRID_COMP_INGENIC_E1: cpu_probe_ingenic(c, cpu); break; - case PRID_COMP_NETLOGIC: - cpu_probe_netlogic(c, cpu); - break; } BUG_ON(!__cpu_name[cpu]); @@ -2069,10 +1934,6 @@ void cpu_probe(void) else cpu_set_nofpu_opts(c); - if (cpu_has_bp_ghist) - write_c0_r10k_diag(read_c0_r10k_diag() | - R10K_DIAG_E_GHIST); - if (cpu_has_mips_r2_r6) { c->srsets = ((read_c0_srsctl() >> 26) & 0x0f) + 1; /* R2 has Performance Counter Interrupt indicator */ @@ -2091,15 +1952,57 @@ void cpu_probe(void) elf_hwcap |= HWCAP_MIPS_MSA; } + if (cpu_has_mips16) + elf_hwcap |= HWCAP_MIPS_MIPS16; + + if (cpu_has_mdmx) + elf_hwcap |= HWCAP_MIPS_MDMX; + + if (cpu_has_mips3d) + elf_hwcap |= HWCAP_MIPS_MIPS3D; + + if (cpu_has_smartmips) + elf_hwcap |= HWCAP_MIPS_SMARTMIPS; + + if (cpu_has_dsp) + elf_hwcap |= HWCAP_MIPS_DSP; + + if (cpu_has_dsp2) + elf_hwcap |= HWCAP_MIPS_DSP2; + + if (cpu_has_dsp3) + elf_hwcap |= HWCAP_MIPS_DSP3; + + if (cpu_has_mips16e2) + elf_hwcap |= HWCAP_MIPS_MIPS16E2; + + if (cpu_has_loongson_mmi) + elf_hwcap |= HWCAP_LOONGSON_MMI; + + if (cpu_has_loongson_ext) + elf_hwcap |= HWCAP_LOONGSON_EXT; + + if (cpu_has_loongson_ext2) + elf_hwcap |= HWCAP_LOONGSON_EXT2; + if (cpu_has_vz) cpu_probe_vz(c); cpu_probe_vmbits(c); + /* Synthesize CPUCFG data if running on Loongson processors; + * no-op otherwise. + * + * This looks at previously probed features, so keep this at bottom. + */ + loongson3_cpucfg_synthesize_data(c); + #ifdef CONFIG_64BIT if (cpu == 0) __ua_limit = ~((1ull << cpu_vmbits) - 1); #endif + + reserve_exception_space(0, 0x1000); } void cpu_report(void) @@ -2113,3 +2016,71 @@ void cpu_report(void) if (cpu_has_msa) pr_info("MSA revision is: %08x\n", c->msa_id); } + +void cpu_set_cluster(struct cpuinfo_mips *cpuinfo, unsigned int cluster) +{ + /* Ensure the core number fits in the field */ + WARN_ON(cluster > (MIPS_GLOBALNUMBER_CLUSTER >> + MIPS_GLOBALNUMBER_CLUSTER_SHF)); + + cpuinfo->globalnumber &= ~MIPS_GLOBALNUMBER_CLUSTER; + cpuinfo->globalnumber |= cluster << MIPS_GLOBALNUMBER_CLUSTER_SHF; +} + +void cpu_set_core(struct cpuinfo_mips *cpuinfo, unsigned int core) +{ + /* Ensure the core number fits in the field */ + WARN_ON(core > (MIPS_GLOBALNUMBER_CORE >> MIPS_GLOBALNUMBER_CORE_SHF)); + + cpuinfo->globalnumber &= ~MIPS_GLOBALNUMBER_CORE; + cpuinfo->globalnumber |= core << MIPS_GLOBALNUMBER_CORE_SHF; +} + +void cpu_set_vpe_id(struct cpuinfo_mips *cpuinfo, unsigned int vpe) +{ + /* Ensure the VP(E) ID fits in the field */ + WARN_ON(vpe > (MIPS_GLOBALNUMBER_VP >> MIPS_GLOBALNUMBER_VP_SHF)); + + /* Ensure we're not using VP(E)s without support */ + WARN_ON(vpe && !IS_ENABLED(CONFIG_MIPS_MT_SMP) && + !IS_ENABLED(CONFIG_CPU_MIPSR6)); + + cpuinfo->globalnumber &= ~MIPS_GLOBALNUMBER_VP; + cpuinfo->globalnumber |= vpe << MIPS_GLOBALNUMBER_VP_SHF; +} + +void cpu_disable_mmid(void) +{ + int i; + unsigned long asid_mask; + unsigned int cpu = smp_processor_id(); + struct cpuinfo_mips *c = ¤t_cpu_data; + unsigned int config4 = read_c0_config4(); + unsigned int config5 = read_c0_config5(); + + /* Setup the initial ASID mask based on config4 */ + asid_mask = MIPS_ENTRYHI_ASID; + if (config4 & MIPS_CONF4_AE) + asid_mask |= MIPS_ENTRYHI_ASIDX; + set_cpu_asid_mask(c, asid_mask); + + /* Disable MMID in the C0 and update cpuinfo_mips accordingly */ + config5 &= ~(MIPS_CONF5_UFR | MIPS_CONF5_UFE); + config5 &= ~MIPS_CONF5_MI; + write_c0_config5(config5); + /* Ensure the write to config5 above takes effect */ + back_to_back_c0_hazard(); + c->options &= ~MIPS_CPU_MMID; + + /* Setup asid cache value cleared in per_cpu_trap_init() */ + cpu_data[cpu].asid_cache = asid_first_version(cpu); + + /* Reinit context for each CPU */ + for_each_possible_cpu(i) + set_cpu_context(i, &init_mm, 0); + + /* Ensure that now MMID will be seen as disable */ + mmid_disabled_quirk = true; + + pr_info("MMID support disabled due to hardware support issue\n"); +} |
