Merge patch series "RISC-V: Export Zba, Zbb to usermode via hwprobe"
authorPalmer Dabbelt <palmer@rivosinc.com>
Mon, 19 Jun 2023 21:34:40 +0000 (14:34 -0700)
committerPalmer Dabbelt <palmer@rivosinc.com>
Mon, 19 Jun 2023 21:34:40 +0000 (14:34 -0700)
Evan Green <evan@rivosinc.com> says:

This change detects the presence of Zba, Zbb, and Zbs extensions and exports
them per-hart to userspace via the hwprobe mechanism. Glibc can then use
these in setting up hwcaps-based library search paths.

There's a little bit of extra housekeeping here: the first change adds
Zba and Zbs to the set of extensions the kernel recognizes, and the second
change starts tracking ISA features per-hart (in addition to the ANDed
mask of features across all harts which the kernel uses to make
decisions). Now that we track the ISA information per-hart, we could
even fix up /proc/cpuinfo to accurately report extension per-hart,
though I've left that out of this series for now.

* b4-shazam-merge:
  RISC-V: hwprobe: Expose Zba, Zbb, and Zbs
  RISC-V: Track ISA extensions per hart
  RISC-V: Add Zba, Zbs extension probing

Link: https://lore.kernel.org/r/20230509182504.2997252-1-evan@rivosinc.com
Signed-off-by: Palmer Dabbelt <palmer@rivosinc.com>
1  2 
Documentation/riscv/hwprobe.rst
arch/riscv/include/asm/hwcap.h
arch/riscv/include/uapi/asm/hwprobe.h
arch/riscv/kernel/cpu.c
arch/riscv/kernel/cpufeature.c
arch/riscv/kernel/sys_riscv.c

index 7431d9d01c73fa8fb0792faba917b73dc37eec29,fb25670ef0e5c5df91cacb27192d4343cba69573..19165ebd82baf8f3dcdff2861738bf2a99c811aa
@@@ -64,9 -64,16 +64,19 @@@ The following keys are defined
    * :c:macro:`RISCV_HWPROBE_IMA_C`: The C extension is supported, as defined
      by version 2.2 of the RISC-V ISA manual.
  
 +  * :c:macro:`RISCV_HWPROBE_IMA_V`: The V extension is supported, as defined by
 +    version 1.0 of the RISC-V Vector extension manual.
 +
+   * :c:macro:`RISCV_HWPROBE_EXT_ZBA`: The Zba address generation extension is
+        supported, as defined in version 1.0 of the Bit-Manipulation ISA
+        extensions.
+   * :c:macro:`RISCV_HWPROBE_EXT_ZBB`: The Zbb extension is supported, as defined
+        in version 1.0 of the Bit-Manipulation ISA extensions.
+   * :c:macro:`RISCV_HWPROBE_EXT_ZBS`: The Zbs extension is supported, as defined
+        in version 1.0 of the Bit-Manipulation ISA extensions.
  * :c:macro:`RISCV_HWPROBE_KEY_CPUPERF_0`: A bitmask that contains performance
    information about the selected set of processors.
  
Simple merge
index 7c6fdcf7ced528aeb7ccbd72c21caaaacc760312,853f8f6d9a42032b17210a82aed2205b7979383f..006bfb48343dd423d5ddd04fb38a73043318e2e1
@@@ -25,7 -25,9 +25,10 @@@ struct riscv_hwprobe 
  #define RISCV_HWPROBE_KEY_IMA_EXT_0   4
  #define               RISCV_HWPROBE_IMA_FD            (1 << 0)
  #define               RISCV_HWPROBE_IMA_C             (1 << 1)
 -#define               RISCV_HWPROBE_EXT_ZBA           (1 << 2)
 -#define               RISCV_HWPROBE_EXT_ZBB           (1 << 3)
 -#define               RISCV_HWPROBE_EXT_ZBS           (1 << 4)
 +#define               RISCV_HWPROBE_IMA_V             (1 << 2)
++#define               RISCV_HWPROBE_EXT_ZBA           (1 << 3)
++#define               RISCV_HWPROBE_EXT_ZBB           (1 << 4)
++#define               RISCV_HWPROBE_EXT_ZBS           (1 << 5)
  #define RISCV_HWPROBE_KEY_CPUPERF_0   5
  #define               RISCV_HWPROBE_MISALIGNED_UNKNOWN        (0 << 0)
  #define               RISCV_HWPROBE_MISALIGNED_EMULATED       (1 << 0)
Simple merge
index d1e9e879f5772b09463a6b2aaccccb75c51e8cbf,e8b7b4b20bb512997cad4dec0814ea61a0c5f22b..f8dc577fc912e0e5e28f8b701c1b397a25136c44
@@@ -119,36 -115,22 +122,36 @@@ void __init riscv_fill_hwcap(void
  
        bitmap_zero(riscv_isa, RISCV_ISA_EXT_MAX);
  
 -      for_each_of_cpu_node(node) {
 -              struct riscv_isainfo *isainfo;
 +      if (!acpi_disabled) {
 +              status = acpi_get_table(ACPI_SIG_RHCT, 0, &rhct);
 +              if (ACPI_FAILURE(status))
 +                      return;
 +      }
 +
 +      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);
                const char *temp;
 -              unsigned int cpu_id;
 -
 -              rc = riscv_of_processor_hartid(node, &hartid);
 -              if (rc < 0)
 -                      continue;
  
 -              cpu_id = riscv_hartid_to_cpuid(hartid);
 -              isainfo = &hart_isa[cpu_id];
 +              if (acpi_disabled) {
 +                      node = of_cpu_device_node_get(cpu);
 +                      if (!node) {
 +                              pr_warn("Unable to find cpu node\n");
 +                              continue;
 +                      }
  
 -              if (of_property_read_string(node, "riscv,isa", &isa)) {
 -                      pr_warn("Unable to find \"riscv,isa\" devicetree entry\n");
 -                      continue;
 +                      rc = of_property_read_string(node, "riscv,isa", &isa);
 +                      of_node_put(node);
 +                      if (rc) {
 +                              pr_warn("Unable to find \"riscv,isa\" devicetree entry\n");
 +                              continue;
 +                      }
 +              } else {
 +                      rc = acpi_get_riscv_isa(rhct, cpu, &isa);
 +                      if (rc < 0) {
 +                              pr_warn("Unable to get ISA for the hart - %d\n", cpu);
 +                              continue;
 +                      }
                }
  
                temp = isa;
                        if (*isa != '_')
                                --isa;
  
 -#define SET_ISA_EXT_MAP(name, bit)                                            \
 -                      do {                                                    \
 -                              if ((ext_end - ext == sizeof(name) - 1) &&      \
 -                                   !memcmp(ext, name, sizeof(name) - 1) &&    \
 -                                   riscv_isa_extension_check(bit))            \
 -                                      set_bit(bit, isainfo->isa);             \
 -                      } while (false)                                         \
 +#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, this_isa);                         \
++                                      set_bit(bit, isainfo->isa);                     \
 +                      } while (false)                                                 \
  
                        if (unlikely(ext_err))
                                continue;
                        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)
 +              acpi_put_table((struct acpi_table_header *)rhct);
 +
        /* 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)) {
index 88357a8487975a747dab32ca016f979fab6c0a60,fe655db19ab4719b305ee5dd38befce7a6c736d0..26ef5526bfb4cc45e57096b536b75e5bb3116600
@@@ -122,6 -121,46 +122,49 @@@ static void hwprobe_arch_id(struct risc
        pair->value = id;
  }
  
+ static void hwprobe_isa_ext0(struct riscv_hwprobe *pair,
+                            const struct cpumask *cpus)
+ {
+       int cpu;
+       u64 missing = 0;
+       pair->value = 0;
+       if (has_fpu())
+               pair->value |= RISCV_HWPROBE_IMA_FD;
+       if (riscv_isa_extension_available(NULL, c))
+               pair->value |= RISCV_HWPROBE_IMA_C;
++      if (has_vector())
++              pair->value |= RISCV_HWPROBE_IMA_V;
++
+       /*
+        * Loop through and record extensions that 1) anyone has, and 2) anyone
+        * doesn't have.
+        */
+       for_each_cpu(cpu, cpus) {
+               struct riscv_isainfo *isainfo = &hart_isa[cpu];
+               if (riscv_isa_extension_available(isainfo->isa, ZBA))
+                       pair->value |= RISCV_HWPROBE_EXT_ZBA;
+               else
+                       missing |= RISCV_HWPROBE_EXT_ZBA;
+               if (riscv_isa_extension_available(isainfo->isa, ZBB))
+                       pair->value |= RISCV_HWPROBE_EXT_ZBB;
+               else
+                       missing |= RISCV_HWPROBE_EXT_ZBB;
+               if (riscv_isa_extension_available(isainfo->isa, ZBS))
+                       pair->value |= RISCV_HWPROBE_EXT_ZBS;
+               else
+                       missing |= RISCV_HWPROBE_EXT_ZBS;
+       }
+       /* Now turn off reporting features if any CPU is missing it. */
+       pair->value &= ~missing;
+ }
  static u64 hwprobe_misaligned(const struct cpumask *cpus)
  {
        int cpu;