1 /* SPDX-License-Identifier: GPL-2.0-only */ 2 /* 3 * Copyright 2024 Rivos, Inc 4 */ 5 6 #ifndef _ASM_VENDOR_EXTENSIONS_H 7 #define _ASM_VENDOR_EXTENSIONS_H 8 9 #include <asm/cpufeature.h> 10 11 #include <linux/array_size.h> 12 #include <linux/types.h> 13 14 /* 15 * The extension keys of each vendor must be strictly less than this value. 16 */ 17 #define RISCV_ISA_VENDOR_EXT_MAX 32 18 19 struct riscv_isavendorinfo { 20 DECLARE_BITMAP(isa, RISCV_ISA_VENDOR_EXT_MAX); 21 }; 22 23 struct riscv_isa_vendor_ext_data_list { 24 bool is_initialized; 25 const size_t ext_data_count; 26 const struct riscv_isa_ext_data *ext_data; 27 struct riscv_isavendorinfo per_hart_isa_bitmap[NR_CPUS]; 28 struct riscv_isavendorinfo all_harts_isa_bitmap; 29 }; 30 31 extern struct riscv_isa_vendor_ext_data_list *riscv_isa_vendor_ext_list[]; 32 33 extern const size_t riscv_isa_vendor_ext_list_size; 34 35 /* 36 * The alternatives need some way of distinguishing between vendor extensions 37 * and errata. Incrementing all of the vendor extension keys so they are at 38 * least 0x8000 accomplishes that. 39 */ 40 #define RISCV_VENDOR_EXT_ALTERNATIVES_BASE 0x8000 41 42 #define VENDOR_EXT_ALL_CPUS -1 43 44 bool __riscv_isa_vendor_extension_available(int cpu, unsigned long vendor, unsigned int bit); 45 #define riscv_cpu_isa_vendor_extension_available(cpu, vendor, ext) \ 46 __riscv_isa_vendor_extension_available(cpu, vendor, RISCV_ISA_VENDOR_EXT_##ext) 47 #define riscv_isa_vendor_extension_available(vendor, ext) \ 48 __riscv_isa_vendor_extension_available(VENDOR_EXT_ALL_CPUS, vendor, \ 49 RISCV_ISA_VENDOR_EXT_##ext) 50 51 static __always_inline bool riscv_has_vendor_extension_likely(const unsigned long vendor, 52 const unsigned long ext) 53 { 54 if (!IS_ENABLED(CONFIG_RISCV_ISA_VENDOR_EXT)) 55 return false; 56 57 if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE)) 58 return __riscv_has_extension_likely(vendor, 59 ext + RISCV_VENDOR_EXT_ALTERNATIVES_BASE); 60 61 return __riscv_isa_vendor_extension_available(VENDOR_EXT_ALL_CPUS, vendor, ext); 62 } 63 64 static __always_inline bool riscv_has_vendor_extension_unlikely(const unsigned long vendor, 65 const unsigned long ext) 66 { 67 if (!IS_ENABLED(CONFIG_RISCV_ISA_VENDOR_EXT)) 68 return false; 69 70 if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE)) 71 return __riscv_has_extension_unlikely(vendor, 72 ext + RISCV_VENDOR_EXT_ALTERNATIVES_BASE); 73 74 return __riscv_isa_vendor_extension_available(VENDOR_EXT_ALL_CPUS, vendor, ext); 75 } 76 77 static __always_inline bool riscv_cpu_has_vendor_extension_likely(const unsigned long vendor, 78 int cpu, const unsigned long ext) 79 { 80 if (!IS_ENABLED(CONFIG_RISCV_ISA_VENDOR_EXT)) 81 return false; 82 83 if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE) && 84 __riscv_has_extension_likely(vendor, ext + RISCV_VENDOR_EXT_ALTERNATIVES_BASE)) 85 return true; 86 87 return __riscv_isa_vendor_extension_available(cpu, vendor, ext); 88 } 89 90 static __always_inline bool riscv_cpu_has_vendor_extension_unlikely(const unsigned long vendor, 91 int cpu, 92 const unsigned long ext) 93 { 94 if (!IS_ENABLED(CONFIG_RISCV_ISA_VENDOR_EXT)) 95 return false; 96 97 if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE) && 98 __riscv_has_extension_unlikely(vendor, ext + RISCV_VENDOR_EXT_ALTERNATIVES_BASE)) 99 return true; 100 101 return __riscv_isa_vendor_extension_available(cpu, vendor, ext); 102 } 103 104 #endif /* _ASM_VENDOR_EXTENSIONS_H */ 105