riscv: integrate alternatives better into the main architecture
authorHeiko Stuebner <heiko@sntech.de>
Wed, 11 May 2022 19:29:10 +0000 (21:29 +0200)
committerPalmer Dabbelt <palmer@rivosinc.com>
Thu, 12 May 2022 04:36:31 +0000 (21:36 -0700)
Right now the alternatives need to be explicitly enabled and
erratas are limited to SiFive ones.

We want to use alternatives not only for patching soc erratas,
but in the future also for handling different behaviour depending
on the existence of future extensions.

So move the core alternatives over to the kernel subdirectory
and move the CONFIG_RISCV_ALTERNATIVE to be a hidden symbol
which we expect relevant erratas and extensions to just select
if needed.

Signed-off-by: Heiko Stuebner <heiko@sntech.de>
Reviewed-by: Philipp Tomsich <philipp.tomsich@vrull.eu>
Link: https://lore.kernel.org/r/20220511192921.2223629-2-heiko@sntech.de
Signed-off-by: Palmer Dabbelt <palmer@rivosinc.com>
12 files changed:
arch/riscv/Kconfig
arch/riscv/Kconfig.erratas
arch/riscv/Kconfig.socs
arch/riscv/Makefile
arch/riscv/errata/Makefile
arch/riscv/errata/alternative.c [deleted file]
arch/riscv/include/asm/alternative-macros.h
arch/riscv/include/asm/alternative.h
arch/riscv/kernel/Makefile
arch/riscv/kernel/alternative.c [new file with mode: 0644]
arch/riscv/kernel/smpboot.c
arch/riscv/kernel/traps.c

index 00fd9c548f2631c6fc537f3e3dfdd28780c3e82a..26464dae8ab732d0350ee4c194074a21fc3fd3af 100644 (file)
@@ -324,6 +324,15 @@ config NODES_SHIFT
          Specify the maximum number of NUMA Nodes available on the target
          system.  Increases memory reserved to accommodate various tables.
 
+config RISCV_ALTERNATIVE
+       bool
+       depends on !XIP_KERNEL
+       help
+         This Kconfig allows the kernel to automatically patch the
+         errata required by the execution platform at run time. The
+         code patching is performed once in the boot stages. It means
+         that the overhead from this mechanism is just taken once.
+
 config RISCV_ISA_C
        bool "Emit compressed instructions when building Linux"
        default y
index 0aacd7052585b5e2820bbcc633a5e8126cbef923..c521c2ae2de2f247e49cd437cd9223525f594132 100644 (file)
@@ -1,18 +1,9 @@
 menu "CPU errata selection"
 
-config RISCV_ERRATA_ALTERNATIVE
-       bool "RISC-V alternative scheme"
-       depends on !XIP_KERNEL
-       default y
-       help
-         This Kconfig allows the kernel to automatically patch the
-         errata required by the execution platform at run time. The
-         code patching is performed once in the boot stages. It means
-         that the overhead from this mechanism is just taken once.
-
 config ERRATA_SIFIVE
        bool "SiFive errata"
-       depends on RISCV_ERRATA_ALTERNATIVE
+       depends on !XIP_KERNEL
+       select RISCV_ALTERNATIVE
        help
          All SiFive errata Kconfig depend on this Kconfig. Disabling
          this Kconfig will disable all SiFive errata. Please say "Y"
index 34592d00dde8c65316b7b4f7325aa7e05fc4ff21..41c0a6e9b0bf0e09c305cf7010222e0a9feafca5 100644 (file)
@@ -14,7 +14,6 @@ config SOC_SIFIVE
        select CLK_SIFIVE
        select CLK_SIFIVE_PRCI
        select SIFIVE_PLIC
-       select RISCV_ERRATA_ALTERNATIVE if !XIP_KERNEL
        select ERRATA_SIFIVE if !XIP_KERNEL
        help
          This enables support for SiFive SoC platform hardware.
index 7d81102cffd48e38e7c16c4782655d4653dc127b..a7ed47ce9311bdbe054e81599a9fddce3fce2c8f 100644 (file)
@@ -103,7 +103,7 @@ endif
 
 head-y := arch/riscv/kernel/head.o
 
-core-$(CONFIG_RISCV_ERRATA_ALTERNATIVE) += arch/riscv/errata/
+core-y += arch/riscv/errata/
 core-$(CONFIG_KVM) += arch/riscv/kvm/
 
 libs-y += arch/riscv/lib/
index b8f8740a3e442cb8d1a91c78676a8570feb3fb5e..0ca1c5281a2d1980ab66f16c490bed798229831f 100644 (file)
@@ -1,2 +1 @@
-obj-y  += alternative.o
 obj-$(CONFIG_ERRATA_SIFIVE) += sifive/
diff --git a/arch/riscv/errata/alternative.c b/arch/riscv/errata/alternative.c
deleted file mode 100644 (file)
index e8b4a0f..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * alternative runtime patching
- * inspired by the ARM64 and x86 version
- *
- * Copyright (C) 2021 Sifive.
- */
-
-#include <linux/init.h>
-#include <linux/cpu.h>
-#include <linux/uaccess.h>
-#include <asm/alternative.h>
-#include <asm/sections.h>
-#include <asm/vendorid_list.h>
-#include <asm/sbi.h>
-#include <asm/csr.h>
-
-static struct cpu_manufacturer_info_t {
-       unsigned long vendor_id;
-       unsigned long arch_id;
-       unsigned long imp_id;
-} cpu_mfr_info;
-
-static void (*vendor_patch_func)(struct alt_entry *begin, struct alt_entry *end,
-                                unsigned long archid,
-                                unsigned long impid) __initdata;
-
-static inline void __init riscv_fill_cpu_mfr_info(void)
-{
-#ifdef CONFIG_RISCV_M_MODE
-       cpu_mfr_info.vendor_id = csr_read(CSR_MVENDORID);
-       cpu_mfr_info.arch_id = csr_read(CSR_MARCHID);
-       cpu_mfr_info.imp_id = csr_read(CSR_MIMPID);
-#else
-       cpu_mfr_info.vendor_id = sbi_get_mvendorid();
-       cpu_mfr_info.arch_id = sbi_get_marchid();
-       cpu_mfr_info.imp_id = sbi_get_mimpid();
-#endif
-}
-
-static void __init init_alternative(void)
-{
-       riscv_fill_cpu_mfr_info();
-
-       switch (cpu_mfr_info.vendor_id) {
-#ifdef CONFIG_ERRATA_SIFIVE
-       case SIFIVE_VENDOR_ID:
-               vendor_patch_func = sifive_errata_patch_func;
-               break;
-#endif
-       default:
-               vendor_patch_func = NULL;
-       }
-}
-
-/*
- * This is called very early in the boot process (directly after we run
- * a feature detect on the boot CPU). No need to worry about other CPUs
- * here.
- */
-void __init apply_boot_alternatives(void)
-{
-       /* If called on non-boot cpu things could go wrong */
-       WARN_ON(smp_processor_id() != 0);
-
-       init_alternative();
-
-       if (!vendor_patch_func)
-               return;
-
-       vendor_patch_func((struct alt_entry *)__alt_start,
-                         (struct alt_entry *)__alt_end,
-                         cpu_mfr_info.arch_id, cpu_mfr_info.imp_id);
-}
-
index 67406c37638903a24ef420e9bd679678050bb1e0..5dd8d03a13da73e0a38afd79934aa50b78146cdf 100644 (file)
@@ -2,7 +2,7 @@
 #ifndef __ASM_ALTERNATIVE_MACROS_H
 #define __ASM_ALTERNATIVE_MACROS_H
 
-#ifdef CONFIG_RISCV_ERRATA_ALTERNATIVE
+#ifdef CONFIG_RISCV_ALTERNATIVE
 
 #ifdef __ASSEMBLY__
 
@@ -76,7 +76,7 @@
 
 #endif /* __ASSEMBLY__ */
 
-#else /* !CONFIG_RISCV_ERRATA_ALTERNATIVE*/
+#else /* CONFIG_RISCV_ALTERNATIVE */
 #ifdef __ASSEMBLY__
 
 .macro __ALTERNATIVE_CFG old_c
@@ -95,7 +95,8 @@
        __ALTERNATIVE_CFG(old_c)
 
 #endif /* __ASSEMBLY__ */
-#endif /* CONFIG_RISCV_ERRATA_ALTERNATIVE */
+#endif /* CONFIG_RISCV_ALTERNATIVE */
+
 /*
  * Usage:
  *   ALTERNATIVE(old_content, new_content, vendor_id, errata_id, CONFIG_k)
index e625d3cafbed5440201ac9bf31afc283aeda45bf..7b42bcef0ecf3e5c87d81ef5ef9620505acb6388 100644 (file)
@@ -12,6 +12,8 @@
 
 #ifndef __ASSEMBLY__
 
+#ifdef CONFIG_RISCV_ALTERNATIVE
+
 #include <linux/init.h>
 #include <linux/types.h>
 #include <linux/stddef.h>
@@ -35,5 +37,11 @@ struct errata_checkfunc_id {
 void sifive_errata_patch_func(struct alt_entry *begin, struct alt_entry *end,
                              unsigned long archid, unsigned long impid);
 
+#else /* CONFIG_RISCV_ALTERNATIVE */
+
+static inline void apply_boot_alternatives(void) { }
+
+#endif /* CONFIG_RISCV_ALTERNATIVE */
+
 #endif
 #endif
index 87adbe47bc158075030cfacaa9bcbbb68be1121b..0f8348ac30f154d5ae308d6a2dc84d6ed06541d5 100644 (file)
@@ -18,6 +18,7 @@ extra-y += head.o
 extra-y += vmlinux.lds
 
 obj-y  += soc.o
+obj-$(CONFIG_RISCV_ALTERNATIVE) += alternative.o
 obj-y  += cpu.o
 obj-y  += cpufeature.o
 obj-y  += entry.o
diff --git a/arch/riscv/kernel/alternative.c b/arch/riscv/kernel/alternative.c
new file mode 100644 (file)
index 0000000..e8b4a0f
--- /dev/null
@@ -0,0 +1,75 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * alternative runtime patching
+ * inspired by the ARM64 and x86 version
+ *
+ * Copyright (C) 2021 Sifive.
+ */
+
+#include <linux/init.h>
+#include <linux/cpu.h>
+#include <linux/uaccess.h>
+#include <asm/alternative.h>
+#include <asm/sections.h>
+#include <asm/vendorid_list.h>
+#include <asm/sbi.h>
+#include <asm/csr.h>
+
+static struct cpu_manufacturer_info_t {
+       unsigned long vendor_id;
+       unsigned long arch_id;
+       unsigned long imp_id;
+} cpu_mfr_info;
+
+static void (*vendor_patch_func)(struct alt_entry *begin, struct alt_entry *end,
+                                unsigned long archid,
+                                unsigned long impid) __initdata;
+
+static inline void __init riscv_fill_cpu_mfr_info(void)
+{
+#ifdef CONFIG_RISCV_M_MODE
+       cpu_mfr_info.vendor_id = csr_read(CSR_MVENDORID);
+       cpu_mfr_info.arch_id = csr_read(CSR_MARCHID);
+       cpu_mfr_info.imp_id = csr_read(CSR_MIMPID);
+#else
+       cpu_mfr_info.vendor_id = sbi_get_mvendorid();
+       cpu_mfr_info.arch_id = sbi_get_marchid();
+       cpu_mfr_info.imp_id = sbi_get_mimpid();
+#endif
+}
+
+static void __init init_alternative(void)
+{
+       riscv_fill_cpu_mfr_info();
+
+       switch (cpu_mfr_info.vendor_id) {
+#ifdef CONFIG_ERRATA_SIFIVE
+       case SIFIVE_VENDOR_ID:
+               vendor_patch_func = sifive_errata_patch_func;
+               break;
+#endif
+       default:
+               vendor_patch_func = NULL;
+       }
+}
+
+/*
+ * This is called very early in the boot process (directly after we run
+ * a feature detect on the boot CPU). No need to worry about other CPUs
+ * here.
+ */
+void __init apply_boot_alternatives(void)
+{
+       /* If called on non-boot cpu things could go wrong */
+       WARN_ON(smp_processor_id() != 0);
+
+       init_alternative();
+
+       if (!vendor_patch_func)
+               return;
+
+       vendor_patch_func((struct alt_entry *)__alt_start,
+                         (struct alt_entry *)__alt_end,
+                         cpu_mfr_info.arch_id, cpu_mfr_info.imp_id);
+}
+
index 622f226454d53d81cbc5cda9fd735fb6ed41d588..a6d13dca1403bf3c2dbe644c2f511e16ecb5235f 100644 (file)
@@ -41,9 +41,7 @@ static DECLARE_COMPLETION(cpu_running);
 void __init smp_prepare_boot_cpu(void)
 {
        init_cpu_topology();
-#ifdef CONFIG_RISCV_ERRATA_ALTERNATIVE
        apply_boot_alternatives();
-#endif
 }
 
 void __init smp_prepare_cpus(unsigned int max_cpus)
index fe92e119e6a3332e4d997176961bac6d0e439dd8..b404265092447ca8e349a89412e363b0199b73d2 100644 (file)
@@ -86,7 +86,7 @@ static void do_trap_error(struct pt_regs *regs, int signo, int code,
        }
 }
 
-#if defined (CONFIG_XIP_KERNEL) && defined (CONFIG_RISCV_ERRATA_ALTERNATIVE)
+#if defined(CONFIG_XIP_KERNEL) && defined(CONFIG_RISCV_ALTERNATIVE)
 #define __trap_section         __section(".xip.traps")
 #else
 #define __trap_section