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 DECLARE_PER_CPU(long, misaligned_access_speed); 32 33 /* Per-cpu ISA extensions. */ 34 extern struct riscv_isainfo hart_isa[NR_CPUS]; 35 36 void riscv_user_isa_enable(void); 37 38 #ifdef CONFIG_RISCV_MISALIGNED 39 bool unaligned_ctl_available(void); 40 bool check_unaligned_access_emulated_all_cpus(void); 41 void unaligned_emulation_finish(void); 42 #else 43 static inline bool unaligned_ctl_available(void) 44 { 45 return false; 46 } 47 48 static inline bool check_unaligned_access_emulated(int cpu) 49 { 50 return false; 51 } 52 53 static inline void unaligned_emulation_finish(void) {} 54 #endif 55 56 DECLARE_STATIC_KEY_FALSE(fast_unaligned_access_speed_key); 57 58 static __always_inline bool has_fast_unaligned_accesses(void) 59 { 60 return static_branch_likely(&fast_unaligned_access_speed_key); 61 } 62 63 unsigned long riscv_get_elf_hwcap(void); 64 65 struct riscv_isa_ext_data { 66 const unsigned int id; 67 const char *name; 68 const char *property; 69 const unsigned int *subset_ext_ids; 70 const unsigned int subset_ext_size; 71 }; 72 73 extern const struct riscv_isa_ext_data riscv_isa_ext[]; 74 extern const size_t riscv_isa_ext_count; 75 extern bool riscv_isa_fallback; 76 77 unsigned long riscv_isa_extension_base(const unsigned long *isa_bitmap); 78 79 bool __riscv_isa_extension_available(const unsigned long *isa_bitmap, unsigned int bit); 80 #define riscv_isa_extension_available(isa_bitmap, ext) \ 81 __riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_##ext) 82 83 static __always_inline bool 84 riscv_has_extension_likely(const unsigned long ext) 85 { 86 compiletime_assert(ext < RISCV_ISA_EXT_MAX, 87 "ext must be < RISCV_ISA_EXT_MAX"); 88 89 if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE)) { 90 asm_volatile_goto( 91 ALTERNATIVE("j %l[l_no]", "nop", 0, %[ext], 1) 92 : 93 : [ext] "i" (ext) 94 : 95 : l_no); 96 } else { 97 if (!__riscv_isa_extension_available(NULL, ext)) 98 goto l_no; 99 } 100 101 return true; 102 l_no: 103 return false; 104 } 105 106 static __always_inline bool 107 riscv_has_extension_unlikely(const unsigned long ext) 108 { 109 compiletime_assert(ext < RISCV_ISA_EXT_MAX, 110 "ext must be < RISCV_ISA_EXT_MAX"); 111 112 if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE)) { 113 asm_volatile_goto( 114 ALTERNATIVE("nop", "j %l[l_yes]", 0, %[ext], 1) 115 : 116 : [ext] "i" (ext) 117 : 118 : l_yes); 119 } else { 120 if (__riscv_isa_extension_available(NULL, ext)) 121 goto l_yes; 122 } 123 124 return false; 125 l_yes: 126 return true; 127 } 128 129 static __always_inline bool riscv_cpu_has_extension_likely(int cpu, const unsigned long ext) 130 { 131 if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE) && riscv_has_extension_likely(ext)) 132 return true; 133 134 return __riscv_isa_extension_available(hart_isa[cpu].isa, ext); 135 } 136 137 static __always_inline bool riscv_cpu_has_extension_unlikely(int cpu, const unsigned long ext) 138 { 139 if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE) && riscv_has_extension_unlikely(ext)) 140 return true; 141 142 return __riscv_isa_extension_available(hart_isa[cpu].isa, ext); 143 } 144 145 #endif 146