]> Git Repo - J-linux.git/commitdiff
Merge patch series "Putting some basic order on isa extension lists"
authorPalmer Dabbelt <[email protected]>
Fri, 20 Jan 2023 00:39:53 +0000 (16:39 -0800)
committerPalmer Dabbelt <[email protected]>
Fri, 20 Jan 2023 00:41:04 +0000 (16:41 -0800)
This cleans up the ISA string handling to more closely match a version
of the ISA spec.  This is visible in /proc/cpuinfo and the ordering
changes may break something in userspace, but these orderings have
changed before without issues so with any luck that's still the case.

This also adds documentation so userspace has a better idea of what is
intended when it comes to compatibility for /proc/cpuinfo, which should
help everyone as this will likely keep changing.

* b4-shazam-merge:
  Documentation: riscv: add a section about ISA string ordering in /proc/cpuinfo
  RISC-V: resort all extensions in consistent orders
  RISC-V: clarify ISA string ordering rules in cpu.c

Link: https://lore.kernel.org/r/[email protected]
Signed-off-by: Palmer Dabbelt <[email protected]>
1  2 
arch/riscv/include/asm/hwcap.h
arch/riscv/kernel/cpu.c
arch/riscv/kernel/cpufeature.c

index 86328e3acb02ee3b5752642039c2cdd2806989a1,ce522aad641a2cdbba3a2faa50fcedabd1eea6be..57439da71c775aba08fb419ca23e14264ff4364e
@@@ -51,27 -51,28 +51,29 @@@ extern unsigned long elf_hwcap
   * RISCV_ISA_EXT_MAX. 0-25 range is reserved for single letter
   * extensions while all the multi-letter extensions should define the next
   * available logical extension id.
+  * Entries are sorted alphabetically.
   */
  enum riscv_isa_ext_id {
        RISCV_ISA_EXT_SSCOFPMF = RISCV_ISA_EXT_BASE,
+       RISCV_ISA_EXT_SSTC,
+       RISCV_ISA_EXT_SVINVAL,
        RISCV_ISA_EXT_SVPBMT,
        RISCV_ISA_EXT_ZICBOM,
        RISCV_ISA_EXT_ZIHINTPAUSE,
-       RISCV_ISA_EXT_SSTC,
-       RISCV_ISA_EXT_SVINVAL,
 -      RISCV_ISA_EXT_ID_MAX = RISCV_ISA_EXT_MAX,
 +      RISCV_ISA_EXT_ID_MAX
  };
 +static_assert(RISCV_ISA_EXT_ID_MAX <= RISCV_ISA_EXT_MAX);
  
  /*
   * This enum represents the logical ID for each RISC-V ISA extension static
   * keys. We can use static key to optimize code path if some ISA extensions
   * are available.
+  * Entries are sorted alphabetically.
   */
  enum riscv_isa_ext_key {
        RISCV_ISA_EXT_KEY_FPU,          /* For 'F' and 'D' */
-       RISCV_ISA_EXT_KEY_ZIHINTPAUSE,
        RISCV_ISA_EXT_KEY_SVINVAL,
+       RISCV_ISA_EXT_KEY_ZIHINTPAUSE,
        RISCV_ISA_EXT_KEY_MAX,
  };
  
@@@ -91,10 -92,10 +93,10 @@@ static __always_inline int riscv_isa_ex
                return RISCV_ISA_EXT_KEY_FPU;
        case RISCV_ISA_EXT_d:
                return RISCV_ISA_EXT_KEY_FPU;
-       case RISCV_ISA_EXT_ZIHINTPAUSE:
-               return RISCV_ISA_EXT_KEY_ZIHINTPAUSE;
        case RISCV_ISA_EXT_SVINVAL:
                return RISCV_ISA_EXT_KEY_SVINVAL;
+       case RISCV_ISA_EXT_ZIHINTPAUSE:
+               return RISCV_ISA_EXT_KEY_ZIHINTPAUSE;
        default:
                return -EINVAL;
        }
diff --combined arch/riscv/kernel/cpu.c
index 1b9a5a66e55ab8eb0bbd7c228565674bd8b91569,b8127bfc8f0fdb093f67235277ab76c1667c3521..0bf1c7f663fc6206cd983856477025527e914bf9
@@@ -70,6 -70,8 +70,6 @@@ int riscv_of_parent_hartid(struct devic
        return -1;
  }
  
 -#ifdef CONFIG_PROC_FS
 -
  struct riscv_cpuinfo {
        unsigned long mvendorid;
        unsigned long marchid;
  };
  static DEFINE_PER_CPU(struct riscv_cpuinfo, riscv_cpuinfo);
  
 +unsigned long riscv_cached_mvendorid(unsigned int cpu_id)
 +{
 +      struct riscv_cpuinfo *ci = per_cpu_ptr(&riscv_cpuinfo, cpu_id);
 +
 +      return ci->mvendorid;
 +}
 +EXPORT_SYMBOL(riscv_cached_mvendorid);
 +
 +unsigned long riscv_cached_marchid(unsigned int cpu_id)
 +{
 +      struct riscv_cpuinfo *ci = per_cpu_ptr(&riscv_cpuinfo, cpu_id);
 +
 +      return ci->marchid;
 +}
 +EXPORT_SYMBOL(riscv_cached_marchid);
 +
 +unsigned long riscv_cached_mimpid(unsigned int cpu_id)
 +{
 +      struct riscv_cpuinfo *ci = per_cpu_ptr(&riscv_cpuinfo, cpu_id);
 +
 +      return ci->mimpid;
 +}
 +EXPORT_SYMBOL(riscv_cached_mimpid);
 +
  static int riscv_cpuinfo_starting(unsigned int cpu)
  {
        struct riscv_cpuinfo *ci = this_cpu_ptr(&riscv_cpuinfo);
@@@ -135,39 -113,60 +135,62 @@@ static int __init riscv_cpuinfo_init(vo
  
        return 0;
  }
 -device_initcall(riscv_cpuinfo_init);
 +arch_initcall(riscv_cpuinfo_init);
 +
 +#ifdef CONFIG_PROC_FS
  
  #define __RISCV_ISA_EXT_DATA(UPROP, EXTID) \
        {                                                       \
                .uprop = #UPROP,                                \
                .isa_ext_id = EXTID,                            \
        }
  /*
-  * Here are the ordering rules of extension naming defined by RISC-V
-  * specification :
-  * 1. All extensions should be separated from other multi-letter extensions
-  *    by an underscore.
-  * 2. The first letter following the 'Z' conventionally indicates the most
+  * 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 should be ordered first
-  *    by category, then alphabetically within a category.
-  * 3. Standard supervisor-level extensions (starts with 'S') should be
-  *    listed after standard unprivileged extensions.  If multiple
-  *    supervisor-level extensions are listed, they should be ordered
+  *    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.
-  * 4. Non-standard extensions (starts with 'X') must be listed after all
-  *    standard extensions. They must be separated from other multi-letter
-  *    extensions by an underscore.
+  *
+  * 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.
   */
  static struct riscv_isa_ext_data isa_ext_arr[] = {
+       __RISCV_ISA_EXT_DATA(zicbom, RISCV_ISA_EXT_ZICBOM),
+       __RISCV_ISA_EXT_DATA(zihintpause, RISCV_ISA_EXT_ZIHINTPAUSE),
        __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(svpbmt, RISCV_ISA_EXT_SVPBMT),
-       __RISCV_ISA_EXT_DATA(zicbom, RISCV_ISA_EXT_ZICBOM),
-       __RISCV_ISA_EXT_DATA(zihintpause, RISCV_ISA_EXT_ZIHINTPAUSE),
        __RISCV_ISA_EXT_DATA("", RISCV_ISA_EXT_MAX),
  };
  
@@@ -237,9 -236,6 +260,9 @@@ static void print_mmu(struct seq_file *
  
  static void *c_start(struct seq_file *m, loff_t *pos)
  {
 +      if (*pos == nr_cpu_ids)
 +              return NULL;
 +
        *pos = cpumask_next(*pos - 1, cpu_online_mask);
        if ((*pos) < nr_cpu_ids)
                return (void *)(uintptr_t)(1 + *pos);
index 205bbd6b1fce0b57f3a500a1853b7b2f0bae6726,8a76a6ce70cf33d1db94a96f0a93c8d123be6e36..dde0e91d766887880d2870732705f0bd939b20dc
@@@ -9,7 -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>
@@@ -69,38 -68,21 +69,38 @@@ bool __riscv_isa_extension_available(co
  }
  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;
  
  #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);
+                               SET_ISA_EXT_MAP("sstc", RISCV_ISA_EXT_SSTC);
+                               SET_ISA_EXT_MAP("svinval", RISCV_ISA_EXT_SVINVAL);
                                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);
-                               SET_ISA_EXT_MAP("svinval", RISCV_ISA_EXT_SVINVAL);
                        }
  #undef SET_ISA_EXT_MAP
                }
@@@ -307,6 -285,7 +308,7 @@@ static bool __init_or_module cpufeature
   * 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.
+  * Tests, unless otherwise required, are to be added in alphabetical order.
   */
  static u32 __init_or_module cpufeature_probe(unsigned int stage)
  {
@@@ -339,11 -318,8 +341,11 @@@ void __init_or_module riscv_cpufeature_
                }
  
                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
This page took 0.072803 seconds and 4 git commands to generate.