Merge patch series "ISA string parser cleanups"
[platform/kernel/linux-starfive.git] / arch / riscv / kernel / cpufeature.c
index d21f7e8..bdcf460 100644 (file)
@@ -21,6 +21,7 @@
 #include <asm/hwcap.h>
 #include <asm/patch.h>
 #include <asm/processor.h>
+#include <asm/vector.h>
 
 #define NUM_ALPHA_EXTS ('z' - 'a' + 1)
 
@@ -29,6 +30,9 @@ unsigned long elf_hwcap __read_mostly;
 /* Host ISA bitmap */
 static DECLARE_BITMAP(riscv_isa, RISCV_ISA_EXT_MAX) __read_mostly;
 
+/* Per-cpu ISA extensions. */
+struct riscv_isainfo hart_isa[NR_CPUS];
+
 /* Performance information */
 DEFINE_PER_CPU(long, misaligned_access_speed);
 
@@ -74,10 +78,10 @@ static bool riscv_isa_extension_check(int id)
        switch (id) {
        case RISCV_ISA_EXT_ZICBOM:
                if (!riscv_cbom_block_size) {
-                       pr_err("Zicbom detected in ISA string, but no cbom-block-size found\n");
+                       pr_err("Zicbom detected in ISA string, disabling as no cbom-block-size found\n");
                        return false;
                } else if (!is_power_of_2(riscv_cbom_block_size)) {
-                       pr_err("cbom-block-size present, but is not a power-of-2\n");
+                       pr_err("Zicbom disabled as cbom-block-size present, but is not a power-of-2\n");
                        return false;
                }
                return true;
@@ -112,6 +116,7 @@ void __init riscv_fill_hwcap(void)
        isa2hwcap['f' - 'a'] = COMPAT_HWCAP_ISA_F;
        isa2hwcap['d' - 'a'] = COMPAT_HWCAP_ISA_D;
        isa2hwcap['c' - 'a'] = COMPAT_HWCAP_ISA_C;
+       isa2hwcap['v' - 'a'] = COMPAT_HWCAP_ISA_V;
 
        elf_hwcap = 0;
 
@@ -124,8 +129,8 @@ void __init riscv_fill_hwcap(void)
        }
 
        for_each_possible_cpu(cpu) {
+               struct riscv_isainfo *isainfo = &hart_isa[cpu];
                unsigned long this_hwcap = 0;
-               DECLARE_BITMAP(this_isa, RISCV_ISA_EXT_MAX);
 
                if (acpi_disabled) {
                        node = of_cpu_device_node_get(cpu);
@@ -156,7 +161,6 @@ void __init riscv_fill_hwcap(void)
                 */
                isa += 4;
 
-               bitmap_zero(this_isa, RISCV_ISA_EXT_MAX);
                while (*isa) {
                        const char *ext = isa++;
                        const char *ext_end = isa;
@@ -282,7 +286,7 @@ void __init riscv_fill_hwcap(void)
                                if ((ext_end - ext == sizeof(name) - 1) &&              \
                                     !strncasecmp(ext, name, sizeof(name) - 1) &&       \
                                     riscv_isa_extension_check(bit))                    \
-                                       set_bit(bit, this_isa);                         \
+                                       set_bit(bit, isainfo->isa);                     \
                        } while (false)                                                 \
 
                        if (unlikely(ext_err))
@@ -292,7 +296,7 @@ void __init riscv_fill_hwcap(void)
 
                                if (riscv_isa_extension_check(nr)) {
                                        this_hwcap |= isa2hwcap[nr];
-                                       set_bit(nr, this_isa);
+                                       set_bit(nr, isainfo->isa);
                                }
                        } else {
                                /* sorted alphabetically */
@@ -303,7 +307,9 @@ void __init riscv_fill_hwcap(void)
                                SET_ISA_EXT_MAP("svinval", RISCV_ISA_EXT_SVINVAL);
                                SET_ISA_EXT_MAP("svnapot", RISCV_ISA_EXT_SVNAPOT);
                                SET_ISA_EXT_MAP("svpbmt", RISCV_ISA_EXT_SVPBMT);
+                               SET_ISA_EXT_MAP("zba", RISCV_ISA_EXT_ZBA);
                                SET_ISA_EXT_MAP("zbb", RISCV_ISA_EXT_ZBB);
+                               SET_ISA_EXT_MAP("zbs", RISCV_ISA_EXT_ZBS);
                                SET_ISA_EXT_MAP("zicbom", RISCV_ISA_EXT_ZICBOM);
                                SET_ISA_EXT_MAP("zicboz", RISCV_ISA_EXT_ZICBOZ);
                                SET_ISA_EXT_MAP("zihintpause", RISCV_ISA_EXT_ZIHINTPAUSE);
@@ -315,8 +321,8 @@ void __init riscv_fill_hwcap(void)
                 * Linux requires the following extensions, so we may as well
                 * always set them.
                 */
-               set_bit(RISCV_ISA_EXT_ZICSR, this_isa);
-               set_bit(RISCV_ISA_EXT_ZIFENCEI, this_isa);
+               set_bit(RISCV_ISA_EXT_ZICSR, isainfo->isa);
+               set_bit(RISCV_ISA_EXT_ZIFENCEI, isainfo->isa);
 
                /*
                 * These ones were as they were part of the base ISA when the
@@ -324,8 +330,8 @@ void __init riscv_fill_hwcap(void)
                 * unconditionally where `i` is in riscv,isa on DT systems.
                 */
                if (acpi_disabled) {
-                       set_bit(RISCV_ISA_EXT_ZICNTR, this_isa);
-                       set_bit(RISCV_ISA_EXT_ZIHPM, this_isa);
+                       set_bit(RISCV_ISA_EXT_ZICNTR, isainfo->isa);
+                       set_bit(RISCV_ISA_EXT_ZIHPM, isainfo->isa);
                }
 
                /*
@@ -339,9 +345,9 @@ void __init riscv_fill_hwcap(void)
                        elf_hwcap = this_hwcap;
 
                if (bitmap_empty(riscv_isa, RISCV_ISA_EXT_MAX))
-                       bitmap_copy(riscv_isa, this_isa, RISCV_ISA_EXT_MAX);
+                       bitmap_copy(riscv_isa, isainfo->isa, RISCV_ISA_EXT_MAX);
                else
-                       bitmap_and(riscv_isa, riscv_isa, this_isa, RISCV_ISA_EXT_MAX);
+                       bitmap_and(riscv_isa, riscv_isa, isainfo->isa, RISCV_ISA_EXT_MAX);
        }
 
        if (!acpi_disabled && rhct)
@@ -354,6 +360,17 @@ void __init riscv_fill_hwcap(void)
                elf_hwcap &= ~COMPAT_HWCAP_ISA_F;
        }
 
+       if (elf_hwcap & COMPAT_HWCAP_ISA_V) {
+               riscv_v_setup_vsize();
+               /*
+                * ISA string in device tree might have 'v' flag, but
+                * CONFIG_RISCV_ISA_V is disabled in kernel.
+                * Clear V flag in elf_hwcap if CONFIG_RISCV_ISA_V is disabled.
+                */
+               if (!IS_ENABLED(CONFIG_RISCV_ISA_V))
+                       elf_hwcap &= ~COMPAT_HWCAP_ISA_V;
+       }
+
        memset(print_str, 0, sizeof(print_str));
        for (i = 0, j = 0; i < NUM_ALPHA_EXTS; i++)
                if (riscv_isa[0] & BIT_MASK(i))
@@ -367,6 +384,18 @@ void __init riscv_fill_hwcap(void)
        pr_info("riscv: ELF capabilities %s\n", print_str);
 }
 
+unsigned long riscv_get_elf_hwcap(void)
+{
+       unsigned long hwcap;
+
+       hwcap = (elf_hwcap & ((1UL << RISCV_ISA_EXT_BASE) - 1));
+
+       if (!riscv_v_vstate_ctrl_user_allowed())
+               hwcap &= ~COMPAT_HWCAP_ISA_V;
+
+       return hwcap;
+}
+
 #ifdef CONFIG_RISCV_ALTERNATIVE
 /*
  * Alternative patch sites consider 48 bits when determining when to patch