aboutsummaryrefslogtreecommitdiffstats
path: root/arch/riscv/kernel/cpufeature.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/riscv/kernel/cpufeature.c')
-rw-r--r--arch/riscv/kernel/cpufeature.c61
1 files changed, 27 insertions, 34 deletions
diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c
index a6e369edbbd7..b1ade9a49347 100644
--- a/arch/riscv/kernel/cpufeature.c
+++ b/arch/riscv/kernel/cpufeature.c
@@ -1,25 +1,15 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copied from arch/arm64/kernel/cpufeature.c
*
* Copyright (C) 2015 ARM Ltd.
* Copyright (C) 2017 SiFive
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/of.h>
#include <asm/processor.h>
#include <asm/hwcap.h>
+#include <asm/smp.h>
unsigned long elf_hwcap __read_mostly;
#ifdef CONFIG_FPU
@@ -28,7 +18,7 @@ bool has_fpu __read_mostly;
void riscv_fill_hwcap(void)
{
- struct device_node *node = NULL;
+ struct device_node *node;
const char *isa;
size_t i;
static unsigned long isa2hwcap[256] = {0};
@@ -42,36 +32,39 @@ void riscv_fill_hwcap(void)
elf_hwcap = 0;
- /*
- * We don't support running Linux on hertergenous ISA systems. For
- * now, we just check the ISA of the first "okay" processor.
- */
- while ((node = of_find_node_by_type(node, "cpu")))
- if (riscv_of_processor_hartid(node) >= 0)
- break;
- if (!node) {
- pr_warning("Unable to find \"cpu\" devicetree entry");
- return;
- }
+ for_each_of_cpu_node(node) {
+ unsigned long this_hwcap = 0;
- if (of_property_read_string(node, "riscv,isa", &isa)) {
- pr_warning("Unable to find \"riscv,isa\" devicetree entry");
- of_node_put(node);
- return;
- }
- of_node_put(node);
+ if (riscv_of_processor_hartid(node) < 0)
+ continue;
+
+ if (of_property_read_string(node, "riscv,isa", &isa)) {
+ pr_warn("Unable to find \"riscv,isa\" devicetree entry\n");
+ continue;
+ }
- for (i = 0; i < strlen(isa); ++i)
- elf_hwcap |= isa2hwcap[(unsigned char)(isa[i])];
+ for (i = 0; i < strlen(isa); ++i)
+ this_hwcap |= isa2hwcap[(unsigned char)(isa[i])];
+
+ /*
+ * All "okay" hart should have same isa. Set HWCAP based on
+ * common capabilities of every "okay" hart, in case they don't
+ * have.
+ */
+ if (elf_hwcap)
+ elf_hwcap &= this_hwcap;
+ else
+ elf_hwcap = this_hwcap;
+ }
/* We don't support systems with F but without D, so mask those out
* here. */
if ((elf_hwcap & COMPAT_HWCAP_ISA_F) && !(elf_hwcap & COMPAT_HWCAP_ISA_D)) {
- pr_info("This kernel does not support systems with F but not D");
+ pr_info("This kernel does not support systems with F but not D\n");
elf_hwcap &= ~COMPAT_HWCAP_ISA_F;
}
- pr_info("elf_hwcap is 0x%lx", elf_hwcap);
+ pr_info("elf_hwcap is 0x%lx\n", elf_hwcap);
#ifdef CONFIG_FPU
if (elf_hwcap & (COMPAT_HWCAP_ISA_F | COMPAT_HWCAP_ISA_D))