Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
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
19struct riscv_isavendorinfo {
20 DECLARE_BITMAP(isa, RISCV_ISA_VENDOR_EXT_MAX);
21};
22
23struct 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
31extern struct riscv_isa_vendor_ext_data_list *riscv_isa_vendor_ext_list[];
32
33extern 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
44bool __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
51static __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
64static __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
77static __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
90static __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 */