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