hc
2023-12-11 d2ccde1c8e90d38cee87a1b0309ad2827f3fd30d
kernel/arch/riscv/kernel/cpufeature.c
....@@ -1,33 +1,70 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12 /*
23 * Copied from arch/arm64/kernel/cpufeature.c
34 *
45 * Copyright (C) 2015 ARM Ltd.
56 * Copyright (C) 2017 SiFive
6
- *
7
- * This program is free software; you can redistribute it and/or modify
8
- * it under the terms of the GNU General Public License version 2 as
9
- * published by the Free Software Foundation.
10
- *
11
- * This program is distributed in the hope that it will be useful,
12
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
- * GNU General Public License for more details.
15
- *
16
- * You should have received a copy of the GNU General Public License
17
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
187 */
198
9
+#include <linux/bitmap.h>
2010 #include <linux/of.h>
2111 #include <asm/processor.h>
2212 #include <asm/hwcap.h>
13
+#include <asm/smp.h>
14
+#include <asm/switch_to.h>
2315
2416 unsigned long elf_hwcap __read_mostly;
17
+
18
+/* Host ISA bitmap */
19
+static DECLARE_BITMAP(riscv_isa, RISCV_ISA_EXT_MAX) __read_mostly;
20
+
21
+#ifdef CONFIG_FPU
22
+bool has_fpu __read_mostly;
23
+#endif
24
+
25
+/**
26
+ * riscv_isa_extension_base() - Get base extension word
27
+ *
28
+ * @isa_bitmap: ISA bitmap to use
29
+ * Return: base extension word as unsigned long value
30
+ *
31
+ * NOTE: If isa_bitmap is NULL then Host ISA bitmap will be used.
32
+ */
33
+unsigned long riscv_isa_extension_base(const unsigned long *isa_bitmap)
34
+{
35
+ if (!isa_bitmap)
36
+ return riscv_isa[0];
37
+ return isa_bitmap[0];
38
+}
39
+EXPORT_SYMBOL_GPL(riscv_isa_extension_base);
40
+
41
+/**
42
+ * __riscv_isa_extension_available() - Check whether given extension
43
+ * is available or not
44
+ *
45
+ * @isa_bitmap: ISA bitmap to use
46
+ * @bit: bit position of the desired extension
47
+ * Return: true or false
48
+ *
49
+ * NOTE: If isa_bitmap is NULL then Host ISA bitmap will be used.
50
+ */
51
+bool __riscv_isa_extension_available(const unsigned long *isa_bitmap, int bit)
52
+{
53
+ const unsigned long *bmap = (isa_bitmap) ? isa_bitmap : riscv_isa;
54
+
55
+ if (bit >= RISCV_ISA_EXT_MAX)
56
+ return false;
57
+
58
+ return test_bit(bit, bmap) ? true : false;
59
+}
60
+EXPORT_SYMBOL_GPL(__riscv_isa_extension_available);
2561
2662 void riscv_fill_hwcap(void)
2763 {
2864 struct device_node *node;
2965 const char *isa;
30
- size_t i;
66
+ char print_str[BITS_PER_LONG + 1];
67
+ size_t i, j, isa_len;
3168 static unsigned long isa2hwcap[256] = {0};
3269
3370 isa2hwcap['i'] = isa2hwcap['I'] = COMPAT_HWCAP_ISA_I;
....@@ -39,23 +76,76 @@
3976
4077 elf_hwcap = 0;
4178
42
- /*
43
- * We don't support running Linux on hertergenous ISA systems. For
44
- * now, we just check the ISA of the first processor.
45
- */
46
- node = of_find_node_by_type(NULL, "cpu");
47
- if (!node) {
48
- pr_warning("Unable to find \"cpu\" devicetree entry");
49
- return;
79
+ bitmap_zero(riscv_isa, RISCV_ISA_EXT_MAX);
80
+
81
+ for_each_of_cpu_node(node) {
82
+ unsigned long this_hwcap = 0;
83
+ unsigned long this_isa = 0;
84
+
85
+ if (riscv_of_processor_hartid(node) < 0)
86
+ continue;
87
+
88
+ if (of_property_read_string(node, "riscv,isa", &isa)) {
89
+ pr_warn("Unable to find \"riscv,isa\" devicetree entry\n");
90
+ continue;
91
+ }
92
+
93
+ i = 0;
94
+ isa_len = strlen(isa);
95
+#if IS_ENABLED(CONFIG_32BIT)
96
+ if (!strncmp(isa, "rv32", 4))
97
+ i += 4;
98
+#elif IS_ENABLED(CONFIG_64BIT)
99
+ if (!strncmp(isa, "rv64", 4))
100
+ i += 4;
101
+#endif
102
+ for (; i < isa_len; ++i) {
103
+ this_hwcap |= isa2hwcap[(unsigned char)(isa[i])];
104
+ /*
105
+ * TODO: X, Y and Z extension parsing for Host ISA
106
+ * bitmap will be added in-future.
107
+ */
108
+ if ('a' <= isa[i] && isa[i] < 'x')
109
+ this_isa |= (1UL << (isa[i] - 'a'));
110
+ }
111
+
112
+ /*
113
+ * All "okay" hart should have same isa. Set HWCAP based on
114
+ * common capabilities of every "okay" hart, in case they don't
115
+ * have.
116
+ */
117
+ if (elf_hwcap)
118
+ elf_hwcap &= this_hwcap;
119
+ else
120
+ elf_hwcap = this_hwcap;
121
+
122
+ if (riscv_isa[0])
123
+ riscv_isa[0] &= this_isa;
124
+ else
125
+ riscv_isa[0] = this_isa;
50126 }
51127
52
- if (of_property_read_string(node, "riscv,isa", &isa)) {
53
- pr_warning("Unable to find \"riscv,isa\" devicetree entry");
54
- return;
128
+ /* We don't support systems with F but without D, so mask those out
129
+ * here. */
130
+ if ((elf_hwcap & COMPAT_HWCAP_ISA_F) && !(elf_hwcap & COMPAT_HWCAP_ISA_D)) {
131
+ pr_info("This kernel does not support systems with F but not D\n");
132
+ elf_hwcap &= ~COMPAT_HWCAP_ISA_F;
55133 }
56134
57
- for (i = 0; i < strlen(isa); ++i)
58
- elf_hwcap |= isa2hwcap[(unsigned char)(isa[i])];
135
+ memset(print_str, 0, sizeof(print_str));
136
+ for (i = 0, j = 0; i < BITS_PER_LONG; i++)
137
+ if (riscv_isa[0] & BIT_MASK(i))
138
+ print_str[j++] = (char)('a' + i);
139
+ pr_info("riscv: ISA extensions %s\n", print_str);
59140
60
- pr_info("elf_hwcap is 0x%lx", elf_hwcap);
141
+ memset(print_str, 0, sizeof(print_str));
142
+ for (i = 0, j = 0; i < BITS_PER_LONG; i++)
143
+ if (elf_hwcap & BIT_MASK(i))
144
+ print_str[j++] = (char)('a' + i);
145
+ pr_info("riscv: ELF capabilities %s\n", print_str);
146
+
147
+#ifdef CONFIG_FPU
148
+ if (elf_hwcap & (COMPAT_HWCAP_ISA_F | COMPAT_HWCAP_ISA_D))
149
+ has_fpu = true;
150
+#endif
61151 }