Add a new hwprobe key "RISCV_HWPROBE_KEY_VENDOR_EXT_0" which allows userspace to probe for the new RISCV_ISA_VENDOR_EXT_XTHEADVECTOR vendor extension.
Signed-off-by: Charlie Jenkins charlie@rivosinc.com --- arch/riscv/include/asm/hwprobe.h | 4 +-- arch/riscv/include/uapi/asm/hwprobe.h | 10 +++++- arch/riscv/kernel/sys_hwprobe.c | 59 +++++++++++++++++++++++++++++++++-- 3 files changed, 68 insertions(+), 5 deletions(-)
diff --git a/arch/riscv/include/asm/hwprobe.h b/arch/riscv/include/asm/hwprobe.h index 630507dff5ea..e68496b4f8de 100644 --- a/arch/riscv/include/asm/hwprobe.h +++ b/arch/riscv/include/asm/hwprobe.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ /* - * Copyright 2023 Rivos, Inc + * Copyright 2023-2024 Rivos, Inc */
#ifndef _ASM_HWPROBE_H @@ -8,7 +8,7 @@
#include <uapi/asm/hwprobe.h>
-#define RISCV_HWPROBE_MAX_KEY 6 +#define RISCV_HWPROBE_MAX_KEY 7
static inline bool riscv_hwprobe_key_is_valid(__s64 key) { diff --git a/arch/riscv/include/uapi/asm/hwprobe.h b/arch/riscv/include/uapi/asm/hwprobe.h index 9f2a8e3ff204..6614d3adfc75 100644 --- a/arch/riscv/include/uapi/asm/hwprobe.h +++ b/arch/riscv/include/uapi/asm/hwprobe.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ /* - * Copyright 2023 Rivos, Inc + * Copyright 2023-2024 Rivos, Inc */
#ifndef _UAPI_ASM_HWPROBE_H @@ -67,6 +67,14 @@ struct riscv_hwprobe { #define RISCV_HWPROBE_MISALIGNED_UNSUPPORTED (4 << 0) #define RISCV_HWPROBE_MISALIGNED_MASK (7 << 0) #define RISCV_HWPROBE_KEY_ZICBOZ_BLOCK_SIZE 6 +/* + * It is not possible for one CPU to have multiple vendor ids, so each vendor + * has its own vendor extension "namespace". The keys for each vendor starts + * at zero. + */ +#define RISCV_HWPROBE_KEY_VENDOR_EXT_0 7 + /* T-Head */ +#define RISCV_HWPROBE_VENDOR_EXT_XTHEADVECTOR (1 << 0) /* Increase RISCV_HWPROBE_MAX_KEY when adding items. */
/* Flags */ diff --git a/arch/riscv/kernel/sys_hwprobe.c b/arch/riscv/kernel/sys_hwprobe.c index e0a42c851511..365ce7380443 100644 --- a/arch/riscv/kernel/sys_hwprobe.c +++ b/arch/riscv/kernel/sys_hwprobe.c @@ -69,7 +69,8 @@ static void hwprobe_isa_ext0(struct riscv_hwprobe *pair, if (riscv_isa_extension_available(NULL, c)) pair->value |= RISCV_HWPROBE_IMA_C;
- if (has_vector() && !riscv_has_vendor_extension_unlikely(RISCV_ISA_VENDOR_EXT_XTHEADVECTOR)) + if (has_vector() && + !__riscv_isa_vendor_extension_available(NULL, RISCV_ISA_VENDOR_EXT_XTHEADVECTOR)) pair->value |= RISCV_HWPROBE_IMA_V;
/* @@ -112,7 +113,8 @@ static void hwprobe_isa_ext0(struct riscv_hwprobe *pair, EXT_KEY(ZACAS); EXT_KEY(ZICOND);
- if (has_vector() && !riscv_has_vendor_extension_unlikely(RISCV_ISA_VENDOR_EXT_XTHEADVECTOR)) { + if (has_vector() && + !riscv_has_vendor_extension_unlikely(RISCV_ISA_VENDOR_EXT_XTHEADVECTOR)) { EXT_KEY(ZVBB); EXT_KEY(ZVBC); EXT_KEY(ZVKB); @@ -139,6 +141,55 @@ static void hwprobe_isa_ext0(struct riscv_hwprobe *pair, pair->value &= ~missing; }
+static void hwprobe_isa_vendor_ext0(struct riscv_hwprobe *pair, + const struct cpumask *cpus) +{ + int cpu; + u64 missing = 0; + + pair->value = 0; + + struct riscv_hwprobe mvendorid = { + .key = RISCV_HWPROBE_KEY_MVENDORID, + .value = 0 + }; + + hwprobe_arch_id(&mvendorid, cpus); + + /* Set value to zero if CPUs in the set do not have the same vendor. */ + if (mvendorid.value == -1ULL) + return; + + /* + * Loop through and record vendor extensions that 1) anyone has, and + * 2) anyone doesn't have. + */ + for_each_cpu(cpu, cpus) { + struct riscv_isainfo *isavendorinfo = &hart_isa_vendor[cpu]; + +#define VENDOR_EXT_KEY(ext) \ + do { \ + if (__riscv_isa_vendor_extension_available(isavendorinfo->isa, \ + RISCV_ISA_VENDOR_EXT_##ext)) \ + pair->value |= RISCV_HWPROBE_VENDOR_EXT_##ext; \ + else \ + missing |= RISCV_HWPROBE_VENDOR_EXT_##ext; \ + } while (false) + + /* + * Only use VENDOR_EXT_KEY() for extensions which can be exposed to userspace, + * regardless of the kernel's configuration, as no other checks, besides + * presence in the hart_vendor_isa bitmap, are made. + */ + VENDOR_EXT_KEY(XTHEADVECTOR); + +#undef VENDOR_EXT_KEY + } + + /* Now turn off reporting features if any CPU is missing it. */ + pair->value &= ~missing; +} + static bool hwprobe_ext0_has(const struct cpumask *cpus, unsigned long ext) { struct riscv_hwprobe pair; @@ -216,6 +267,10 @@ static void hwprobe_one_pair(struct riscv_hwprobe *pair, pair->value = riscv_cboz_block_size; break;
+ case RISCV_HWPROBE_KEY_VENDOR_EXT_0: + hwprobe_isa_vendor_ext0(pair, cpus); + break; + /* * For forward compatibility, unknown keys don't fail the whole * call, but get their element key set to -1 and value set to 0