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