// SPDX-License-Identifier: GPL-2.0-or-later/* * Processor capabilities determination functions. * * Copyright (C) xxxx the Anonymous * Copyright (C) 1994 - 2006 Ralf Baechle * Copyright (C) 2003, 2004 Maciej W. Rozycki * Copyright (C) 2001, 2004, 2011, 2012 MIPS Technologies, Inc. */#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>#include <linux/export.h> #include <asm/bugs.h>#include <asm/cpu.h>#include <asm/cpu-features.h>#include <asm/cpu-type.h>#include <asm/fpu.h>#include <asm/mipsregs.h>#include <asm/mipsmtregs.h>#include <asm/msa.h>#include <asm/watch.h>#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); static bool mmid_disabled_quirk; static inline unsigned long cpu_get_msa_id(void){ unsigned long status, msa_id; status = read_c0_status(); __enable_fpu(FPU_64BIT); enable_msa(); msa_id = read_msa_ir(); disable_msa(); write_c0_status(status); return msa_id;} static int mips_dsp_disabled; static int __init dsp_disable(char *s){ cpu_data[0].ases &= ~(MIPS_ASE_DSP | MIPS_ASE_DSP2P); mips_dsp_disabled = 1; return 1;} __setup("nodsp", dsp_disable); static int mips_htw_disabled; static int __init htw_disable(char *s){ mips_htw_disabled = 1; cpu_data[0].options &= ~MIPS_CPU_HTW; write_c0_pwctl(read_c0_pwctl() & ~(1 << MIPS_PWCTL_PWEN_SHIFT)); return 1;} __setup("nohtw", htw_disable); static int mips_ftlb_disabled;static int mips_has_ftlb_configured; enum ftlb_flags { FTLB_EN = 1 << 0, FTLB_SET_PROB = 1 << 1,}; static int set_ftlb_enable(struct cpuinfo_mips *c, enum ftlb_flags flags); static int __init ftlb_disable(char *s){ unsigned int config4, mmuextdef; /* * If the core hasn't done any FTLB configuration, there is nothing * for us to do here. */ if (!mips_has_ftlb_configured) return 1; /* Disable it in the boot cpu */ if (set_ftlb_enable(&cpu_data[0], 0)) { pr_warn("Can't turn FTLB off\n"); return 1; } config4 = read_c0_config4(); /* Check that FTLB has been disabled */ mmuextdef = config4 & MIPS_CONF4_MMUEXTDEF; /* MMUSIZEEXT == VTLB ON, FTLB OFF */ if (mmuextdef == MIPS_CONF4_MMUEXTDEF_FTLBSIZEEXT) { /* This should never happen */ pr_warn("FTLB could not be disabled!\n"); return 1; } mips_ftlb_disabled = 1; mips_has_ftlb_configured = 0; /* * noftlb is mainly used for debug purposes so print * an informative message instead of using pr_debug() */ pr_info("FTLB has been disabled\n"); /* * Some of these bits are duplicated in the decode_config4. * MIPS_CONF4_MMUEXTDEF_MMUSIZEEXT is the only possible case * once FTLB has been disabled so undo what decode_config4 did. */ cpu_data[0].tlbsize -= cpu_data[0].tlbsizeftlbways * cpu_data[0].tlbsizeftlbsets; cpu_data[0].tlbsizeftlbsets = 0; cpu_data[0].tlbsizeftlbways = 0; return 1;} __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){ struct cpuinfo_mips *c = ¤t_cpu_data; switch (current_cpu_type()) { case CPU_34K: /* * Erratum "RPS May Cause Incorrect Instruction Execution" * This code only handles VPE0, any SMP/RTOS code * 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); break; default: break; }} void __init check_bugs32(void){ check_errata();} /* * Probe whether cpu has config register by trying to play with * alternate cache bit and see whether it matters. * It's used by cpu_probe to distinguish between R3000A and R3081. */static inline int cpu_has_confreg(void){#ifdef CONFIG_CPU_R3000 unsigned long size1, size2; unsigned long cfg = read_c0_conf(); size1 = r3k_cache_size(ST0_ISC); write_c0_conf(cfg ^ R30XX_CONF_AC); size2 = r3k_cache_size(ST0_ISC); write_c0_conf(cfg); return size1 != size2;#else return 0;#endif} static inline void set_elf_platform(int cpu, const char *plat){ if (cpu == 0) __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){ int vmbits = 31; if (cpu_has_64bits) { write_c0_entryhi_64(0x3fffffffffffe000ULL); back_to_back_c0_hazard(); vmbits = fls64(read_c0_entryhi_64() & 0x3fffffffffffe000ULL); } c->vmbits = vmbits;} 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; }} static char unknown_isa[] = KERN_ERR \ "Unsupported ISA type, c0.config0: %d."; static unsigned int calculate_ftlb_probability(struct cpuinfo_mips *c){ unsigned int probability = c->tlbsize / c->tlbsizevtlb; /* * 0 = All TLBWR instructions go to FTLB * 1 = 15:1: For every 16 TBLWR instructions, 15 go to the * FTLB and 1 goes to the VTLB. * 2 = 7:1: As above with 7:1 ratio. * 3 = 3:1: As above with 3:1 ratio. * * Use the linear midpoint as the probability threshold. */ if (probability >= 12) return 1; else if (probability >= 6) return 2; else /* * So FTLB is less than 4 times bigger than VTLB. * A 3:1 ratio can still be useful though. */ return 3;} static int set_ftlb_enable(struct cpuinfo_mips *c, enum ftlb_flags flags){ unsigned int config; /* It's implementation dependent how the FTLB can be enabled */ switch (c->cputype) { case CPU_PROAPTIV: case CPU_P5600: case CPU_P6600: /* proAptiv & related cores use Config6 to enable the FTLB */ config = read_c0_config6(); if (flags & FTLB_EN) config |= MTI_CONF6_FTLBEN; else config &= ~MTI_CONF6_FTLBEN; if (flags & FTLB_SET_PROB) { config &= ~(3 << MTI_CONF6_FTLBP_SHIFT); config |= calculate_ftlb_probability(c) << MTI_CONF6_FTLBP_SHIFT; } write_c0_config6(config); back_to_back_c0_hazard(); break; case CPU_I6400: case CPU_I6500: /* There's no way to disable the FTLB */ if (!(flags & FTLB_EN)) return 1; return 0; case CPU_LOONGSON64: /* Flush ITLB, DTLB, VTLB and FTLB */ write_c0_diag(LOONGSON_DIAG_ITLB | LOONGSON_DIAG_DTLB | LOONGSON_DIAG_VTLB | LOONGSON_DIAG_FTLB); /* Loongson-3 cores use Config6 to enable the FTLB */ config = read_c0_config6(); if (flags & FTLB_EN) /* Enable FTLB */ write_c0_config6(config & ~LOONGSON_CONF6_FTLBDIS); else /* Disable FTLB */ write_c0_config6(config | LOONGSON_CONF6_FTLBDIS); break; default: return 1; } 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; int isa, mt; config0 = read_c0_config(); /* * Look for Standard TLB or Dual VTLB and FTLB */ mt = config0 & MIPS_CONF_MT; if (mt == MIPS_CONF_MT_TLB) c->options |= MIPS_CPU_TLB; else if (mt == MIPS_CONF_MT_FTLB) c->options |= MIPS_CPU_TLB | MIPS_CPU_FTLB; isa = (config0 & MIPS_CONF_AT) >> 13; switch (isa) { case 0: switch ((config0 & MIPS_CONF_AR) >> 10) { case 0: set_isa(c, MIPS_CPU_ISA_M32R1); break; case 1: set_isa(c, MIPS_CPU_ISA_M32R2); break; case 2: set_isa(c, MIPS_CPU_ISA_M32R6); break; default: goto unknown; } break; case 2: switch ((config0 & MIPS_CONF_AR) >> 10) { case 0: set_isa(c, MIPS_CPU_ISA_M64R1); break; case 1: set_isa(c, MIPS_CPU_ISA_M64R2); break; case 2: set_isa(c, MIPS_CPU_ISA_M64R6); break; default: goto unknown; } break; default: goto unknown; } return config0 & MIPS_CONF_M; unknown: panic(unknown_isa, config0);} static inline unsigned int decode_config1(struct cpuinfo_mips *c){ unsigned int config1; config1 = read_c0_config1(); if (config1 & MIPS_CONF1_MD) c->ases |= MIPS_ASE_MDMX; if (config1 & MIPS_CONF1_PC) c->options |= MIPS_CPU_PERF; if (config1 & MIPS_CONF1_WR) c->options |= MIPS_CPU_WATCH; if (config1 & MIPS_CONF1_CA) c->ases |= MIPS_ASE_MIPS16; if (config1 & MIPS_CONF1_EP) c->options |= MIPS_CPU_EJTAG; if (config1 & MIPS_CONF1_FP) { c->options |= MIPS_CPU_FPU; c->options |= MIPS_CPU_32FPR; } if (cpu_has_tlb) { c->tlbsize = ((config1 & MIPS_CONF1_TLBS) >> 25) + 1; c->tlbsizevtlb = c->tlbsize; c->tlbsizeftlbsets = 0; } return config1 & MIPS_CONF_M;} static inline unsigned int decode_config2(struct cpuinfo_mips *c){ unsigned int config2; config2 = read_c0_config2(); if (config2 & MIPS_CONF2_SL)Lines 1–500 of 2089. Load more
// SPDX-License-Identifier: GPL-2.0-or-later /* * Processor capabilities determination functions. * * Copyright (C) xxxx the Anonymous * Copyright (C) 1994 - 2006 Ralf Baechle * Copyright (C) 2003, 2004 Maciej W. Rozycki * Copyright (C) 2001, 2004, 2011, 2012 MIPS Technologies, Inc. */ #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> #include <linux/export.h> #include <asm/bugs.h> #include <asm/cpu.h> #include <asm/cpu-features.h> #include <asm/cpu-type.h> #include <asm/fpu.h> #include <asm/mipsregs.h> #include <asm/mipsmtregs.h> #include <asm/msa.h> #include <asm/watch.h> #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); static bool mmid_disabled_quirk; static inline unsigned long cpu_get_msa_id(void) { unsigned long status, msa_id; status = read_c0_status(); __enable_fpu(FPU_64BIT); enable_msa(); msa_id = read_msa_ir(); disable_msa(); write_c0_status(status); return msa_id; } static int mips_dsp_disabled; static int __init dsp_disable(char *s) { cpu_data[0].ases &= ~(MIPS_ASE_DSP | MIPS_ASE_DSP2P); mips_dsp_disabled = 1; return 1; } __setup("nodsp", dsp_disable); static int mips_htw_disabled; static int __init htw_disable(char *s) { mips_htw_disabled = 1; cpu_data[0].options &= ~MIPS_CPU_HTW; write_c0_pwctl(read_c0_pwctl() & ~(1 << MIPS_PWCTL_PWEN_SHIFT)); return 1; } __setup("nohtw", htw_disable); static int mips_ftlb_disabled; static int mips_has_ftlb_configured; enum ftlb_flags { FTLB_EN = 1 << 0, FTLB_SET_PROB = 1 << 1, }; static int set_ftlb_enable(struct cpuinfo_mips *c, enum ftlb_flags flags); static int __init ftlb_disable(char *s) { unsigned int config4, mmuextdef; /* * If the core hasn't done any FTLB configuration, there is nothing * for us to do here. */ if (!mips_has_ftlb_configured) return 1; /* Disable it in the boot cpu */ if (set_ftlb_enable(&cpu_data[0], 0)) { pr_warn("Can't turn FTLB off\n"); return 1; } config4 = read_c0_config4(); /* Check that FTLB has been disabled */ mmuextdef = config4 & MIPS_CONF4_MMUEXTDEF; /* MMUSIZEEXT == VTLB ON, FTLB OFF */ if (mmuextdef == MIPS_CONF4_MMUEXTDEF_FTLBSIZEEXT) { /* This should never happen */ pr_warn("FTLB could not be disabled!\n"); return 1; } mips_ftlb_disabled = 1; mips_has_ftlb_configured = 0; /* * noftlb is mainly used for debug purposes so print * an informative message instead of using pr_debug() */ pr_info("FTLB has been disabled\n"); /* * Some of these bits are duplicated in the decode_config4. * MIPS_CONF4_MMUEXTDEF_MMUSIZEEXT is the only possible case * once FTLB has been disabled so undo what decode_config4 did. */ cpu_data[0].tlbsize -= cpu_data[0].tlbsizeftlbways * cpu_data[0].tlbsizeftlbsets; cpu_data[0].tlbsizeftlbsets = 0; cpu_data[0].tlbsizeftlbways = 0; return 1; } __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) { struct cpuinfo_mips *c = ¤t_cpu_data; switch (current_cpu_type()) { case CPU_34K: /* * Erratum "RPS May Cause Incorrect Instruction Execution" * This code only handles VPE0, any SMP/RTOS code * 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); break; default: break; } } void __init check_bugs32(void) { check_errata(); } /* * Probe whether cpu has config register by trying to play with * alternate cache bit and see whether it matters. * It's used by cpu_probe to distinguish between R3000A and R3081. */ static inline int cpu_has_confreg(void) { #ifdef CONFIG_CPU_R3000 unsigned long size1, size2; unsigned long cfg = read_c0_conf(); size1 = r3k_cache_size(ST0_ISC); write_c0_conf(cfg ^ R30XX_CONF_AC); size2 = r3k_cache_size(ST0_ISC); write_c0_conf(cfg); return size1 != size2; #else return 0; #endif } static inline void set_elf_platform(int cpu, const char *plat) { if (cpu == 0) __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) { int vmbits = 31; if (cpu_has_64bits) { write_c0_entryhi_64(0x3fffffffffffe000ULL); back_to_back_c0_hazard(); vmbits = fls64(read_c0_entryhi_64() & 0x3fffffffffffe000ULL); } c->vmbits = vmbits; } 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; } } static char unknown_isa[] = KERN_ERR \ "Unsupported ISA type, c0.config0: %d."; static unsigned int calculate_ftlb_probability(struct cpuinfo_mips *c) { unsigned int probability = c->tlbsize / c->tlbsizevtlb; /* * 0 = All TLBWR instructions go to FTLB * 1 = 15:1: For every 16 TBLWR instructions, 15 go to the * FTLB and 1 goes to the VTLB. * 2 = 7:1: As above with 7:1 ratio. * 3 = 3:1: As above with 3:1 ratio. * * Use the linear midpoint as the probability threshold. */ if (probability >= 12) return 1; else if (probability >= 6) return 2; else /* * So FTLB is less than 4 times bigger than VTLB. * A 3:1 ratio can still be useful though. */ return 3; } static int set_ftlb_enable(struct cpuinfo_mips *c, enum ftlb_flags flags) { unsigned int config; /* It's implementation dependent how the FTLB can be enabled */ switch (c->cputype) { case CPU_PROAPTIV: case CPU_P5600: case CPU_P6600: /* proAptiv & related cores use Config6 to enable the FTLB */ config = read_c0_config6(); if (flags & FTLB_EN) config |= MTI_CONF6_FTLBEN; else config &= ~MTI_CONF6_FTLBEN; if (flags & FTLB_SET_PROB) { config &= ~(3 << MTI_CONF6_FTLBP_SHIFT); config |= calculate_ftlb_probability(c) << MTI_CONF6_FTLBP_SHIFT; } write_c0_config6(config); back_to_back_c0_hazard(); break; case CPU_I6400: case CPU_I6500: /* There's no way to disable the FTLB */ if (!(flags & FTLB_EN)) return 1; return 0; case CPU_LOONGSON64: /* Flush ITLB, DTLB, VTLB and FTLB */ write_c0_diag(LOONGSON_DIAG_ITLB | LOONGSON_DIAG_DTLB | LOONGSON_DIAG_VTLB | LOONGSON_DIAG_FTLB); /* Loongson-3 cores use Config6 to enable the FTLB */ config = read_c0_config6(); if (flags & FTLB_EN) /* Enable FTLB */ write_c0_config6(config & ~LOONGSON_CONF6_FTLBDIS); else /* Disable FTLB */ write_c0_config6(config | LOONGSON_CONF6_FTLBDIS); break; default: return 1; } 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; int isa, mt; config0 = read_c0_config(); /* * Look for Standard TLB or Dual VTLB and FTLB */ mt = config0 & MIPS_CONF_MT; if (mt == MIPS_CONF_MT_TLB) c->options |= MIPS_CPU_TLB; else if (mt == MIPS_CONF_MT_FTLB) c->options |= MIPS_CPU_TLB | MIPS_CPU_FTLB; isa = (config0 & MIPS_CONF_AT) >> 13; switch (isa) { case 0: switch ((config0 & MIPS_CONF_AR) >> 10) { case 0: set_isa(c, MIPS_CPU_ISA_M32R1); break; case 1: set_isa(c, MIPS_CPU_ISA_M32R2); break; case 2: set_isa(c, MIPS_CPU_ISA_M32R6); break; default: goto unknown; } break; case 2: switch ((config0 & MIPS_CONF_AR) >> 10) { case 0: set_isa(c, MIPS_CPU_ISA_M64R1); break; case 1: set_isa(c, MIPS_CPU_ISA_M64R2); break; case 2: set_isa(c, MIPS_CPU_ISA_M64R6); break; default: goto unknown; } break; default: goto unknown; } return config0 & MIPS_CONF_M; unknown: panic(unknown_isa, config0); } static inline unsigned int decode_config1(struct cpuinfo_mips *c) { unsigned int config1; config1 = read_c0_config1(); if (config1 & MIPS_CONF1_MD) c->ases |= MIPS_ASE_MDMX; if (config1 & MIPS_CONF1_PC) c->options |= MIPS_CPU_PERF; if (config1 & MIPS_CONF1_WR) c->options |= MIPS_CPU_WATCH; if (config1 & MIPS_CONF1_CA) c->ases |= MIPS_ASE_MIPS16; if (config1 & MIPS_CONF1_EP) c->options |= MIPS_CPU_EJTAG; if (config1 & MIPS_CONF1_FP) { c->options |= MIPS_CPU_FPU; c->options |= MIPS_CPU_32FPR; } if (cpu_has_tlb) { c->tlbsize = ((config1 & MIPS_CONF1_TLBS) >> 25) + 1; c->tlbsizevtlb = c->tlbsize; c->tlbsizeftlbsets = 0; } return config1 & MIPS_CONF_M; } static inline unsigned int decode_config2(struct cpuinfo_mips *c) { unsigned int config2; config2 = read_c0_config2(); if (config2 & MIPS_CONF2_SL)