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