RISC-V: Add Sstc extension support
[linux-2.6-microblaze.git] / arch / riscv / kernel / cpufeature.c
index d1d83cd..553d755 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/module.h>
 #include <linux/of.h>
 #include <asm/alternative.h>
+#include <asm/cacheflush.h>
 #include <asm/errata_list.h>
 #include <asm/hwcap.h>
 #include <asm/patch.h>
@@ -27,9 +28,8 @@ unsigned long elf_hwcap __read_mostly;
 /* Host ISA bitmap */
 static DECLARE_BITMAP(riscv_isa, RISCV_ISA_EXT_MAX) __read_mostly;
 
-#ifdef CONFIG_FPU
-__ro_after_init DEFINE_STATIC_KEY_FALSE(cpu_hwcap_fpu);
-#endif
+__ro_after_init DEFINE_STATIC_KEY_ARRAY_FALSE(riscv_isa_ext_keys, RISCV_ISA_EXT_KEY_MAX);
+EXPORT_SYMBOL(riscv_isa_ext_keys);
 
 /**
  * riscv_isa_extension_base() - Get base extension word
@@ -73,8 +73,9 @@ void __init riscv_fill_hwcap(void)
        struct device_node *node;
        const char *isa;
        char print_str[NUM_ALPHA_EXTS + 1];
-       int i, j;
+       int i, j, rc;
        static unsigned long isa2hwcap[256] = {0};
+       unsigned long hartid;
 
        isa2hwcap['i'] = isa2hwcap['I'] = COMPAT_HWCAP_ISA_I;
        isa2hwcap['m'] = isa2hwcap['M'] = COMPAT_HWCAP_ISA_M;
@@ -92,7 +93,8 @@ void __init riscv_fill_hwcap(void)
                DECLARE_BITMAP(this_isa, RISCV_ISA_EXT_MAX);
                const char *temp;
 
-               if (riscv_of_processor_hartid(node) < 0)
+               rc = riscv_of_processor_hartid(node, &hartid);
+               if (rc < 0)
                        continue;
 
                if (of_property_read_string(node, "riscv,isa", &isa)) {
@@ -199,6 +201,8 @@ void __init riscv_fill_hwcap(void)
                        } else {
                                SET_ISA_EXT_MAP("sscofpmf", RISCV_ISA_EXT_SSCOFPMF);
                                SET_ISA_EXT_MAP("svpbmt", RISCV_ISA_EXT_SVPBMT);
+                               SET_ISA_EXT_MAP("zicbom", RISCV_ISA_EXT_ZICBOM);
+                               SET_ISA_EXT_MAP("zihintpause", RISCV_ISA_EXT_ZIHINTPAUSE);
                                SET_ISA_EXT_MAP("sstc", RISCV_ISA_EXT_SSTC);
                        }
 #undef SET_ISA_EXT_MAP
@@ -239,19 +243,15 @@ void __init riscv_fill_hwcap(void)
                        print_str[j++] = (char)('a' + i);
        pr_info("riscv: ELF capabilities %s\n", print_str);
 
-#ifdef CONFIG_FPU
-       if (elf_hwcap & (COMPAT_HWCAP_ISA_F | COMPAT_HWCAP_ISA_D))
-               static_branch_enable(&cpu_hwcap_fpu);
-#endif
+       for_each_set_bit(i, riscv_isa, RISCV_ISA_EXT_MAX) {
+               j = riscv_isa_ext2key(i);
+               if (j >= 0)
+                       static_branch_enable(&riscv_isa_ext_keys[j]);
+       }
 }
 
 #ifdef CONFIG_RISCV_ALTERNATIVE
-struct cpufeature_info {
-       char name[ERRATA_STRING_LENGTH_MAX];
-       bool (*check_func)(unsigned int stage);
-};
-
-static bool __init_or_module cpufeature_svpbmt_check_func(unsigned int stage)
+static bool __init_or_module cpufeature_probe_svpbmt(unsigned int stage)
 {
 #ifdef CONFIG_RISCV_ISA_SVPBMT
        switch (stage) {
@@ -265,26 +265,41 @@ static bool __init_or_module cpufeature_svpbmt_check_func(unsigned int stage)
        return false;
 }
 
-static const struct cpufeature_info __initdata_or_module
-cpufeature_list[CPUFEATURE_NUMBER] = {
-       {
-               .name = "svpbmt",
-               .check_func = cpufeature_svpbmt_check_func
-       },
-};
+static bool __init_or_module cpufeature_probe_zicbom(unsigned int stage)
+{
+#ifdef CONFIG_RISCV_ISA_ZICBOM
+       switch (stage) {
+       case RISCV_ALTERNATIVES_EARLY_BOOT:
+               return false;
+       default:
+               if (riscv_isa_extension_available(NULL, ZICBOM)) {
+                       riscv_noncoherent_supported();
+                       return true;
+               } else {
+                       return false;
+               }
+       }
+#endif
+
+       return false;
+}
 
+/*
+ * Probe presence of individual extensions.
+ *
+ * This code may also be executed before kernel relocation, so we cannot use
+ * addresses generated by the address-of operator as they won't be valid in
+ * this context.
+ */
 static u32 __init_or_module cpufeature_probe(unsigned int stage)
 {
-       const struct cpufeature_info *info;
        u32 cpu_req_feature = 0;
-       int idx;
 
-       for (idx = 0; idx < CPUFEATURE_NUMBER; idx++) {
-               info = &cpufeature_list[idx];
+       if (cpufeature_probe_svpbmt(stage))
+               cpu_req_feature |= (1U << CPUFEATURE_SVPBMT);
 
-               if (info->check_func(stage))
-                       cpu_req_feature |= (1U << idx);
-       }
+       if (cpufeature_probe_zicbom(stage))
+               cpu_req_feature |= (1U << CPUFEATURE_ZICBOM);
 
        return cpu_req_feature;
 }
@@ -294,7 +309,6 @@ void __init_or_module riscv_cpufeature_patch_func(struct alt_entry *begin,
                                                  unsigned int stage)
 {
        u32 cpu_req_feature = cpufeature_probe(stage);
-       u32 cpu_apply_feature = 0;
        struct alt_entry *alt;
        u32 tmp;
 
@@ -308,10 +322,8 @@ void __init_or_module riscv_cpufeature_patch_func(struct alt_entry *begin,
                }
 
                tmp = (1U << alt->errata_id);
-               if (cpu_req_feature & tmp) {
+               if (cpu_req_feature & tmp)
                        patch_text_nosync(alt->old_ptr, alt->alt_ptr, alt->alt_len);
-                       cpu_apply_feature |= tmp;
-               }
        }
 }
 #endif