1 /* SPDX-License-Identifier: GPL-2.0-only */
3 * Copyright 2022-2024 Rivos, Inc
6 #ifndef _ASM_CPUFEATURE_H
7 #define _ASM_CPUFEATURE_H
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>
19 * These are probed via a device_initcall(), via either the SBI or directly
20 * from the corresponding CSRs.
22 struct riscv_cpuinfo
{
23 unsigned long mvendorid
;
24 unsigned long marchid
;
28 struct riscv_isainfo
{
29 DECLARE_BITMAP(isa
, RISCV_ISA_EXT_MAX
);
32 DECLARE_PER_CPU(struct riscv_cpuinfo
, riscv_cpuinfo
);
34 /* Per-cpu ISA extensions. */
35 extern struct riscv_isainfo hart_isa
[NR_CPUS
];
37 void __init
riscv_user_isa_enable(void);
39 #define _RISCV_ISA_EXT_DATA(_name, _id, _subset_exts, _subset_exts_size, _validate) { \
43 .subset_ext_ids = _subset_exts, \
44 .subset_ext_size = _subset_exts_size, \
45 .validate = _validate \
48 #define __RISCV_ISA_EXT_DATA(_name, _id) _RISCV_ISA_EXT_DATA(_name, _id, NULL, 0, NULL)
50 #define __RISCV_ISA_EXT_DATA_VALIDATE(_name, _id, _validate) \
51 _RISCV_ISA_EXT_DATA(_name, _id, NULL, 0, _validate)
53 /* Used to declare pure "lasso" extension (Zk for instance) */
54 #define __RISCV_ISA_EXT_BUNDLE(_name, _bundled_exts) \
55 _RISCV_ISA_EXT_DATA(_name, RISCV_ISA_EXT_INVALID, _bundled_exts, \
56 ARRAY_SIZE(_bundled_exts), NULL)
58 /* Used to declare extensions that are a superset of other extensions (Zvbb for instance) */
59 #define __RISCV_ISA_EXT_SUPERSET(_name, _id, _sub_exts) \
60 _RISCV_ISA_EXT_DATA(_name, _id, _sub_exts, ARRAY_SIZE(_sub_exts), NULL)
61 #define __RISCV_ISA_EXT_SUPERSET_VALIDATE(_name, _id, _sub_exts, _validate) \
62 _RISCV_ISA_EXT_DATA(_name, _id, _sub_exts, ARRAY_SIZE(_sub_exts), _validate)
64 bool check_unaligned_access_emulated_all_cpus(void);
65 #if defined(CONFIG_RISCV_SCALAR_MISALIGNED)
66 void check_unaligned_access_emulated(struct work_struct
*work __always_unused
);
67 void unaligned_emulation_finish(void);
68 bool unaligned_ctl_available(void);
69 DECLARE_PER_CPU(long, misaligned_access_speed
);
71 static inline bool unaligned_ctl_available(void)
77 bool check_vector_unaligned_access_emulated_all_cpus(void);
78 #if defined(CONFIG_RISCV_VECTOR_MISALIGNED)
79 void check_vector_unaligned_access_emulated(struct work_struct
*work __always_unused
);
80 DECLARE_PER_CPU(long, vector_misaligned_access
);
83 #if defined(CONFIG_RISCV_PROBE_UNALIGNED_ACCESS)
84 DECLARE_STATIC_KEY_FALSE(fast_unaligned_access_speed_key
);
86 static __always_inline
bool has_fast_unaligned_accesses(void)
88 return static_branch_likely(&fast_unaligned_access_speed_key
);
91 static __always_inline
bool has_fast_unaligned_accesses(void)
93 if (IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
))
100 unsigned long riscv_get_elf_hwcap(void);
102 struct riscv_isa_ext_data
{
103 const unsigned int id
;
105 const char *property
;
106 const unsigned int *subset_ext_ids
;
107 const unsigned int subset_ext_size
;
108 int (*validate
)(const struct riscv_isa_ext_data
*data
, const unsigned long *isa_bitmap
);
111 extern const struct riscv_isa_ext_data riscv_isa_ext
[];
112 extern const size_t riscv_isa_ext_count
;
113 extern bool riscv_isa_fallback
;
115 unsigned long riscv_isa_extension_base(const unsigned long *isa_bitmap
);
116 static __always_inline
bool riscv_cpu_has_extension_likely(int cpu
, const unsigned long ext
)
118 compiletime_assert(ext
< RISCV_ISA_EXT_MAX
, "ext must be < RISCV_ISA_EXT_MAX");
120 if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE
) &&
121 __riscv_has_extension_likely(STANDARD_EXT
, ext
))
124 return __riscv_isa_extension_available(hart_isa
[cpu
].isa
, ext
);
127 static __always_inline
bool riscv_cpu_has_extension_unlikely(int cpu
, const unsigned long ext
)
129 compiletime_assert(ext
< RISCV_ISA_EXT_MAX
, "ext must be < RISCV_ISA_EXT_MAX");
131 if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE
) &&
132 __riscv_has_extension_unlikely(STANDARD_EXT
, ext
))
135 return __riscv_isa_extension_available(hart_isa
[cpu
].isa
, ext
);