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