Merge patch series "Putting some basic order on isa extension lists"
[linux-2.6-microblaze.git] / arch / riscv / kernel / cpufeature.c
index 8a76a6c..dde0e91 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/bitmap.h>
 #include <linux/ctype.h>
 #include <linux/libfdt.h>
+#include <linux/log2.h>
 #include <linux/module.h>
 #include <linux/of.h>
 #include <asm/alternative.h>
@@ -68,21 +69,38 @@ bool __riscv_isa_extension_available(const unsigned long *isa_bitmap, int bit)
 }
 EXPORT_SYMBOL_GPL(__riscv_isa_extension_available);
 
+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");
+                       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");
+                       return false;
+               }
+               return true;
+       }
+
+       return true;
+}
+
 void __init riscv_fill_hwcap(void)
 {
        struct device_node *node;
        const char *isa;
        char print_str[NUM_ALPHA_EXTS + 1];
        int i, j, rc;
-       static unsigned long isa2hwcap[256] = {0};
+       unsigned long isa2hwcap[26] = {0};
        unsigned long hartid;
 
-       isa2hwcap['i'] = isa2hwcap['I'] = COMPAT_HWCAP_ISA_I;
-       isa2hwcap['m'] = isa2hwcap['M'] = COMPAT_HWCAP_ISA_M;
-       isa2hwcap['a'] = isa2hwcap['A'] = COMPAT_HWCAP_ISA_A;
-       isa2hwcap['f'] = isa2hwcap['F'] = COMPAT_HWCAP_ISA_F;
-       isa2hwcap['d'] = isa2hwcap['D'] = COMPAT_HWCAP_ISA_D;
-       isa2hwcap['c'] = isa2hwcap['C'] = COMPAT_HWCAP_ISA_C;
+       isa2hwcap['i' - 'a'] = COMPAT_HWCAP_ISA_I;
+       isa2hwcap['m' - 'a'] = COMPAT_HWCAP_ISA_M;
+       isa2hwcap['a' - 'a'] = COMPAT_HWCAP_ISA_A;
+       isa2hwcap['f' - 'a'] = COMPAT_HWCAP_ISA_F;
+       isa2hwcap['d' - 'a'] = COMPAT_HWCAP_ISA_D;
+       isa2hwcap['c' - 'a'] = COMPAT_HWCAP_ISA_C;
 
        elf_hwcap = 0;
 
@@ -189,15 +207,20 @@ void __init riscv_fill_hwcap(void)
 #define SET_ISA_EXT_MAP(name, bit)                                             \
                        do {                                                    \
                                if ((ext_end - ext == sizeof(name) - 1) &&      \
-                                    !memcmp(ext, name, sizeof(name) - 1))      \
+                                    !memcmp(ext, name, sizeof(name) - 1) &&    \
+                                    riscv_isa_extension_check(bit))            \
                                        set_bit(bit, this_isa);                 \
                        } while (false)                                         \
 
                        if (unlikely(ext_err))
                                continue;
                        if (!ext_long) {
-                               this_hwcap |= isa2hwcap[(unsigned char)(*ext)];
-                               set_bit(*ext - 'a', this_isa);
+                               int nr = *ext - 'a';
+
+                               if (riscv_isa_extension_check(nr)) {
+                                       this_hwcap |= isa2hwcap[nr];
+                                       set_bit(nr, this_isa);
+                               }
                        } else {
                                /* sorted alphabetically */
                                SET_ISA_EXT_MAP("sscofpmf", RISCV_ISA_EXT_SSCOFPMF);
@@ -318,8 +341,11 @@ 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);
+                       riscv_alternative_fix_offsets(alt->old_ptr, alt->alt_len,
+                                                     alt->old_ptr - alt->alt_ptr);
+               }
        }
 }
 #endif