cpufeature.c (779fda86bdeb86bad6daa4f0ecf37788dfc26f6c) cpufeature.c (1631ba1259d6d7f49b6028f2a1a0fa02be1c522a)
1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * Copied from arch/arm64/kernel/cpufeature.c
4 *
5 * Copyright (C) 2015 ARM Ltd.
6 * Copyright (C) 2017 SiFive
7 */
8
9#include <linux/bitmap.h>
10#include <linux/ctype.h>
11#include <linux/libfdt.h>
12#include <linux/module.h>
13#include <linux/of.h>
14#include <asm/alternative.h>
1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * Copied from arch/arm64/kernel/cpufeature.c
4 *
5 * Copyright (C) 2015 ARM Ltd.
6 * Copyright (C) 2017 SiFive
7 */
8
9#include <linux/bitmap.h>
10#include <linux/ctype.h>
11#include <linux/libfdt.h>
12#include <linux/module.h>
13#include <linux/of.h>
14#include <asm/alternative.h>
15#include <asm/cacheflush.h>
15#include <asm/errata_list.h>
16#include <asm/hwcap.h>
17#include <asm/patch.h>
18#include <asm/pgtable.h>
19#include <asm/processor.h>
20#include <asm/smp.h>
21#include <asm/switch_to.h>
22
23#define NUM_ALPHA_EXTS ('z' - 'a' + 1)
24
25unsigned long elf_hwcap __read_mostly;
26
27/* Host ISA bitmap */
28static DECLARE_BITMAP(riscv_isa, RISCV_ISA_EXT_MAX) __read_mostly;
29
16#include <asm/errata_list.h>
17#include <asm/hwcap.h>
18#include <asm/patch.h>
19#include <asm/pgtable.h>
20#include <asm/processor.h>
21#include <asm/smp.h>
22#include <asm/switch_to.h>
23
24#define NUM_ALPHA_EXTS ('z' - 'a' + 1)
25
26unsigned long elf_hwcap __read_mostly;
27
28/* Host ISA bitmap */
29static DECLARE_BITMAP(riscv_isa, RISCV_ISA_EXT_MAX) __read_mostly;
30
30#ifdef CONFIG_FPU
31__ro_after_init DEFINE_STATIC_KEY_FALSE(cpu_hwcap_fpu);
32#endif
31__ro_after_init DEFINE_STATIC_KEY_ARRAY_FALSE(riscv_isa_ext_keys, RISCV_ISA_EXT_KEY_MAX);
32EXPORT_SYMBOL(riscv_isa_ext_keys);
33
34/**
35 * riscv_isa_extension_base() - Get base extension word
36 *
37 * @isa_bitmap: ISA bitmap to use
38 * Return: base extension word as unsigned long value
39 *
40 * NOTE: If isa_bitmap is NULL then Host ISA bitmap will be used.

--- 153 unchanged lines hidden (view full) ---

194 if (unlikely(ext_err))
195 continue;
196 if (!ext_long) {
197 this_hwcap |= isa2hwcap[(unsigned char)(*ext)];
198 set_bit(*ext - 'a', this_isa);
199 } else {
200 SET_ISA_EXT_MAP("sscofpmf", RISCV_ISA_EXT_SSCOFPMF);
201 SET_ISA_EXT_MAP("svpbmt", RISCV_ISA_EXT_SVPBMT);
33
34/**
35 * riscv_isa_extension_base() - Get base extension word
36 *
37 * @isa_bitmap: ISA bitmap to use
38 * Return: base extension word as unsigned long value
39 *
40 * NOTE: If isa_bitmap is NULL then Host ISA bitmap will be used.

--- 153 unchanged lines hidden (view full) ---

194 if (unlikely(ext_err))
195 continue;
196 if (!ext_long) {
197 this_hwcap |= isa2hwcap[(unsigned char)(*ext)];
198 set_bit(*ext - 'a', this_isa);
199 } else {
200 SET_ISA_EXT_MAP("sscofpmf", RISCV_ISA_EXT_SSCOFPMF);
201 SET_ISA_EXT_MAP("svpbmt", RISCV_ISA_EXT_SVPBMT);
202 SET_ISA_EXT_MAP("zicbom", RISCV_ISA_EXT_ZICBOM);
202 }
203#undef SET_ISA_EXT_MAP
204 }
205
206 /*
207 * All "okay" hart should have same isa. Set HWCAP based on
208 * common capabilities of every "okay" hart, in case they don't
209 * have.

--- 23 unchanged lines hidden (view full) ---

233 pr_info("riscv: base ISA extensions %s\n", print_str);
234
235 memset(print_str, 0, sizeof(print_str));
236 for (i = 0, j = 0; i < NUM_ALPHA_EXTS; i++)
237 if (elf_hwcap & BIT_MASK(i))
238 print_str[j++] = (char)('a' + i);
239 pr_info("riscv: ELF capabilities %s\n", print_str);
240
203 }
204#undef SET_ISA_EXT_MAP
205 }
206
207 /*
208 * All "okay" hart should have same isa. Set HWCAP based on
209 * common capabilities of every "okay" hart, in case they don't
210 * have.

--- 23 unchanged lines hidden (view full) ---

234 pr_info("riscv: base ISA extensions %s\n", print_str);
235
236 memset(print_str, 0, sizeof(print_str));
237 for (i = 0, j = 0; i < NUM_ALPHA_EXTS; i++)
238 if (elf_hwcap & BIT_MASK(i))
239 print_str[j++] = (char)('a' + i);
240 pr_info("riscv: ELF capabilities %s\n", print_str);
241
241#ifdef CONFIG_FPU
242 if (elf_hwcap & (COMPAT_HWCAP_ISA_F | COMPAT_HWCAP_ISA_D))
243 static_branch_enable(&cpu_hwcap_fpu);
244#endif
242 for_each_set_bit(i, riscv_isa, RISCV_ISA_EXT_MAX) {
243 j = riscv_isa_ext2key(i);
244 if (j >= 0)
245 static_branch_enable(&riscv_isa_ext_keys[j]);
246 }
245}
246
247#ifdef CONFIG_RISCV_ALTERNATIVE
247}
248
249#ifdef CONFIG_RISCV_ALTERNATIVE
248struct cpufeature_info {
249 char name[ERRATA_STRING_LENGTH_MAX];
250 bool (*check_func)(unsigned int stage);
251};
252
253static bool __init_or_module cpufeature_svpbmt_check_func(unsigned int stage)
250static bool __init_or_module cpufeature_probe_svpbmt(unsigned int stage)
254{
255#ifdef CONFIG_RISCV_ISA_SVPBMT
256 switch (stage) {
257 case RISCV_ALTERNATIVES_EARLY_BOOT:
258 return false;
259 default:
260 return riscv_isa_extension_available(NULL, SVPBMT);
261 }
262#endif
263
264 return false;
265}
266
251{
252#ifdef CONFIG_RISCV_ISA_SVPBMT
253 switch (stage) {
254 case RISCV_ALTERNATIVES_EARLY_BOOT:
255 return false;
256 default:
257 return riscv_isa_extension_available(NULL, SVPBMT);
258 }
259#endif
260
261 return false;
262}
263
267static const struct cpufeature_info __initdata_or_module
268cpufeature_list[CPUFEATURE_NUMBER] = {
269 {
270 .name = "svpbmt",
271 .check_func = cpufeature_svpbmt_check_func
272 },
273};
264static bool __init_or_module cpufeature_probe_zicbom(unsigned int stage)
265{
266#ifdef CONFIG_RISCV_ISA_ZICBOM
267 switch (stage) {
268 case RISCV_ALTERNATIVES_EARLY_BOOT:
269 return false;
270 default:
271 if (riscv_isa_extension_available(NULL, ZICBOM)) {
272 riscv_noncoherent_supported();
273 return true;
274 } else {
275 return false;
276 }
277 }
278#endif
274
279
280 return false;
281}
282
283/*
284 * Probe presence of individual extensions.
285 *
286 * This code may also be executed before kernel relocation, so we cannot use
287 * addresses generated by the address-of operator as they won't be valid in
288 * this context.
289 */
275static u32 __init_or_module cpufeature_probe(unsigned int stage)
276{
290static u32 __init_or_module cpufeature_probe(unsigned int stage)
291{
277 const struct cpufeature_info *info;
278 u32 cpu_req_feature = 0;
292 u32 cpu_req_feature = 0;
279 int idx;
280
293
281 for (idx = 0; idx < CPUFEATURE_NUMBER; idx++) {
282 info = &cpufeature_list[idx];
294 if (cpufeature_probe_svpbmt(stage))
295 cpu_req_feature |= (1U << CPUFEATURE_SVPBMT);
283
296
284 if (info->check_func(stage))
285 cpu_req_feature |= (1U << idx);
286 }
297 if (cpufeature_probe_zicbom(stage))
298 cpu_req_feature |= (1U << CPUFEATURE_ZICBOM);
287
288 return cpu_req_feature;
289}
290
291void __init_or_module riscv_cpufeature_patch_func(struct alt_entry *begin,
292 struct alt_entry *end,
293 unsigned int stage)
294{

--- 19 unchanged lines hidden ---
299
300 return cpu_req_feature;
301}
302
303void __init_or_module riscv_cpufeature_patch_func(struct alt_entry *begin,
304 struct alt_entry *end,
305 unsigned int stage)
306{

--- 19 unchanged lines hidden ---