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 <linux/workqueue.h>
12 #include <linux/kconfig.h>
13 #include <linux/percpu-defs.h>
14 #include <linux/threads.h>
15 #include <asm/hwcap.h>
16 #include <asm/cpufeature-macros.h>
17
18 /*
19 * These are probed via a device_initcall(), via either the SBI or directly
20 * from the corresponding CSRs.
21 */
22 struct riscv_cpuinfo {
23 unsigned long mvendorid;
24 unsigned long marchid;
25 unsigned long mimpid;
26 };
27
28 struct riscv_isainfo {
29 DECLARE_BITMAP(isa, RISCV_ISA_EXT_MAX);
30 };
31
32 DECLARE_PER_CPU(struct riscv_cpuinfo, riscv_cpuinfo);
33
34 extern const struct seq_operations cpuinfo_op;
35
36 /* Per-cpu ISA extensions. */
37 extern struct riscv_isainfo hart_isa[NR_CPUS];
38
39 extern u32 thead_vlenb_of;
40
41 void __init riscv_user_isa_enable(void);
42
43 #define _RISCV_ISA_EXT_DATA(_name, _id, _subset_exts, _subset_exts_size, _validate) { \
44 .name = #_name, \
45 .property = #_name, \
46 .id = _id, \
47 .subset_ext_ids = _subset_exts, \
48 .subset_ext_size = _subset_exts_size, \
49 .validate = _validate \
50 }
51
52 #define __RISCV_ISA_EXT_DATA(_name, _id) _RISCV_ISA_EXT_DATA(_name, _id, NULL, 0, NULL)
53
54 #define __RISCV_ISA_EXT_DATA_VALIDATE(_name, _id, _validate) \
55 _RISCV_ISA_EXT_DATA(_name, _id, NULL, 0, _validate)
56
57 /* Used to declare pure "lasso" extension (Zk for instance) */
58 #define __RISCV_ISA_EXT_BUNDLE(_name, _bundled_exts) \
59 _RISCV_ISA_EXT_DATA(_name, RISCV_ISA_EXT_INVALID, _bundled_exts, \
60 ARRAY_SIZE(_bundled_exts), NULL)
61 #define __RISCV_ISA_EXT_BUNDLE_VALIDATE(_name, _bundled_exts, _validate) \
62 _RISCV_ISA_EXT_DATA(_name, RISCV_ISA_EXT_INVALID, _bundled_exts, \
63 ARRAY_SIZE(_bundled_exts), _validate)
64
65 /* Used to declare extensions that are a superset of other extensions (Zvbb for instance) */
66 #define __RISCV_ISA_EXT_SUPERSET(_name, _id, _sub_exts) \
67 _RISCV_ISA_EXT_DATA(_name, _id, _sub_exts, ARRAY_SIZE(_sub_exts), NULL)
68 #define __RISCV_ISA_EXT_SUPERSET_VALIDATE(_name, _id, _sub_exts, _validate) \
69 _RISCV_ISA_EXT_DATA(_name, _id, _sub_exts, ARRAY_SIZE(_sub_exts), _validate)
70
71 bool __init check_unaligned_access_emulated_all_cpus(void);
72 void unaligned_access_init(void);
73 int cpu_online_unaligned_access_init(unsigned int cpu);
74 #if defined(CONFIG_RISCV_SCALAR_MISALIGNED)
75 void unaligned_emulation_finish(void);
76 bool unaligned_ctl_available(void);
77 #else
unaligned_ctl_available(void)78 static inline bool unaligned_ctl_available(void)
79 {
80 return false;
81 }
82 #endif
83
84 #if defined(CONFIG_RISCV_MISALIGNED)
85 DECLARE_PER_CPU(long, misaligned_access_speed);
86 bool misaligned_traps_can_delegate(void);
87 #else
misaligned_traps_can_delegate(void)88 static inline bool misaligned_traps_can_delegate(void)
89 {
90 return false;
91 }
92 #endif
93
94 bool __init check_vector_unaligned_access_emulated_all_cpus(void);
95 #if defined(CONFIG_RISCV_VECTOR_MISALIGNED)
96 void check_vector_unaligned_access_emulated(struct work_struct *work __always_unused);
97 DECLARE_PER_CPU(long, vector_misaligned_access);
98 #endif
99
100 #if defined(CONFIG_RISCV_PROBE_UNALIGNED_ACCESS)
101 DECLARE_STATIC_KEY_FALSE(fast_unaligned_access_speed_key);
102
has_fast_unaligned_accesses(void)103 static __always_inline bool has_fast_unaligned_accesses(void)
104 {
105 return static_branch_likely(&fast_unaligned_access_speed_key);
106 }
107 #else
has_fast_unaligned_accesses(void)108 static __always_inline bool has_fast_unaligned_accesses(void)
109 {
110 if (IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS))
111 return true;
112 else
113 return false;
114 }
115 #endif
116
117 unsigned long riscv_get_elf_hwcap(void);
118
119 struct riscv_isa_ext_data {
120 const unsigned int id;
121 const char *name;
122 const char *property;
123 const unsigned int *subset_ext_ids;
124 const unsigned int subset_ext_size;
125 int (*validate)(const struct riscv_isa_ext_data *data, const unsigned long *isa_bitmap);
126 };
127
128 extern const struct riscv_isa_ext_data riscv_isa_ext[];
129 extern const size_t riscv_isa_ext_count;
130 extern bool riscv_isa_fallback;
131
132 unsigned long riscv_isa_extension_base(const unsigned long *isa_bitmap);
riscv_cpu_has_extension_likely(int cpu,const unsigned long ext)133 static __always_inline bool riscv_cpu_has_extension_likely(int cpu, const unsigned long ext)
134 {
135 compiletime_assert(ext < RISCV_ISA_EXT_MAX, "ext must be < RISCV_ISA_EXT_MAX");
136
137 if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE) &&
138 __riscv_has_extension_likely(STANDARD_EXT, ext))
139 return true;
140
141 return __riscv_isa_extension_available(hart_isa[cpu].isa, ext);
142 }
143
riscv_cpu_has_extension_unlikely(int cpu,const unsigned long ext)144 static __always_inline bool riscv_cpu_has_extension_unlikely(int cpu, const unsigned long ext)
145 {
146 compiletime_assert(ext < RISCV_ISA_EXT_MAX, "ext must be < RISCV_ISA_EXT_MAX");
147
148 if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE) &&
149 __riscv_has_extension_unlikely(STANDARD_EXT, ext))
150 return true;
151
152 return __riscv_isa_extension_available(hart_isa[cpu].isa, ext);
153 }
154
155 #endif
156