123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152 |
- // 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/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/elf.h>
- #include <asm/traps.h>
- #include "fpu-probe.h"
- /* Hardware capabilities */
- unsigned int elf_hwcap __read_mostly;
- EXPORT_SYMBOL_GPL(elf_hwcap);
- void __init check_bugs32(void)
- {
- }
- /*
- * 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
- extern unsigned long r3k_cache_size(unsigned long);
- 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;
- }
- const char *__cpu_name[NR_CPUS];
- const char *__elf_platform;
- const char *__elf_base_platform;
- void cpu_probe(void)
- {
- struct cpuinfo_mips *c = ¤t_cpu_data;
- unsigned int cpu = smp_processor_id();
- /*
- * Set a default elf platform, cpu probe may later
- * overwrite it with a more precise value
- */
- set_elf_platform(cpu, "mips");
- c->processor_id = PRID_IMP_UNKNOWN;
- c->fpu_id = FPIR_IMP_NONE;
- c->cputype = CPU_UNKNOWN;
- c->writecombine = _CACHE_UNCACHED;
- c->fpu_csr31 = FPU_CSR_RN;
- c->fpu_msk31 = FPU_CSR_RSVD | FPU_CSR_ABS2008 | FPU_CSR_NAN2008 |
- FPU_CSR_CONDX | FPU_CSR_FS;
- c->srsets = 1;
- c->processor_id = read_c0_prid();
- switch (c->processor_id & (PRID_COMP_MASK | PRID_IMP_MASK)) {
- case PRID_COMP_LEGACY | PRID_IMP_R2000:
- c->cputype = CPU_R2000;
- __cpu_name[cpu] = "R2000";
- c->options = MIPS_CPU_TLB | MIPS_CPU_3K_CACHE |
- MIPS_CPU_NOFPUEX;
- if (__cpu_has_fpu())
- c->options |= MIPS_CPU_FPU;
- c->tlbsize = 64;
- break;
- case PRID_COMP_LEGACY | PRID_IMP_R3000:
- if ((c->processor_id & PRID_REV_MASK) == PRID_REV_R3000A) {
- if (cpu_has_confreg()) {
- c->cputype = CPU_R3081E;
- __cpu_name[cpu] = "R3081";
- } else {
- c->cputype = CPU_R3000A;
- __cpu_name[cpu] = "R3000A";
- }
- } else {
- c->cputype = CPU_R3000;
- __cpu_name[cpu] = "R3000";
- }
- c->options = MIPS_CPU_TLB | MIPS_CPU_3K_CACHE |
- MIPS_CPU_NOFPUEX;
- if (__cpu_has_fpu())
- c->options |= MIPS_CPU_FPU;
- c->tlbsize = 64;
- break;
- }
- BUG_ON(!__cpu_name[cpu]);
- BUG_ON(c->cputype == CPU_UNKNOWN);
- /*
- * Platform code can force the cpu type to optimize code
- * generation. In that case be sure the cpu type is correctly
- * manually setup otherwise it could trigger some nasty bugs.
- */
- BUG_ON(current_cpu_type() != c->cputype);
- if (mips_fpu_disabled)
- c->options &= ~MIPS_CPU_FPU;
- if (c->options & MIPS_CPU_FPU)
- cpu_set_fpu_opts(c);
- else
- cpu_set_nofpu_opts(c);
- reserve_exception_space(0, 0x400);
- }
- void cpu_report(void)
- {
- struct cpuinfo_mips *c = ¤t_cpu_data;
- pr_info("CPU%d revision is: %08x (%s)\n",
- smp_processor_id(), c->processor_id, cpu_name_string());
- if (c->options & MIPS_CPU_FPU)
- pr_info("FPU revision is: %08x\n", c->fpu_id);
- }
|