Merge branch 'for-6.9/amd-sfh' into for-linus
[sfrench/cifs-2.6.git] / arch / riscv / include / asm / cpufeature.h
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