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/of.h> 10 #include <asm/processor.h> 11 #include <asm/hwcap.h> 12 #include <asm/smp.h> 13 14 unsigned long elf_hwcap __read_mostly; 15 #ifdef CONFIG_FPU 16 bool has_fpu __read_mostly; 17 #endif 18 19 void riscv_fill_hwcap(void) 20 { 21 struct device_node *node; 22 const char *isa; 23 size_t i; 24 static unsigned long isa2hwcap[256] = {0}; 25 26 isa2hwcap['i'] = isa2hwcap['I'] = COMPAT_HWCAP_ISA_I; 27 isa2hwcap['m'] = isa2hwcap['M'] = COMPAT_HWCAP_ISA_M; 28 isa2hwcap['a'] = isa2hwcap['A'] = COMPAT_HWCAP_ISA_A; 29 isa2hwcap['f'] = isa2hwcap['F'] = COMPAT_HWCAP_ISA_F; 30 isa2hwcap['d'] = isa2hwcap['D'] = COMPAT_HWCAP_ISA_D; 31 isa2hwcap['c'] = isa2hwcap['C'] = COMPAT_HWCAP_ISA_C; 32 33 elf_hwcap = 0; 34 35 for_each_of_cpu_node(node) { 36 unsigned long this_hwcap = 0; 37 38 if (riscv_of_processor_hartid(node) < 0) 39 continue; 40 41 if (of_property_read_string(node, "riscv,isa", &isa)) { 42 pr_warn("Unable to find \"riscv,isa\" devicetree entry\n"); 43 continue; 44 } 45 46 for (i = 0; i < strlen(isa); ++i) 47 this_hwcap |= isa2hwcap[(unsigned char)(isa[i])]; 48 49 /* 50 * All "okay" hart should have same isa. Set HWCAP based on 51 * common capabilities of every "okay" hart, in case they don't 52 * have. 53 */ 54 if (elf_hwcap) 55 elf_hwcap &= this_hwcap; 56 else 57 elf_hwcap = this_hwcap; 58 } 59 60 /* We don't support systems with F but without D, so mask those out 61 * here. */ 62 if ((elf_hwcap & COMPAT_HWCAP_ISA_F) && !(elf_hwcap & COMPAT_HWCAP_ISA_D)) { 63 pr_info("This kernel does not support systems with F but not D\n"); 64 elf_hwcap &= ~COMPAT_HWCAP_ISA_F; 65 } 66 67 pr_info("elf_hwcap is 0x%lx\n", elf_hwcap); 68 69 #ifdef CONFIG_FPU 70 if (elf_hwcap & (COMPAT_HWCAP_ISA_F | COMPAT_HWCAP_ISA_D)) 71 has_fpu = true; 72 #endif 73 } 74