/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright 2024 Rivos, Inc */ #ifndef _ASM_VENDOR_EXTENSIONS_H #define _ASM_VENDOR_EXTENSIONS_H #include #include #include /* * 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_cpu_isa_vendor_extension_available(cpu, vendor, ext) \ __riscv_isa_vendor_extension_available(cpu, vendor, RISCV_ISA_VENDOR_EXT_##ext) #define riscv_isa_vendor_extension_available(vendor, ext) \ __riscv_isa_vendor_extension_available(VENDOR_EXT_ALL_CPUS, vendor, \ RISCV_ISA_VENDOR_EXT_##ext) static __always_inline bool riscv_has_vendor_extension_likely(const unsigned long vendor, const unsigned long ext) { if (!IS_ENABLED(CONFIG_RISCV_ISA_VENDOR_EXT)) return false; if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE)) return __riscv_has_extension_likely(vendor, ext + RISCV_VENDOR_EXT_ALTERNATIVES_BASE); return __riscv_isa_vendor_extension_available(VENDOR_EXT_ALL_CPUS, vendor, ext); } static __always_inline bool riscv_has_vendor_extension_unlikely(const unsigned long vendor, const unsigned long ext) { if (!IS_ENABLED(CONFIG_RISCV_ISA_VENDOR_EXT)) return false; if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE)) return __riscv_has_extension_unlikely(vendor, ext + RISCV_VENDOR_EXT_ALTERNATIVES_BASE); return __riscv_isa_vendor_extension_available(VENDOR_EXT_ALL_CPUS, vendor, ext); } static __always_inline bool riscv_cpu_has_vendor_extension_likely(const unsigned long vendor, int cpu, const unsigned long ext) { if (!IS_ENABLED(CONFIG_RISCV_ISA_VENDOR_EXT)) return false; if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE) && __riscv_has_extension_likely(vendor, ext + RISCV_VENDOR_EXT_ALTERNATIVES_BASE)) return true; return __riscv_isa_vendor_extension_available(cpu, vendor, ext); } static __always_inline bool riscv_cpu_has_vendor_extension_unlikely(const unsigned long vendor, int cpu, const unsigned long ext) { if (!IS_ENABLED(CONFIG_RISCV_ISA_VENDOR_EXT)) return false; if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE) && __riscv_has_extension_unlikely(vendor, ext + RISCV_VENDOR_EXT_ALTERNATIVES_BASE)) return true; return __riscv_isa_vendor_extension_available(cpu, vendor, ext); } #endif /* _ASM_VENDOR_EXTENSIONS_H */