1 /* SPDX-License-Identifier: GPL-2.0-only */ 2 /* 3 * Copyright 2022-2024 Rivos, Inc 4 */ 5 6 #ifndef _ASM_CPUFEATURE_H 7 #define _ASM_CPUFEATURE_H 8 9 #include <linux/bitmap.h> 10 #include <linux/jump_label.h> 11 #include <asm/hwcap.h> 12 #include <asm/alternative-macros.h> 13 #include <asm/errno.h> 14 15 /* 16 * These are probed via a device_initcall(), via either the SBI or directly 17 * from the corresponding CSRs. 18 */ 19 struct riscv_cpuinfo { 20 unsigned long mvendorid; 21 unsigned long marchid; 22 unsigned long mimpid; 23 }; 24 25 struct riscv_isainfo { 26 DECLARE_BITMAP(isa, RISCV_ISA_EXT_MAX); 27 }; 28 29 DECLARE_PER_CPU(struct riscv_cpuinfo, riscv_cpuinfo); 30 31 /* Per-cpu ISA extensions. */ 32 extern struct riscv_isainfo hart_isa[NR_CPUS]; 33 34 void riscv_user_isa_enable(void); 35 36 #define _RISCV_ISA_EXT_DATA(_name, _id, _subset_exts, _subset_exts_size, _validate) { \ 37 .name = #_name, \ 38 .property = #_name, \ 39 .id = _id, \ 40 .subset_ext_ids = _subset_exts, \ 41 .subset_ext_size = _subset_exts_size, \ 42 .validate = _validate \ 43 } 44 45 #define __RISCV_ISA_EXT_DATA(_name, _id) _RISCV_ISA_EXT_DATA(_name, _id, NULL, 0, NULL) 46 47 #define __RISCV_ISA_EXT_DATA_VALIDATE(_name, _id, _validate) \ 48 _RISCV_ISA_EXT_DATA(_name, _id, NULL, 0, _validate) 49 50 /* Used to declare pure "lasso" extension (Zk for instance) */ 51 #define __RISCV_ISA_EXT_BUNDLE(_name, _bundled_exts) \ 52 _RISCV_ISA_EXT_DATA(_name, RISCV_ISA_EXT_INVALID, _bundled_exts, \ 53 ARRAY_SIZE(_bundled_exts), NULL) 54 55 /* Used to declare extensions that are a superset of other extensions (Zvbb for instance) */ 56 #define __RISCV_ISA_EXT_SUPERSET(_name, _id, _sub_exts) \ 57 _RISCV_ISA_EXT_DATA(_name, _id, _sub_exts, ARRAY_SIZE(_sub_exts), NULL) 58 #define __RISCV_ISA_EXT_SUPERSET_VALIDATE(_name, _id, _sub_exts, _validate) \ 59 _RISCV_ISA_EXT_DATA(_name, _id, _sub_exts, ARRAY_SIZE(_sub_exts), _validate) 60 61 #if defined(CONFIG_RISCV_MISALIGNED) 62 bool check_unaligned_access_emulated_all_cpus(void); 63 void unaligned_emulation_finish(void); 64 bool unaligned_ctl_available(void); 65 DECLARE_PER_CPU(long, misaligned_access_speed); 66 #else 67 static inline bool unaligned_ctl_available(void) 68 { 69 return false; 70 } 71 #endif 72 73 #if defined(CONFIG_RISCV_PROBE_UNALIGNED_ACCESS) 74 DECLARE_STATIC_KEY_FALSE(fast_unaligned_access_speed_key); 75 76 static __always_inline bool has_fast_unaligned_accesses(void) 77 { 78 return static_branch_likely(&fast_unaligned_access_speed_key); 79 } 80 #else 81 static __always_inline bool has_fast_unaligned_accesses(void) 82 { 83 if (IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)) 84 return true; 85 else 86 return false; 87 } 88 #endif 89 90 unsigned long riscv_get_elf_hwcap(void); 91 92 struct riscv_isa_ext_data { 93 const unsigned int id; 94 const char *name; 95 const char *property; 96 const unsigned int *subset_ext_ids; 97 const unsigned int subset_ext_size; 98 int (*validate)(const struct riscv_isa_ext_data *data, const unsigned long *isa_bitmap); 99 }; 100 101 extern const struct riscv_isa_ext_data riscv_isa_ext[]; 102 extern const size_t riscv_isa_ext_count; 103 extern bool riscv_isa_fallback; 104 105 unsigned long riscv_isa_extension_base(const unsigned long *isa_bitmap); 106 107 #define STANDARD_EXT 0 108 109 bool __riscv_isa_extension_available(const unsigned long *isa_bitmap, unsigned int bit); 110 #define riscv_isa_extension_available(isa_bitmap, ext) \ 111 __riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_##ext) 112 113 static __always_inline bool __riscv_has_extension_likely(const unsigned long vendor, 114 const unsigned long ext) 115 { 116 asm goto(ALTERNATIVE("j %l[l_no]", "nop", %[vendor], %[ext], 1) 117 : 118 : [vendor] "i" (vendor), [ext] "i" (ext) 119 : 120 : l_no); 121 122 return true; 123 l_no: 124 return false; 125 } 126 127 static __always_inline bool __riscv_has_extension_unlikely(const unsigned long vendor, 128 const unsigned long ext) 129 { 130 asm goto(ALTERNATIVE("nop", "j %l[l_yes]", %[vendor], %[ext], 1) 131 : 132 : [vendor] "i" (vendor), [ext] "i" (ext) 133 : 134 : l_yes); 135 136 return false; 137 l_yes: 138 return true; 139 } 140 141 static __always_inline bool riscv_has_extension_unlikely(const unsigned long ext) 142 { 143 compiletime_assert(ext < RISCV_ISA_EXT_MAX, "ext must be < RISCV_ISA_EXT_MAX"); 144 145 if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE)) 146 return __riscv_has_extension_unlikely(STANDARD_EXT, ext); 147 148 return __riscv_isa_extension_available(NULL, ext); 149 } 150 151 static __always_inline bool riscv_has_extension_likely(const unsigned long ext) 152 { 153 compiletime_assert(ext < RISCV_ISA_EXT_MAX, "ext must be < RISCV_ISA_EXT_MAX"); 154 155 if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE)) 156 return __riscv_has_extension_likely(STANDARD_EXT, ext); 157 158 return __riscv_isa_extension_available(NULL, ext); 159 } 160 161 static __always_inline bool riscv_cpu_has_extension_likely(int cpu, const unsigned long ext) 162 { 163 compiletime_assert(ext < RISCV_ISA_EXT_MAX, "ext must be < RISCV_ISA_EXT_MAX"); 164 165 if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE) && 166 __riscv_has_extension_likely(STANDARD_EXT, ext)) 167 return true; 168 169 return __riscv_isa_extension_available(hart_isa[cpu].isa, ext); 170 } 171 172 static __always_inline bool riscv_cpu_has_extension_unlikely(int cpu, const unsigned long ext) 173 { 174 compiletime_assert(ext < RISCV_ISA_EXT_MAX, "ext must be < RISCV_ISA_EXT_MAX"); 175 176 if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE) && 177 __riscv_has_extension_unlikely(STANDARD_EXT, ext)) 178 return true; 179 180 return __riscv_isa_extension_available(hart_isa[cpu].isa, ext); 181 } 182 183 #endif 184
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.