Merge patch series "RISC-V: Probe for misaligned access speed"
[sfrench/cifs-2.6.git] / arch / riscv / kernel / cpufeature.c
index cc09444352b2730c5a7b95a9c0cb0f87fd0d0ee6..1cfbba65d11ae311d54729966e57fb3c9386d61c 100644 (file)
@@ -13,7 +13,6 @@
 #include <linux/memory.h>
 #include <linux/module.h>
 #include <linux/of.h>
-#include <linux/of_device.h>
 #include <asm/acpi.h>
 #include <asm/alternative.h>
 #include <asm/cacheflush.h>
@@ -106,29 +105,252 @@ static bool riscv_isa_extension_check(int id)
        return true;
 }
 
-void __init riscv_fill_hwcap(void)
+#define __RISCV_ISA_EXT_DATA(_name, _id) {     \
+       .name = #_name,                         \
+       .property = #_name,                     \
+       .id = _id,                              \
+}
+
+/*
+ * The canonical order of ISA extension names in the ISA string is defined in
+ * chapter 27 of the unprivileged specification.
+ *
+ * Ordinarily, for in-kernel data structures, this order is unimportant but
+ * isa_ext_arr defines the order of the ISA string in /proc/cpuinfo.
+ *
+ * The specification uses vague wording, such as should, when it comes to
+ * ordering, so for our purposes the following rules apply:
+ *
+ * 1. All multi-letter extensions must be separated from other extensions by an
+ *    underscore.
+ *
+ * 2. Additional standard extensions (starting with 'Z') must be sorted after
+ *    single-letter extensions and before any higher-privileged extensions.
+ *
+ * 3. The first letter following the 'Z' conventionally indicates the most
+ *    closely related alphabetical extension category, IMAFDQLCBKJTPVH.
+ *    If multiple 'Z' extensions are named, they must be ordered first by
+ *    category, then alphabetically within a category.
+ *
+ * 3. Standard supervisor-level extensions (starting with 'S') must be listed
+ *    after standard unprivileged extensions.  If multiple supervisor-level
+ *    extensions are listed, they must be ordered alphabetically.
+ *
+ * 4. Standard machine-level extensions (starting with 'Zxm') must be listed
+ *    after any lower-privileged, standard extensions.  If multiple
+ *    machine-level extensions are listed, they must be ordered
+ *    alphabetically.
+ *
+ * 5. Non-standard extensions (starting with 'X') must be listed after all
+ *    standard extensions. If multiple non-standard extensions are listed, they
+ *    must be ordered alphabetically.
+ *
+ * An example string following the order is:
+ *    rv64imadc_zifoo_zigoo_zafoo_sbar_scar_zxmbaz_xqux_xrux
+ *
+ * New entries to this struct should follow the ordering rules described above.
+ */
+const struct riscv_isa_ext_data riscv_isa_ext[] = {
+       __RISCV_ISA_EXT_DATA(i, RISCV_ISA_EXT_i),
+       __RISCV_ISA_EXT_DATA(m, RISCV_ISA_EXT_m),
+       __RISCV_ISA_EXT_DATA(a, RISCV_ISA_EXT_a),
+       __RISCV_ISA_EXT_DATA(f, RISCV_ISA_EXT_f),
+       __RISCV_ISA_EXT_DATA(d, RISCV_ISA_EXT_d),
+       __RISCV_ISA_EXT_DATA(q, RISCV_ISA_EXT_q),
+       __RISCV_ISA_EXT_DATA(c, RISCV_ISA_EXT_c),
+       __RISCV_ISA_EXT_DATA(b, RISCV_ISA_EXT_b),
+       __RISCV_ISA_EXT_DATA(k, RISCV_ISA_EXT_k),
+       __RISCV_ISA_EXT_DATA(j, RISCV_ISA_EXT_j),
+       __RISCV_ISA_EXT_DATA(p, RISCV_ISA_EXT_p),
+       __RISCV_ISA_EXT_DATA(v, RISCV_ISA_EXT_v),
+       __RISCV_ISA_EXT_DATA(h, RISCV_ISA_EXT_h),
+       __RISCV_ISA_EXT_DATA(zicbom, RISCV_ISA_EXT_ZICBOM),
+       __RISCV_ISA_EXT_DATA(zicboz, RISCV_ISA_EXT_ZICBOZ),
+       __RISCV_ISA_EXT_DATA(zicntr, RISCV_ISA_EXT_ZICNTR),
+       __RISCV_ISA_EXT_DATA(zicsr, RISCV_ISA_EXT_ZICSR),
+       __RISCV_ISA_EXT_DATA(zifencei, RISCV_ISA_EXT_ZIFENCEI),
+       __RISCV_ISA_EXT_DATA(zihintpause, RISCV_ISA_EXT_ZIHINTPAUSE),
+       __RISCV_ISA_EXT_DATA(zihpm, RISCV_ISA_EXT_ZIHPM),
+       __RISCV_ISA_EXT_DATA(zba, RISCV_ISA_EXT_ZBA),
+       __RISCV_ISA_EXT_DATA(zbb, RISCV_ISA_EXT_ZBB),
+       __RISCV_ISA_EXT_DATA(zbs, RISCV_ISA_EXT_ZBS),
+       __RISCV_ISA_EXT_DATA(smaia, RISCV_ISA_EXT_SMAIA),
+       __RISCV_ISA_EXT_DATA(ssaia, RISCV_ISA_EXT_SSAIA),
+       __RISCV_ISA_EXT_DATA(sscofpmf, RISCV_ISA_EXT_SSCOFPMF),
+       __RISCV_ISA_EXT_DATA(sstc, RISCV_ISA_EXT_SSTC),
+       __RISCV_ISA_EXT_DATA(svinval, RISCV_ISA_EXT_SVINVAL),
+       __RISCV_ISA_EXT_DATA(svnapot, RISCV_ISA_EXT_SVNAPOT),
+       __RISCV_ISA_EXT_DATA(svpbmt, RISCV_ISA_EXT_SVPBMT),
+};
+
+const size_t riscv_isa_ext_count = ARRAY_SIZE(riscv_isa_ext);
+
+static void __init riscv_parse_isa_string(unsigned long *this_hwcap, struct riscv_isainfo *isainfo,
+                                         unsigned long *isa2hwcap, const char *isa)
+{
+       /*
+        * For all possible cpus, we have already validated in
+        * the boot process that they at least contain "rv" and
+        * whichever of "32"/"64" this kernel supports, and so this
+        * section can be skipped.
+        */
+       isa += 4;
+
+       while (*isa) {
+               const char *ext = isa++;
+               const char *ext_end = isa;
+               bool ext_long = false, ext_err = false;
+
+               switch (*ext) {
+               case 's':
+                       /*
+                        * Workaround for invalid single-letter 's' & 'u'(QEMU).
+                        * No need to set the bit in riscv_isa as 's' & 'u' are
+                        * not valid ISA extensions. It works until multi-letter
+                        * extension starting with "Su" appears.
+                        */
+                       if (ext[-1] != '_' && ext[1] == 'u') {
+                               ++isa;
+                               ext_err = true;
+                               break;
+                       }
+                       fallthrough;
+               case 'S':
+               case 'x':
+               case 'X':
+               case 'z':
+               case 'Z':
+                       /*
+                        * Before attempting to parse the extension itself, we find its end.
+                        * As multi-letter extensions must be split from other multi-letter
+                        * extensions with an "_", the end of a multi-letter extension will
+                        * either be the null character or the "_" at the start of the next
+                        * multi-letter extension.
+                        *
+                        * Next, as the extensions version is currently ignored, we
+                        * eliminate that portion. This is done by parsing backwards from
+                        * the end of the extension, removing any numbers. This may be a
+                        * major or minor number however, so the process is repeated if a
+                        * minor number was found.
+                        *
+                        * ext_end is intended to represent the first character *after* the
+                        * name portion of an extension, but will be decremented to the last
+                        * character itself while eliminating the extensions version number.
+                        * A simple re-increment solves this problem.
+                        */
+                       ext_long = true;
+                       for (; *isa && *isa != '_'; ++isa)
+                               if (unlikely(!isalnum(*isa)))
+                                       ext_err = true;
+
+                       ext_end = isa;
+                       if (unlikely(ext_err))
+                               break;
+
+                       if (!isdigit(ext_end[-1]))
+                               break;
+
+                       while (isdigit(*--ext_end))
+                               ;
+
+                       if (tolower(ext_end[0]) != 'p' || !isdigit(ext_end[-1])) {
+                               ++ext_end;
+                               break;
+                       }
+
+                       while (isdigit(*--ext_end))
+                               ;
+
+                       ++ext_end;
+                       break;
+               default:
+                       /*
+                        * Things are a little easier for single-letter extensions, as they
+                        * are parsed forwards.
+                        *
+                        * After checking that our starting position is valid, we need to
+                        * ensure that, when isa was incremented at the start of the loop,
+                        * that it arrived at the start of the next extension.
+                        *
+                        * If we are already on a non-digit, there is nothing to do. Either
+                        * we have a multi-letter extension's _, or the start of an
+                        * extension.
+                        *
+                        * Otherwise we have found the current extension's major version
+                        * number. Parse past it, and a subsequent p/minor version number
+                        * if present. The `p` extension must not appear immediately after
+                        * a number, so there is no fear of missing it.
+                        *
+                        */
+                       if (unlikely(!isalpha(*ext))) {
+                               ext_err = true;
+                               break;
+                       }
+
+                       if (!isdigit(*isa))
+                               break;
+
+                       while (isdigit(*++isa))
+                               ;
+
+                       if (tolower(*isa) != 'p')
+                               break;
+
+                       if (!isdigit(*++isa)) {
+                               --isa;
+                               break;
+                       }
+
+                       while (isdigit(*++isa))
+                               ;
+
+                       break;
+               }
+
+               /*
+                * The parser expects that at the start of an iteration isa points to the
+                * first character of the next extension. As we stop parsing an extension
+                * on meeting a non-alphanumeric character, an extra increment is needed
+                * where the succeeding extension is a multi-letter prefixed with an "_".
+                */
+               if (*isa == '_')
+                       ++isa;
+
+#define SET_ISA_EXT_MAP(name, bit)                                             \
+               do {                                                            \
+                       if ((ext_end - ext == strlen(name)) &&                  \
+                            !strncasecmp(ext, name, strlen(name)) &&           \
+                            riscv_isa_extension_check(bit))                    \
+                               set_bit(bit, isainfo->isa);                     \
+               } while (false)                                                 \
+
+               if (unlikely(ext_err))
+                       continue;
+               if (!ext_long) {
+                       int nr = tolower(*ext) - 'a';
+
+                       if (riscv_isa_extension_check(nr)) {
+                               *this_hwcap |= isa2hwcap[nr];
+                               set_bit(nr, isainfo->isa);
+                       }
+               } else {
+                       for (int i = 0; i < riscv_isa_ext_count; i++)
+                               SET_ISA_EXT_MAP(riscv_isa_ext[i].name,
+                                               riscv_isa_ext[i].id);
+               }
+#undef SET_ISA_EXT_MAP
+       }
+}
+
+static void __init riscv_fill_hwcap_from_isa_string(unsigned long *isa2hwcap)
 {
        struct device_node *node;
        const char *isa;
-       char print_str[NUM_ALPHA_EXTS + 1];
-       int i, j, rc;
-       unsigned long isa2hwcap[26] = {0};
+       int rc;
        struct acpi_table_header *rhct;
        acpi_status status;
        unsigned int cpu;
 
-       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;
-       isa2hwcap['v' - 'a'] = COMPAT_HWCAP_ISA_V;
-
-       elf_hwcap = 0;
-
-       bitmap_zero(riscv_isa, RISCV_ISA_EXT_MAX);
-
        if (!acpi_disabled) {
                status = acpi_get_table(ACPI_SIG_RHCT, 0, &rhct);
                if (ACPI_FAILURE(status))
@@ -160,176 +382,7 @@ void __init riscv_fill_hwcap(void)
                        }
                }
 
-               /*
-                * For all possible cpus, we have already validated in
-                * the boot process that they at least contain "rv" and
-                * whichever of "32"/"64" this kernel supports, and so this
-                * section can be skipped.
-                */
-               isa += 4;
-
-               while (*isa) {
-                       const char *ext = isa++;
-                       const char *ext_end = isa;
-                       bool ext_long = false, ext_err = false;
-
-                       switch (*ext) {
-                       case 's':
-                               /*
-                                * Workaround for invalid single-letter 's' & 'u'(QEMU).
-                                * No need to set the bit in riscv_isa as 's' & 'u' are
-                                * not valid ISA extensions. It works until multi-letter
-                                * extension starting with "Su" appears.
-                                */
-                               if (ext[-1] != '_' && ext[1] == 'u') {
-                                       ++isa;
-                                       ext_err = true;
-                                       break;
-                               }
-                               fallthrough;
-                       case 'S':
-                       case 'x':
-                       case 'X':
-                       case 'z':
-                       case 'Z':
-                               /*
-                                * Before attempting to parse the extension itself, we find its end.
-                                * As multi-letter extensions must be split from other multi-letter
-                                * extensions with an "_", the end of a multi-letter extension will
-                                * either be the null character or the "_" at the start of the next
-                                * multi-letter extension.
-                                *
-                                * Next, as the extensions version is currently ignored, we
-                                * eliminate that portion. This is done by parsing backwards from
-                                * the end of the extension, removing any numbers. This may be a
-                                * major or minor number however, so the process is repeated if a
-                                * minor number was found.
-                                *
-                                * ext_end is intended to represent the first character *after* the
-                                * name portion of an extension, but will be decremented to the last
-                                * character itself while eliminating the extensions version number.
-                                * A simple re-increment solves this problem.
-                                */
-                               ext_long = true;
-                               for (; *isa && *isa != '_'; ++isa)
-                                       if (unlikely(!isalnum(*isa)))
-                                               ext_err = true;
-
-                               ext_end = isa;
-                               if (unlikely(ext_err))
-                                       break;
-
-                               if (!isdigit(ext_end[-1]))
-                                       break;
-
-                               while (isdigit(*--ext_end))
-                                       ;
-
-                               if (tolower(ext_end[0]) != 'p' || !isdigit(ext_end[-1])) {
-                                       ++ext_end;
-                                       break;
-                               }
-
-                               while (isdigit(*--ext_end))
-                                       ;
-
-                               ++ext_end;
-                               break;
-                       default:
-                               /*
-                                * Things are a little easier for single-letter extensions, as they
-                                * are parsed forwards.
-                                *
-                                * After checking that our starting position is valid, we need to
-                                * ensure that, when isa was incremented at the start of the loop,
-                                * that it arrived at the start of the next extension.
-                                *
-                                * If we are already on a non-digit, there is nothing to do. Either
-                                * we have a multi-letter extension's _, or the start of an
-                                * extension.
-                                *
-                                * Otherwise we have found the current extension's major version
-                                * number. Parse past it, and a subsequent p/minor version number
-                                * if present. The `p` extension must not appear immediately after
-                                * a number, so there is no fear of missing it.
-                                *
-                                */
-                               if (unlikely(!isalpha(*ext))) {
-                                       ext_err = true;
-                                       break;
-                               }
-
-                               if (!isdigit(*isa))
-                                       break;
-
-                               while (isdigit(*++isa))
-                                       ;
-
-                               if (tolower(*isa) != 'p')
-                                       break;
-
-                               if (!isdigit(*++isa)) {
-                                       --isa;
-                                       break;
-                               }
-
-                               while (isdigit(*++isa))
-                                       ;
-
-                               break;
-                       }
-
-                       /*
-                        * The parser expects that at the start of an iteration isa points to the
-                        * first character of the next extension. As we stop parsing an extension
-                        * on meeting a non-alphanumeric character, an extra increment is needed
-                        * where the succeeding extension is a multi-letter prefixed with an "_".
-                        */
-                       if (*isa == '_')
-                               ++isa;
-
-#define SET_ISA_EXT_MAP(name, bit)                                                     \
-                       do {                                                            \
-                               if ((ext_end - ext == sizeof(name) - 1) &&              \
-                                    !strncasecmp(ext, name, sizeof(name) - 1) &&       \
-                                    riscv_isa_extension_check(bit))                    \
-                                       set_bit(bit, isainfo->isa);                     \
-                       } while (false)                                                 \
-
-                       if (unlikely(ext_err))
-                               continue;
-                       if (!ext_long) {
-                               int nr = tolower(*ext) - 'a';
-
-                               if (riscv_isa_extension_check(nr)) {
-                                       this_hwcap |= isa2hwcap[nr];
-                                       set_bit(nr, isainfo->isa);
-                               }
-                       } else {
-                               /* sorted alphabetically */
-                               SET_ISA_EXT_MAP("smaia", RISCV_ISA_EXT_SMAIA);
-                               SET_ISA_EXT_MAP("ssaia", RISCV_ISA_EXT_SSAIA);
-                               SET_ISA_EXT_MAP("sscofpmf", RISCV_ISA_EXT_SSCOFPMF);
-                               SET_ISA_EXT_MAP("sstc", RISCV_ISA_EXT_SSTC);
-                               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);
-                       }
-#undef SET_ISA_EXT_MAP
-               }
-
-               /*
-                * Linux requires the following extensions, so we may as well
-                * always set them.
-                */
-               set_bit(RISCV_ISA_EXT_ZICSR, isainfo->isa);
-               set_bit(RISCV_ISA_EXT_ZIFENCEI, isainfo->isa);
+               riscv_parse_isa_string(&this_hwcap, isainfo, isa2hwcap, isa);
 
                /*
                 * These ones were as they were part of the base ISA when the
@@ -337,6 +390,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_ZICSR, isainfo->isa);
+                       set_bit(RISCV_ISA_EXT_ZIFENCEI, isainfo->isa);
                        set_bit(RISCV_ISA_EXT_ZICNTR, isainfo->isa);
                        set_bit(RISCV_ISA_EXT_ZIHPM, isainfo->isa);
                }
@@ -359,9 +414,107 @@ void __init riscv_fill_hwcap(void)
 
        if (!acpi_disabled && rhct)
                acpi_put_table((struct acpi_table_header *)rhct);
+}
+
+static int __init riscv_fill_hwcap_from_ext_list(unsigned long *isa2hwcap)
+{
+       unsigned int cpu;
+
+       for_each_possible_cpu(cpu) {
+               unsigned long this_hwcap = 0;
+               struct device_node *cpu_node;
+               struct riscv_isainfo *isainfo = &hart_isa[cpu];
+
+               cpu_node = of_cpu_device_node_get(cpu);
+               if (!cpu_node) {
+                       pr_warn("Unable to find cpu node\n");
+                       continue;
+               }
+
+               if (!of_property_present(cpu_node, "riscv,isa-extensions")) {
+                       of_node_put(cpu_node);
+                       continue;
+               }
+
+               for (int i = 0; i < riscv_isa_ext_count; i++) {
+                       if (of_property_match_string(cpu_node, "riscv,isa-extensions",
+                                                    riscv_isa_ext[i].property) < 0)
+                               continue;
+
+                       if (!riscv_isa_extension_check(riscv_isa_ext[i].id))
+                               continue;
+
+                       /* Only single letter extensions get set in hwcap */
+                       if (strnlen(riscv_isa_ext[i].name, 2) == 1)
+                               this_hwcap |= isa2hwcap[riscv_isa_ext[i].id];
+
+                       set_bit(riscv_isa_ext[i].id, isainfo->isa);
+               }
 
-       /* We don't support systems with F but without D, so mask those out
-        * here. */
+               of_node_put(cpu_node);
+
+               /*
+                * All "okay" harts should have same isa. Set HWCAP based on
+                * common capabilities of every "okay" hart, in case they don't.
+                */
+               if (elf_hwcap)
+                       elf_hwcap &= this_hwcap;
+               else
+                       elf_hwcap = this_hwcap;
+
+               if (bitmap_empty(riscv_isa, RISCV_ISA_EXT_MAX))
+                       bitmap_copy(riscv_isa, isainfo->isa, RISCV_ISA_EXT_MAX);
+               else
+                       bitmap_and(riscv_isa, riscv_isa, isainfo->isa, RISCV_ISA_EXT_MAX);
+       }
+
+       if (bitmap_empty(riscv_isa, RISCV_ISA_EXT_MAX))
+               return -ENOENT;
+
+       return 0;
+}
+
+#ifdef CONFIG_RISCV_ISA_FALLBACK
+bool __initdata riscv_isa_fallback = true;
+#else
+bool __initdata riscv_isa_fallback;
+static int __init riscv_isa_fallback_setup(char *__unused)
+{
+       riscv_isa_fallback = true;
+       return 1;
+}
+early_param("riscv_isa_fallback", riscv_isa_fallback_setup);
+#endif
+
+void __init riscv_fill_hwcap(void)
+{
+       char print_str[NUM_ALPHA_EXTS + 1];
+       unsigned long isa2hwcap[26] = {0};
+       int i, j;
+
+       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;
+       isa2hwcap['v' - 'a'] = COMPAT_HWCAP_ISA_V;
+
+       if (!acpi_disabled) {
+               riscv_fill_hwcap_from_isa_string(isa2hwcap);
+       } else {
+               int ret = riscv_fill_hwcap_from_ext_list(isa2hwcap);
+
+               if (ret && riscv_isa_fallback) {
+                       pr_info("Falling back to deprecated \"riscv,isa\"\n");
+                       riscv_fill_hwcap_from_isa_string(isa2hwcap);
+               }
+       }
+
+       /*
+        * We don't support systems with F but without D, so mask those out
+        * here.
+        */
        if ((elf_hwcap & COMPAT_HWCAP_ISA_F) && !(elf_hwcap & COMPAT_HWCAP_ISA_D)) {
                pr_info("This kernel does not support systems with F but not D\n");
                elf_hwcap &= ~COMPAT_HWCAP_ISA_F;