MIPS: cpu-probe: introduce exclusive R3k CPU probe
authorThomas Bogendoerfer <tsbogend@alpha.franken.de>
Thu, 8 Oct 2020 21:33:26 +0000 (23:33 +0200)
committerThomas Bogendoerfer <tsbogend@alpha.franken.de>
Mon, 12 Oct 2020 10:05:16 +0000 (12:05 +0200)
Running a kernel on a R3k of machine definitly will never see one of
the newer CPU cores. And since R3k system usually are low on memory
we could save quite some kbytes:

   text    data     bss     dec     hex filename
  15070      88      32   15190    3b56 arch/mips/kernel/cpu-probe.o
    844       4      16     864     360 arch/mips/kernel/cpu-r3k-probe.o

Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
arch/mips/kernel/Makefile
arch/mips/kernel/cpu-r3k-probe.c [new file with mode: 0644]

index 026801c..2a05b92 100644 (file)
@@ -5,11 +5,17 @@
 
 extra-y                := head.o vmlinux.lds
 
-obj-y          += cmpxchg.o cpu-probe.o branch.o elf.o entry.o genex.o idle.o irq.o \
+obj-y          += branch.o cmpxchg.o elf.o entry.o genex.o idle.o irq.o \
                   process.o prom.o ptrace.o reset.o setup.o signal.o \
                   syscall.o time.o topology.o traps.o unaligned.o watch.o \
                   vdso.o cacheinfo.o
 
+ifdef CONFIG_CPU_R3K_TLB
+obj-y          += cpu-r3k-probe.o
+else
+obj-y          += cpu-probe.o
+endif
+
 ifdef CONFIG_FUNCTION_TRACER
 CFLAGS_REMOVE_ftrace.o = -pg
 CFLAGS_REMOVE_early_printk.o = -pg
diff --git a/arch/mips/kernel/cpu-r3k-probe.c b/arch/mips/kernel/cpu-r3k-probe.c
new file mode 100644 (file)
index 0000000..abdbbe8
--- /dev/null
@@ -0,0 +1,171 @@
+// 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 "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 = &current_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;
+       case PRID_COMP_LEGACY | PRID_IMP_TX39:
+               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;
+       }
+
+       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);
+}
+
+void cpu_report(void)
+{
+       struct cpuinfo_mips *c = &current_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);
+}