[PATCH v2 1/4] riscv: Extend cpufeature.c to detect vendor extensions

Andy Chiu andy.chiu at sifive.com
Fri Jun 21 00:37:11 PDT 2024


On Mon, Jun 10, 2024 at 12:34 PM Charlie Jenkins <charlie at rivosinc.com> wrote:
>
> Instead of grouping all vendor extensions into the same riscv_isa_ext
> that standard instructions use, create a struct
> "riscv_isa_vendor_ext_data_list" that allows each vendor to maintain
> their vendor extensions independently of the standard extensions.
> xandespmu is currently the only vendor extension so that is the only
> extension that is affected by this change.
>
> An additional benefit of this is that the extensions of each vendor can
> be conditionally enabled. A config RISCV_ISA_VENDOR_EXT_ANDES has been
> added to allow for that.
>
> Signed-off-by: Charlie Jenkins <charlie at rivosinc.com>

Reviewed-by: Andy Chiu <andy.chiu at sifive.com>

> ---
>  arch/riscv/Kconfig                               |   2 +
>  arch/riscv/Kconfig.vendor                        |  19 ++++
>  arch/riscv/errata/andes/errata.c                 |   3 +
>  arch/riscv/errata/sifive/errata.c                |   3 +
>  arch/riscv/errata/thead/errata.c                 |   3 +
>  arch/riscv/include/asm/cpufeature.h              |  18 +++
>  arch/riscv/include/asm/hwcap.h                   |   1 -
>  arch/riscv/include/asm/vendor_extensions.h       |  49 ++++++++
>  arch/riscv/include/asm/vendor_extensions/andes.h |  19 ++++
>  arch/riscv/kernel/Makefile                       |   2 +
>  arch/riscv/kernel/cpufeature.c                   | 137 +++++++++++++++++------
>  arch/riscv/kernel/vendor_extensions.c            |  56 +++++++++
>  arch/riscv/kernel/vendor_extensions/Makefile     |   3 +
>  arch/riscv/kernel/vendor_extensions/andes.c      |  18 +++
>  drivers/perf/riscv_pmu_sbi.c                     |  10 +-
>  15 files changed, 306 insertions(+), 37 deletions(-)
>
> diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
> index 0525ee2d63c7..4ae2bf4dd497 100644
> --- a/arch/riscv/Kconfig
> +++ b/arch/riscv/Kconfig
> @@ -774,6 +774,8 @@ config RISCV_EFFICIENT_UNALIGNED_ACCESS
>
>  endchoice
>
> +source "arch/riscv/Kconfig.vendor"
> +
>  endmenu # "Platform type"
>
>  menu "Kernel features"
> diff --git a/arch/riscv/Kconfig.vendor b/arch/riscv/Kconfig.vendor
> new file mode 100644
> index 000000000000..6f1cdd32ed29
> --- /dev/null
> +++ b/arch/riscv/Kconfig.vendor
> @@ -0,0 +1,19 @@
> +menu "Vendor extensions"
> +
> +config RISCV_ISA_VENDOR_EXT
> +       bool
> +
> +menu "Andes"
> +config RISCV_ISA_VENDOR_EXT_ANDES
> +       bool "Andes vendor extension support"
> +       select RISCV_ISA_VENDOR_EXT
> +       default y
> +       help
> +         Say N here if you want to disable all Andes vendor extension
> +         support. This will cause any Andes vendor extensions that are
> +         requested by hardware probing to be ignored.
> +
> +         If you don't know what to do here, say Y.
> +endmenu
> +
> +endmenu
> diff --git a/arch/riscv/errata/andes/errata.c b/arch/riscv/errata/andes/errata.c
> index f2708a9494a1..fc1a34faa5f3 100644
> --- a/arch/riscv/errata/andes/errata.c
> +++ b/arch/riscv/errata/andes/errata.c
> @@ -17,6 +17,7 @@
>  #include <asm/processor.h>
>  #include <asm/sbi.h>
>  #include <asm/vendorid_list.h>
> +#include <asm/vendor_extensions.h>
>
>  #define ANDES_AX45MP_MARCHID           0x8000000000008a45UL
>  #define ANDES_AX45MP_MIMPID            0x500UL
> @@ -65,6 +66,8 @@ void __init_or_module andes_errata_patch_func(struct alt_entry *begin, struct al
>                                               unsigned long archid, unsigned long impid,
>                                               unsigned int stage)
>  {
> +       BUILD_BUG_ON(ERRATA_ANDES_NUMBER >= RISCV_VENDOR_EXT_ALTERNATIVES_BASE);
> +
>         if (stage == RISCV_ALTERNATIVES_BOOT)
>                 errata_probe_iocp(stage, archid, impid);
>
> diff --git a/arch/riscv/errata/sifive/errata.c b/arch/riscv/errata/sifive/errata.c
> index 716cfedad3a2..cea3b96ade11 100644
> --- a/arch/riscv/errata/sifive/errata.c
> +++ b/arch/riscv/errata/sifive/errata.c
> @@ -12,6 +12,7 @@
>  #include <asm/alternative.h>
>  #include <asm/vendorid_list.h>
>  #include <asm/errata_list.h>
> +#include <asm/vendor_extensions.h>
>
>  struct errata_info_t {
>         char name[32];
> @@ -96,6 +97,8 @@ void sifive_errata_patch_func(struct alt_entry *begin, struct alt_entry *end,
>         u32 cpu_apply_errata = 0;
>         u32 tmp;
>
> +       BUILD_BUG_ON(ERRATA_SIFIVE_NUMBER >= RISCV_VENDOR_EXT_ALTERNATIVES_BASE);
> +
>         if (stage == RISCV_ALTERNATIVES_EARLY_BOOT)
>                 return;
>
> diff --git a/arch/riscv/errata/thead/errata.c b/arch/riscv/errata/thead/errata.c
> index bf6a0a6318ee..f5120e07c318 100644
> --- a/arch/riscv/errata/thead/errata.c
> +++ b/arch/riscv/errata/thead/errata.c
> @@ -18,6 +18,7 @@
>  #include <asm/io.h>
>  #include <asm/patch.h>
>  #include <asm/vendorid_list.h>
> +#include <asm/vendor_extensions.h>
>
>  #define CSR_TH_SXSTATUS                0x5c0
>  #define SXSTATUS_MAEE          _AC(0x200000, UL)
> @@ -166,6 +167,8 @@ void thead_errata_patch_func(struct alt_entry *begin, struct alt_entry *end,
>         u32 tmp;
>         void *oldptr, *altptr;
>
> +       BUILD_BUG_ON(ERRATA_THEAD_NUMBER >= RISCV_VENDOR_EXT_ALTERNATIVES_BASE);
> +
>         for (alt = begin; alt < end; alt++) {
>                 if (alt->vendor_id != THEAD_VENDOR_ID)
>                         continue;
> diff --git a/arch/riscv/include/asm/cpufeature.h b/arch/riscv/include/asm/cpufeature.h
> index 347805446151..550d661dc78d 100644
> --- a/arch/riscv/include/asm/cpufeature.h
> +++ b/arch/riscv/include/asm/cpufeature.h
> @@ -33,6 +33,24 @@ extern struct riscv_isainfo hart_isa[NR_CPUS];
>
>  void riscv_user_isa_enable(void);
>
> +#define _RISCV_ISA_EXT_DATA(_name, _id, _subset_exts, _subset_exts_size) {     \
> +       .name = #_name,                                                         \
> +       .property = #_name,                                                     \
> +       .id = _id,                                                              \
> +       .subset_ext_ids = _subset_exts,                                         \
> +       .subset_ext_size = _subset_exts_size                                    \
> +}
> +
> +#define __RISCV_ISA_EXT_DATA(_name, _id) _RISCV_ISA_EXT_DATA(_name, _id, NULL, 0)
> +
> +/* Used to declare pure "lasso" extension (Zk for instance) */
> +#define __RISCV_ISA_EXT_BUNDLE(_name, _bundled_exts) \
> +       _RISCV_ISA_EXT_DATA(_name, RISCV_ISA_EXT_INVALID, _bundled_exts, ARRAY_SIZE(_bundled_exts))
> +
> +/* Used to declare extensions that are a superset of other extensions (Zvbb for instance) */
> +#define __RISCV_ISA_EXT_SUPERSET(_name, _id, _sub_exts) \
> +       _RISCV_ISA_EXT_DATA(_name, _id, _sub_exts, ARRAY_SIZE(_sub_exts))
> +
>  #if defined(CONFIG_RISCV_MISALIGNED)
>  bool check_unaligned_access_emulated_all_cpus(void);
>  void unaligned_emulation_finish(void);
> diff --git a/arch/riscv/include/asm/hwcap.h b/arch/riscv/include/asm/hwcap.h
> index e17d0078a651..1f2d2599c655 100644
> --- a/arch/riscv/include/asm/hwcap.h
> +++ b/arch/riscv/include/asm/hwcap.h
> @@ -80,7 +80,6 @@
>  #define RISCV_ISA_EXT_ZFA              71
>  #define RISCV_ISA_EXT_ZTSO             72
>  #define RISCV_ISA_EXT_ZACAS            73
> -#define RISCV_ISA_EXT_XANDESPMU                74
>
>  #define RISCV_ISA_EXT_XLINUXENVCFG     127
>
> diff --git a/arch/riscv/include/asm/vendor_extensions.h b/arch/riscv/include/asm/vendor_extensions.h
> new file mode 100644
> index 000000000000..5fca550fc1f6
> --- /dev/null
> +++ b/arch/riscv/include/asm/vendor_extensions.h
> @@ -0,0 +1,49 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * Copyright 2024 Rivos, Inc
> + */
> +
> +#ifndef _ASM_VENDOR_EXTENSIONS_H
> +#define _ASM_VENDOR_EXTENSIONS_H
> +
> +#include <asm/cpufeature.h>
> +
> +#include <linux/array_size.h>
> +#include <linux/types.h>
> +
> +/*
> + * The extension keys of each vendor must be strictly less than this value.
> + */
> +#define RISCV_ISA_VENDOR_EXT_MAX 32
> +
> +struct riscv_isavendorinfo {
> +       DECLARE_BITMAP(isa, RISCV_ISA_VENDOR_EXT_MAX);
> +};
> +
> +struct riscv_isa_vendor_ext_data_list {
> +       bool is_initialized;
> +       const size_t ext_data_count;
> +       const struct riscv_isa_ext_data *ext_data;
> +       struct riscv_isavendorinfo per_hart_isa_bitmap[NR_CPUS];
> +       struct riscv_isavendorinfo all_harts_isa_bitmap;
> +};
> +
> +extern struct riscv_isa_vendor_ext_data_list *riscv_isa_vendor_ext_list[];
> +
> +extern const size_t riscv_isa_vendor_ext_list_size;
> +
> +/*
> + * The alternatives need some way of distinguishing between vendor extensions
> + * and errata. Incrementing all of the vendor extension keys so they are at
> + * least 0x8000 accomplishes that.
> + */
> +#define RISCV_VENDOR_EXT_ALTERNATIVES_BASE     0x8000
> +
> +#define VENDOR_EXT_ALL_CPUS                    -1
> +
> +bool __riscv_isa_vendor_extension_available(int cpu, unsigned long vendor, unsigned int bit);
> +#define riscv_isa_vendor_extension_available(vendor, ext)      \
> +       __riscv_isa_vendor_extension_available(VENDOR_EXT_ALL_CPUS, vendor, \
> +                                              RISCV_ISA_VENDOR_EXT_##ext)
> +
> +#endif /* _ASM_VENDOR_EXTENSIONS_H */
> diff --git a/arch/riscv/include/asm/vendor_extensions/andes.h b/arch/riscv/include/asm/vendor_extensions/andes.h
> new file mode 100644
> index 000000000000..7bb2fc43438f
> --- /dev/null
> +++ b/arch/riscv/include/asm/vendor_extensions/andes.h
> @@ -0,0 +1,19 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +#ifndef _ASM_RISCV_VENDOR_EXTENSIONS_ANDES_H
> +#define _ASM_RISCV_VENDOR_EXTENSIONS_ANDES_H
> +
> +#include <asm/vendor_extensions.h>
> +
> +#include <linux/types.h>
> +
> +#define RISCV_ISA_VENDOR_EXT_XANDESPMU         0
> +
> +/*
> + * Extension keys should be strictly less than max.
> + * It is safe to increment this when necessary.
> + */
> +#define RISCV_ISA_VENDOR_EXT_MAX_ANDES                 32
> +
> +extern struct riscv_isa_vendor_ext_data_list riscv_isa_vendor_ext_list_andes;
> +
> +#endif
> diff --git a/arch/riscv/kernel/Makefile b/arch/riscv/kernel/Makefile
> index 5b243d46f4b1..b0aea202273d 100644
> --- a/arch/riscv/kernel/Makefile
> +++ b/arch/riscv/kernel/Makefile
> @@ -58,6 +58,8 @@ obj-y += riscv_ksyms.o
>  obj-y  += stacktrace.o
>  obj-y  += cacheinfo.o
>  obj-y  += patch.o
> +obj-y  += vendor_extensions.o
> +obj-y  += vendor_extensions/
>  obj-y  += probes/
>  obj-y  += tests/
>  obj-$(CONFIG_MMU) += vdso.o vdso/
> diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c
> index 5ef48cb20ee1..f2c24820700b 100644
> --- a/arch/riscv/kernel/cpufeature.c
> +++ b/arch/riscv/kernel/cpufeature.c
> @@ -24,6 +24,7 @@
>  #include <asm/processor.h>
>  #include <asm/sbi.h>
>  #include <asm/vector.h>
> +#include <asm/vendor_extensions.h>
>
>  #define NUM_ALPHA_EXTS ('z' - 'a' + 1)
>
> @@ -100,24 +101,6 @@ static bool riscv_isa_extension_check(int id)
>         return true;
>  }
>
> -#define _RISCV_ISA_EXT_DATA(_name, _id, _subset_exts, _subset_exts_size) {     \
> -       .name = #_name,                                                         \
> -       .property = #_name,                                                     \
> -       .id = _id,                                                              \
> -       .subset_ext_ids = _subset_exts,                                         \
> -       .subset_ext_size = _subset_exts_size                                    \
> -}
> -
> -#define __RISCV_ISA_EXT_DATA(_name, _id) _RISCV_ISA_EXT_DATA(_name, _id, NULL, 0)
> -
> -/* Used to declare pure "lasso" extension (Zk for instance) */
> -#define __RISCV_ISA_EXT_BUNDLE(_name, _bundled_exts) \
> -       _RISCV_ISA_EXT_DATA(_name, RISCV_ISA_EXT_INVALID, _bundled_exts, ARRAY_SIZE(_bundled_exts))
> -
> -/* Used to declare extensions that are a superset of other extensions (Zvbb for instance) */
> -#define __RISCV_ISA_EXT_SUPERSET(_name, _id, _sub_exts) \
> -       _RISCV_ISA_EXT_DATA(_name, _id, _sub_exts, ARRAY_SIZE(_sub_exts))
> -
>  static const unsigned int riscv_zk_bundled_exts[] = {
>         RISCV_ISA_EXT_ZBKB,
>         RISCV_ISA_EXT_ZBKC,
> @@ -304,7 +287,6 @@ const struct riscv_isa_ext_data riscv_isa_ext[] = {
>         __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),
> -       __RISCV_ISA_EXT_DATA(xandespmu, RISCV_ISA_EXT_XANDESPMU),
>  };
>
>  const size_t riscv_isa_ext_count = ARRAY_SIZE(riscv_isa_ext);
> @@ -351,6 +333,21 @@ static void __init riscv_parse_isa_string(unsigned long *this_hwcap, struct risc
>                 bool ext_long = false, ext_err = false;
>
>                 switch (*ext) {
> +               case 'x':
> +               case 'X':
> +                       if (acpi_disabled)
> +                               pr_warn_once("Vendor extensions are ignored in riscv,isa. Use riscv,isa-extensions instead.");
> +                       /*
> +                        * To skip an extension, 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.
> +                        */
> +                       for (; *isa && *isa != '_'; ++isa)
> +                               ;
> +                       ext_err = true;
> +                       break;
>                 case 's':
>                         /*
>                          * Workaround for invalid single-letter 's' & 'u' (QEMU).
> @@ -366,8 +363,6 @@ static void __init riscv_parse_isa_string(unsigned long *this_hwcap, struct risc
>                         }
>                         fallthrough;
>                 case 'S':
> -               case 'x':
> -               case 'X':
>                 case 'z':
>                 case 'Z':
>                         /*
> @@ -574,6 +569,61 @@ static void __init riscv_fill_hwcap_from_isa_string(unsigned long *isa2hwcap)
>                 acpi_put_table((struct acpi_table_header *)rhct);
>  }
>
> +static void __init riscv_fill_cpu_vendor_ext(struct device_node *cpu_node, int cpu)
> +{
> +       if (!IS_ENABLED(CONFIG_RISCV_ISA_VENDOR_EXT))
> +               return;
> +
> +       for (int i = 0; i < riscv_isa_vendor_ext_list_size; i++) {
> +               struct riscv_isa_vendor_ext_data_list *ext_list = riscv_isa_vendor_ext_list[i];
> +
> +               for (int j = 0; j < ext_list->ext_data_count; j++) {
> +                       const struct riscv_isa_ext_data ext = ext_list->ext_data[j];
> +                       struct riscv_isavendorinfo *isavendorinfo = &ext_list->per_hart_isa_bitmap[cpu];
> +
> +                       if (of_property_match_string(cpu_node, "riscv,isa-extensions",
> +                                                    ext.property) < 0)
> +                               continue;
> +
> +                       /*
> +                        * Assume that subset extensions are all members of the
> +                        * same vendor.
> +                        */
> +                       if (ext.subset_ext_size)
> +                               for (int k = 0; k < ext.subset_ext_size; k++)
> +                                       set_bit(ext.subset_ext_ids[k], isavendorinfo->isa);
> +
> +                       set_bit(ext.id, isavendorinfo->isa);
> +               }
> +       }
> +}
> +
> +/*
> + * Populate all_harts_isa_bitmap for each vendor with all of the extensions that
> + * are shared across CPUs for that vendor.
> + */
> +static void __init riscv_fill_vendor_ext_list(int cpu)
> +{
> +       if (!IS_ENABLED(CONFIG_RISCV_ISA_VENDOR_EXT))
> +               return;
> +
> +       for (int i = 0; i < riscv_isa_vendor_ext_list_size; i++) {
> +               struct riscv_isa_vendor_ext_data_list *ext_list = riscv_isa_vendor_ext_list[i];
> +
> +               if (!ext_list->is_initialized) {
> +                       bitmap_copy(ext_list->all_harts_isa_bitmap.isa,
> +                                   ext_list->per_hart_isa_bitmap[cpu].isa,
> +                                   RISCV_ISA_VENDOR_EXT_MAX);
> +                       ext_list->is_initialized = true;
> +               } else {
> +                       bitmap_and(ext_list->all_harts_isa_bitmap.isa,
> +                                  ext_list->all_harts_isa_bitmap.isa,
> +                                  ext_list->per_hart_isa_bitmap[cpu].isa,
> +                                  RISCV_ISA_VENDOR_EXT_MAX);
> +               }
> +       }
> +}
> +
>  static int __init riscv_fill_hwcap_from_ext_list(unsigned long *isa2hwcap)
>  {
>         unsigned int cpu;
> @@ -617,6 +667,8 @@ static int __init riscv_fill_hwcap_from_ext_list(unsigned long *isa2hwcap)
>                         }
>                 }
>
> +               riscv_fill_cpu_vendor_ext(cpu_node, cpu);
> +
>                 of_node_put(cpu_node);
>
>                 /*
> @@ -632,6 +684,8 @@ static int __init riscv_fill_hwcap_from_ext_list(unsigned long *isa2hwcap)
>                         bitmap_copy(riscv_isa, isainfo->isa, RISCV_ISA_EXT_MAX);
>                 else
>                         bitmap_and(riscv_isa, riscv_isa, isainfo->isa, RISCV_ISA_EXT_MAX);
> +
> +               riscv_fill_vendor_ext_list(cpu);
>         }
>
>         if (bitmap_empty(riscv_isa, RISCV_ISA_EXT_MAX))
> @@ -768,28 +822,45 @@ void __init_or_module riscv_cpufeature_patch_func(struct alt_entry *begin,
>  {
>         struct alt_entry *alt;
>         void *oldptr, *altptr;
> -       u16 id, value;
> +       u16 id, value, vendor;
>
>         if (stage == RISCV_ALTERNATIVES_EARLY_BOOT)
>                 return;
>
>         for (alt = begin; alt < end; alt++) {
> -               if (alt->vendor_id != 0)
> -                       continue;
> -
>                 id = PATCH_ID_CPUFEATURE_ID(alt->patch_id);
> +               vendor = PATCH_ID_CPUFEATURE_ID(alt->vendor_id);
>
> -               if (id >= RISCV_ISA_EXT_MAX) {
> -                       WARN(1, "This extension id:%d is not in ISA extension list", id);
> -                       continue;
> -               }
> +               /*
> +                * Any alternative with a patch_id that is less than
> +                * RISCV_ISA_EXT_MAX is interpreted as a standard extension.
> +                *
> +                * Any alternative with patch_id that is greater than or equal
> +                * to RISCV_VENDOR_EXT_ALTERNATIVES_BASE is interpreted as a
> +                * vendor extension.
> +                */
> +               if (id < RISCV_ISA_EXT_MAX) {
> +                       /*
> +                        * This patch should be treated as errata so skip
> +                        * processing here.
> +                        */
> +                       if (alt->vendor_id != 0)
> +                               continue;
>
> -               if (!__riscv_isa_extension_available(NULL, id))
> -                       continue;
> +                       if (!__riscv_isa_extension_available(NULL, id))
> +                               continue;
>
> -               value = PATCH_ID_CPUFEATURE_VALUE(alt->patch_id);
> -               if (!riscv_cpufeature_patch_check(id, value))
> +                       value = PATCH_ID_CPUFEATURE_VALUE(alt->patch_id);
> +                       if (!riscv_cpufeature_patch_check(id, value))
> +                               continue;
> +               } else if (id >= RISCV_VENDOR_EXT_ALTERNATIVES_BASE) {
> +                       if (!__riscv_isa_vendor_extension_available(VENDOR_EXT_ALL_CPUS, vendor,
> +                                                                   id - RISCV_VENDOR_EXT_ALTERNATIVES_BASE))
> +                               continue;
> +               } else {
> +                       WARN(1, "This extension id:%d is not in ISA extension list", id);
>                         continue;
> +               }
>
>                 oldptr = ALT_OLD_PTR(alt);
>                 altptr = ALT_ALT_PTR(alt);
> diff --git a/arch/riscv/kernel/vendor_extensions.c b/arch/riscv/kernel/vendor_extensions.c
> new file mode 100644
> index 000000000000..b6c1e7b5d34b
> --- /dev/null
> +++ b/arch/riscv/kernel/vendor_extensions.c
> @@ -0,0 +1,56 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright 2024 Rivos, Inc
> + */
> +
> +#include <asm/vendorid_list.h>
> +#include <asm/vendor_extensions.h>
> +#include <asm/vendor_extensions/andes.h>
> +
> +#include <linux/array_size.h>
> +#include <linux/types.h>
> +
> +struct riscv_isa_vendor_ext_data_list *riscv_isa_vendor_ext_list[] = {
> +#ifdef CONFIG_RISCV_ISA_VENDOR_EXT_ANDES
> +       &riscv_isa_vendor_ext_list_andes,
> +#endif
> +};
> +
> +const size_t riscv_isa_vendor_ext_list_size = ARRAY_SIZE(riscv_isa_vendor_ext_list);
> +
> +/**
> + * __riscv_isa_vendor_extension_available() - Check whether given vendor
> + * extension is available or not.
> + *
> + * @cpu: check if extension is available on this cpu
> + * @vendor: vendor that the extension is a member of
> + * @bit: bit position of the desired extension
> + * Return: true or false
> + *
> + * NOTE: When cpu is -1, will check if extension is available on all cpus
> + */
> +bool __riscv_isa_vendor_extension_available(int cpu, unsigned long vendor, unsigned int bit)
> +{
> +       struct riscv_isavendorinfo *bmap;
> +       struct riscv_isavendorinfo *cpu_bmap;
> +
> +       switch (vendor) {
> +       #ifdef CONFIG_RISCV_ISA_VENDOR_EXT_ANDES
> +       case ANDES_VENDOR_ID:
> +               bmap = &riscv_isa_vendor_ext_list_andes.all_harts_isa_bitmap;
> +               cpu_bmap = &riscv_isa_vendor_ext_list_andes.per_hart_isa_bitmap[cpu];
> +               break;
> +       #endif
> +       default:
> +               return false;
> +       }
> +
> +       if (cpu != -1)
> +               bmap = &cpu_bmap[cpu];
> +
> +       if (bit >= RISCV_ISA_VENDOR_EXT_MAX)
> +               return false;
> +
> +       return test_bit(bit, bmap->isa) ? true : false;
> +}
> +EXPORT_SYMBOL_GPL(__riscv_isa_vendor_extension_available);
> diff --git a/arch/riscv/kernel/vendor_extensions/Makefile b/arch/riscv/kernel/vendor_extensions/Makefile
> new file mode 100644
> index 000000000000..6a61aed944f1
> --- /dev/null
> +++ b/arch/riscv/kernel/vendor_extensions/Makefile
> @@ -0,0 +1,3 @@
> +# SPDX-License-Identifier: GPL-2.0-only
> +
> +obj-$(CONFIG_RISCV_ISA_VENDOR_EXT_ANDES)       += andes.o
> diff --git a/arch/riscv/kernel/vendor_extensions/andes.c b/arch/riscv/kernel/vendor_extensions/andes.c
> new file mode 100644
> index 000000000000..ec688c88456a
> --- /dev/null
> +++ b/arch/riscv/kernel/vendor_extensions/andes.c
> @@ -0,0 +1,18 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +
> +#include <asm/cpufeature.h>
> +#include <asm/vendor_extensions.h>
> +#include <asm/vendor_extensions/andes.h>
> +
> +#include <linux/array_size.h>
> +#include <linux/types.h>
> +
> +/* All Andes vendor extensions supported in Linux */
> +const struct riscv_isa_ext_data riscv_isa_vendor_ext_andes[] = {
> +       __RISCV_ISA_EXT_DATA(xandespmu, RISCV_ISA_VENDOR_EXT_XANDESPMU),
> +};
> +
> +struct riscv_isa_vendor_ext_data_list riscv_isa_vendor_ext_list_andes = {
> +       .ext_data_count = ARRAY_SIZE(riscv_isa_vendor_ext_andes),
> +       .ext_data = riscv_isa_vendor_ext_andes,
> +};
> diff --git a/drivers/perf/riscv_pmu_sbi.c b/drivers/perf/riscv_pmu_sbi.c
> index a2e4005e1fd0..02719e0c6368 100644
> --- a/drivers/perf/riscv_pmu_sbi.c
> +++ b/drivers/perf/riscv_pmu_sbi.c
> @@ -24,6 +24,8 @@
>  #include <asm/errata_list.h>
>  #include <asm/sbi.h>
>  #include <asm/cpufeature.h>
> +#include <asm/vendor_extensions.h>
> +#include <asm/vendor_extensions/andes.h>
>
>  #define ALT_SBI_PMU_OVERFLOW(__ovl)                                    \
>  asm volatile(ALTERNATIVE_2(                                            \
> @@ -32,7 +34,8 @@ asm volatile(ALTERNATIVE_2(                                           \
>                 THEAD_VENDOR_ID, ERRATA_THEAD_PMU,                      \
>                 CONFIG_ERRATA_THEAD_PMU,                                \
>         "csrr %0, " __stringify(ANDES_CSR_SCOUNTEROF),                  \
> -               0, RISCV_ISA_EXT_XANDESPMU,                             \
> +               ANDES_VENDOR_ID,                                        \
> +               RISCV_ISA_VENDOR_EXT_XANDESPMU + RISCV_VENDOR_EXT_ALTERNATIVES_BASE, \
>                 CONFIG_ANDES_CUSTOM_PMU)                                \
>         : "=r" (__ovl) :                                                \
>         : "memory")
> @@ -41,7 +44,8 @@ asm volatile(ALTERNATIVE_2(                                           \
>  asm volatile(ALTERNATIVE(                                              \
>         "csrc " __stringify(CSR_IP) ", %0\n\t",                         \
>         "csrc " __stringify(ANDES_CSR_SLIP) ", %0\n\t",                 \
> -               0, RISCV_ISA_EXT_XANDESPMU,                             \
> +               ANDES_VENDOR_ID,                                        \
> +               RISCV_ISA_VENDOR_EXT_XANDESPMU + RISCV_VENDOR_EXT_ALTERNATIVES_BASE, \
>                 CONFIG_ANDES_CUSTOM_PMU)                                \
>         : : "r"(__irq_mask)                                             \
>         : "memory")
> @@ -1060,7 +1064,7 @@ static int pmu_sbi_setup_irqs(struct riscv_pmu *pmu, struct platform_device *pde
>                    riscv_cached_mimpid(0) == 0) {
>                 riscv_pmu_irq_num = THEAD_C9XX_RV_IRQ_PMU;
>                 riscv_pmu_use_irq = true;
> -       } else if (riscv_isa_extension_available(NULL, XANDESPMU) &&
> +       } else if (riscv_isa_vendor_extension_available(ANDES_VENDOR_ID, XANDESPMU) &&
>                    IS_ENABLED(CONFIG_ANDES_CUSTOM_PMU)) {
>                 riscv_pmu_irq_num = ANDES_SLI_CAUSE_BASE + ANDES_RV_IRQ_PMOVI;
>                 riscv_pmu_use_irq = true;
>
> --
> 2.44.0
>



More information about the linux-riscv mailing list