.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * Copied from arch/arm64/kernel/cpufeature.c |
---|
3 | 4 | * |
---|
4 | 5 | * Copyright (C) 2015 ARM Ltd. |
---|
5 | 6 | * 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 | 7 | */ |
---|
19 | 8 | |
---|
| 9 | +#include <linux/bitmap.h> |
---|
20 | 10 | #include <linux/of.h> |
---|
21 | 11 | #include <asm/processor.h> |
---|
22 | 12 | #include <asm/hwcap.h> |
---|
| 13 | +#include <asm/smp.h> |
---|
| 14 | +#include <asm/switch_to.h> |
---|
23 | 15 | |
---|
24 | 16 | 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); |
---|
25 | 61 | |
---|
26 | 62 | void riscv_fill_hwcap(void) |
---|
27 | 63 | { |
---|
28 | 64 | struct device_node *node; |
---|
29 | 65 | const char *isa; |
---|
30 | | - size_t i; |
---|
| 66 | + char print_str[BITS_PER_LONG + 1]; |
---|
| 67 | + size_t i, j, isa_len; |
---|
31 | 68 | static unsigned long isa2hwcap[256] = {0}; |
---|
32 | 69 | |
---|
33 | 70 | isa2hwcap['i'] = isa2hwcap['I'] = COMPAT_HWCAP_ISA_I; |
---|
.. | .. |
---|
39 | 76 | |
---|
40 | 77 | elf_hwcap = 0; |
---|
41 | 78 | |
---|
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; |
---|
50 | 126 | } |
---|
51 | 127 | |
---|
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; |
---|
55 | 133 | } |
---|
56 | 134 | |
---|
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); |
---|
59 | 140 | |
---|
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 |
---|
61 | 151 | } |
---|