1 /* SPDX-License-Identifier: GPL-2.0-only */ 2 /* 3 * Copyright 2022-2023 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(int cpu); 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 unsigned long riscv_get_elf_hwcap(void); 57 58 struct riscv_isa_ext_data { 59 const unsigned int id; 60 const char *name; 61 const char *property; 62 const unsigned int *subset_ext_ids; 63 const unsigned int subset_ext_size; 64 }; 65 66 extern const struct riscv_isa_ext_data riscv_isa_ext[]; 67 extern const size_t riscv_isa_ext_count; 68 extern bool riscv_isa_fallback; 69 70 unsigned long riscv_isa_extension_base(const unsigned long *isa_bitmap); 71 72 bool __riscv_isa_extension_available(const unsigned long *isa_bitmap, unsigned int bit); 73 #define riscv_isa_extension_available(isa_bitmap, ext) \ 74 __riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_##ext) 75 76 static __always_inline bool 77 riscv_has_extension_likely(const unsigned long ext) 78 { 79 compiletime_assert(ext < RISCV_ISA_EXT_MAX, 80 "ext must be < RISCV_ISA_EXT_MAX"); 81 82 if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE)) { 83 asm goto( 84 ALTERNATIVE("j %l[l_no]", "nop", 0, %[ext], 1) 85 : 86 : [ext] "i" (ext) 87 : 88 : l_no); 89 } else { 90 if (!__riscv_isa_extension_available(NULL, ext)) 91 goto l_no; 92 } 93 94 return true; 95 l_no: 96 return false; 97 } 98 99 static __always_inline bool 100 riscv_has_extension_unlikely(const unsigned long ext) 101 { 102 compiletime_assert(ext < RISCV_ISA_EXT_MAX, 103 "ext must be < RISCV_ISA_EXT_MAX"); 104 105 if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE)) { 106 asm goto( 107 ALTERNATIVE("nop", "j %l[l_yes]", 0, %[ext], 1) 108 : 109 : [ext] "i" (ext) 110 : 111 : l_yes); 112 } else { 113 if (__riscv_isa_extension_available(NULL, ext)) 114 goto l_yes; 115 } 116 117 return false; 118 l_yes: 119 return true; 120 } 121 122 static __always_inline bool riscv_cpu_has_extension_likely(int cpu, const unsigned long ext) 123 { 124 if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE) && riscv_has_extension_likely(ext)) 125 return true; 126 127 return __riscv_isa_extension_available(hart_isa[cpu].isa, ext); 128 } 129 130 static __always_inline bool riscv_cpu_has_extension_unlikely(int cpu, const unsigned long ext) 131 { 132 if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE) && riscv_has_extension_unlikely(ext)) 133 return true; 134 135 return __riscv_isa_extension_available(hart_isa[cpu].isa, ext); 136 } 137 138 DECLARE_STATIC_KEY_FALSE(fast_misaligned_access_speed_key); 139 140 #endif 141