xref: /linux/arch/riscv/include/asm/vendor_extensions.h (revision c532de5a67a70f8533d495f8f2aaa9a0491c3ad0)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 /*
3  * Copyright 2024 Rivos, Inc
4  */
5 
6 #ifndef _ASM_VENDOR_EXTENSIONS_H
7 #define _ASM_VENDOR_EXTENSIONS_H
8 
9 #include <asm/cpufeature.h>
10 
11 #include <linux/array_size.h>
12 #include <linux/types.h>
13 
14 /*
15  * The extension keys of each vendor must be strictly less than this value.
16  */
17 #define RISCV_ISA_VENDOR_EXT_MAX 32
18 
19 struct riscv_isavendorinfo {
20 	DECLARE_BITMAP(isa, RISCV_ISA_VENDOR_EXT_MAX);
21 };
22 
23 struct riscv_isa_vendor_ext_data_list {
24 	bool is_initialized;
25 	const size_t ext_data_count;
26 	const struct riscv_isa_ext_data *ext_data;
27 	struct riscv_isavendorinfo per_hart_isa_bitmap[NR_CPUS];
28 	struct riscv_isavendorinfo all_harts_isa_bitmap;
29 };
30 
31 extern struct riscv_isa_vendor_ext_data_list *riscv_isa_vendor_ext_list[];
32 
33 extern const size_t riscv_isa_vendor_ext_list_size;
34 
35 /*
36  * The alternatives need some way of distinguishing between vendor extensions
37  * and errata. Incrementing all of the vendor extension keys so they are at
38  * least 0x8000 accomplishes that.
39  */
40 #define RISCV_VENDOR_EXT_ALTERNATIVES_BASE	0x8000
41 
42 #define VENDOR_EXT_ALL_CPUS			-1
43 
44 bool __riscv_isa_vendor_extension_available(int cpu, unsigned long vendor, unsigned int bit);
45 #define riscv_cpu_isa_vendor_extension_available(cpu, vendor, ext)	\
46 	__riscv_isa_vendor_extension_available(cpu, vendor, RISCV_ISA_VENDOR_EXT_##ext)
47 #define riscv_isa_vendor_extension_available(vendor, ext)	\
48 	__riscv_isa_vendor_extension_available(VENDOR_EXT_ALL_CPUS, vendor, \
49 					       RISCV_ISA_VENDOR_EXT_##ext)
50 
51 static __always_inline bool riscv_has_vendor_extension_likely(const unsigned long vendor,
52 							      const unsigned long ext)
53 {
54 	if (!IS_ENABLED(CONFIG_RISCV_ISA_VENDOR_EXT))
55 		return false;
56 
57 	if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE))
58 		return __riscv_has_extension_likely(vendor,
59 						    ext + RISCV_VENDOR_EXT_ALTERNATIVES_BASE);
60 
61 	return __riscv_isa_vendor_extension_available(VENDOR_EXT_ALL_CPUS, vendor, ext);
62 }
63 
64 static __always_inline bool riscv_has_vendor_extension_unlikely(const unsigned long vendor,
65 								const unsigned long ext)
66 {
67 	if (!IS_ENABLED(CONFIG_RISCV_ISA_VENDOR_EXT))
68 		return false;
69 
70 	if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE))
71 		return __riscv_has_extension_unlikely(vendor,
72 						      ext + RISCV_VENDOR_EXT_ALTERNATIVES_BASE);
73 
74 	return __riscv_isa_vendor_extension_available(VENDOR_EXT_ALL_CPUS, vendor, ext);
75 }
76 
77 static __always_inline bool riscv_cpu_has_vendor_extension_likely(const unsigned long vendor,
78 								  int cpu, const unsigned long ext)
79 {
80 	if (!IS_ENABLED(CONFIG_RISCV_ISA_VENDOR_EXT))
81 		return false;
82 
83 	if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE) &&
84 	    __riscv_has_extension_likely(vendor, ext + RISCV_VENDOR_EXT_ALTERNATIVES_BASE))
85 		return true;
86 
87 	return __riscv_isa_vendor_extension_available(cpu, vendor, ext);
88 }
89 
90 static __always_inline bool riscv_cpu_has_vendor_extension_unlikely(const unsigned long vendor,
91 								    int cpu,
92 								    const unsigned long ext)
93 {
94 	if (!IS_ENABLED(CONFIG_RISCV_ISA_VENDOR_EXT))
95 		return false;
96 
97 	if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE) &&
98 	    __riscv_has_extension_unlikely(vendor, ext + RISCV_VENDOR_EXT_ALTERNATIVES_BASE))
99 		return true;
100 
101 	return __riscv_isa_vendor_extension_available(cpu, vendor, ext);
102 }
103 
104 #endif /* _ASM_VENDOR_EXTENSIONS_H */
105