riscv: allow different stages with alternatives
authorHeiko Stuebner <heiko@sntech.de>
Wed, 11 May 2022 19:29:11 +0000 (21:29 +0200)
committerPalmer Dabbelt <palmer@rivosinc.com>
Thu, 12 May 2022 04:36:31 +0000 (21:36 -0700)
Future features may need to be applied at a different
time during boot, so allow defining stages for alternatives
and handling them differently depending on the stage.

Also make the alternatives-location more flexible so that
future stages may provide their own location.

Signed-off-by: Heiko Stuebner <heiko@sntech.de>
Reviewed-by: Philipp Tomsich <philipp.tomsich@vrull.eu>
Link: https://lore.kernel.org/r/20220511192921.2223629-3-heiko@sntech.de
Signed-off-by: Palmer Dabbelt <palmer@rivosinc.com>
arch/riscv/errata/sifive/errata.c
arch/riscv/include/asm/alternative.h
arch/riscv/kernel/alternative.c

index f5e5ae7..4fe03ac 100644 (file)
@@ -80,7 +80,8 @@ static void __init warn_miss_errata(u32 miss_errata)
 }
 
 void __init sifive_errata_patch_func(struct alt_entry *begin, struct alt_entry *end,
-                                    unsigned long archid, unsigned long impid)
+                                    unsigned long archid, unsigned long impid,
+                                    unsigned int stage)
 {
        struct alt_entry *alt;
        u32 cpu_req_errata = sifive_errata_probe(archid, impid);
index 7b42bce..0ff5506 100644 (file)
@@ -19,6 +19,8 @@
 #include <linux/stddef.h>
 #include <asm/hwcap.h>
 
+#define RISCV_ALTERNATIVES_BOOT                0 /* alternatives applied during regular boot */
+
 void __init apply_boot_alternatives(void);
 
 struct alt_entry {
@@ -35,7 +37,8 @@ struct errata_checkfunc_id {
 };
 
 void sifive_errata_patch_func(struct alt_entry *begin, struct alt_entry *end,
-                             unsigned long archid, unsigned long impid);
+                             unsigned long archid, unsigned long impid,
+                             unsigned int stage);
 
 #else /* CONFIG_RISCV_ALTERNATIVE */
 
index e8b4a0f..02db62f 100644 (file)
@@ -22,8 +22,8 @@ static struct cpu_manufacturer_info_t {
 } cpu_mfr_info;
 
 static void (*vendor_patch_func)(struct alt_entry *begin, struct alt_entry *end,
-                                unsigned long archid,
-                                unsigned long impid) __initdata;
+                                unsigned long archid, unsigned long impid,
+                                unsigned int stage) __initdata;
 
 static inline void __init riscv_fill_cpu_mfr_info(void)
 {
@@ -58,6 +58,18 @@ static void __init init_alternative(void)
  * a feature detect on the boot CPU). No need to worry about other CPUs
  * here.
  */
+static void __init _apply_alternatives(struct alt_entry *begin,
+                                      struct alt_entry *end,
+                                      unsigned int stage)
+{
+       if (!vendor_patch_func)
+               return;
+
+       vendor_patch_func(begin, end,
+                         cpu_mfr_info.arch_id, cpu_mfr_info.imp_id,
+                         stage);
+}
+
 void __init apply_boot_alternatives(void)
 {
        /* If called on non-boot cpu things could go wrong */
@@ -65,11 +77,7 @@ void __init apply_boot_alternatives(void)
 
        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);
+       _apply_alternatives((struct alt_entry *)__alt_start,
+                           (struct alt_entry *)__alt_end,
+                           RISCV_ALTERNATIVES_BOOT);
 }
-