
Various specifications of riscv allow the number of hart to be greater than 32. The limit of 32 is determined by gd->arch.available_harts. We can eliminate this limitation through bitmaps. Currently, the number of hart is limited to 4095, and 4095 is the limit of the RISC-V Advanced Core Local Interruptor Specification.
Test on sifive unmatched.
Signed-off-by: Xiang W wxjstz@126.com --- Changes since v1:
* When NR_CPUS is very large, the value of GD_AVAILABLE_HARTS will overflow the immediate range of ld/lw. This patch fixes this problem
arch/riscv/Kconfig | 4 ++-- arch/riscv/cpu/start.S | 21 ++++++++++++++++----- arch/riscv/include/asm/global_data.h | 4 +++- arch/riscv/lib/smp.c | 2 +- 4 files changed, 22 insertions(+), 9 deletions(-)
diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index ba29e70acf..7b9c7f5bca 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -220,8 +220,8 @@ config SPL_SMP all, single processor machines.
config NR_CPUS - int "Maximum number of CPUs (2-32)" - range 2 32 + int "Maximum number of CPUs (2-4095)" + range 2 4095 depends on SMP || SPL_SMP default 8 help diff --git a/arch/riscv/cpu/start.S b/arch/riscv/cpu/start.S index 76850ec9be..92f3b78f29 100644 --- a/arch/riscv/cpu/start.S +++ b/arch/riscv/cpu/start.S @@ -166,11 +166,22 @@ wait_for_gd_init: mv gp, s0
/* register available harts in the available_harts mask */ - li t1, 1 - sll t1, t1, tp - LREG t2, GD_AVAILABLE_HARTS(gp) - or t2, t2, t1 - SREG t2, GD_AVAILABLE_HARTS(gp) + li t1, GD_AVAILABLE_HARTS + add t1, t1, gp + LREG t1, 0(t1) +#if defined(CONFIG_ARCH_RV64I) + srli t2, tp, 6 + slli t2, t2, 3 +#elif defined(CONFIG_ARCH_RV32I) + srli t2, tp, 5 + slli t2, t2, 2 +#endif + add t1, t1, t2 + LREG t2, 0(t1) + li t3, 1 + sll t3, t3, tp + or t2, t2, t3 + SREG t2, 0(t1)
amoswap.w.rl zero, zero, 0(t0)
diff --git a/arch/riscv/include/asm/global_data.h b/arch/riscv/include/asm/global_data.h index 095484a635..6de2ee0b25 100644 --- a/arch/riscv/include/asm/global_data.h +++ b/arch/riscv/include/asm/global_data.h @@ -10,9 +10,11 @@ #ifndef __ASM_GBL_DATA_H #define __ASM_GBL_DATA_H
+#include <config.h> #include <asm/smp.h> #include <asm/u-boot.h> #include <compiler.h> +#include <linux/bitops.h>
/* Architecture-specific global data */ struct arch_global_data { @@ -28,7 +30,7 @@ struct arch_global_data { struct ipi_data ipi[CONFIG_NR_CPUS]; #endif #ifndef CONFIG_XIP - ulong available_harts; + ulong available_harts[BITS_TO_LONGS(CONFIG_NR_CPUS)]; #endif };
diff --git a/arch/riscv/lib/smp.c b/arch/riscv/lib/smp.c index ba992100ad..e8e391fd41 100644 --- a/arch/riscv/lib/smp.c +++ b/arch/riscv/lib/smp.c @@ -47,7 +47,7 @@ static int send_ipi_many(struct ipi_data *ipi, int wait)
#ifndef CONFIG_XIP /* skip if hart is not available */ - if (!(gd->arch.available_harts & (1 << reg))) + if (!test_bit(reg, gd->arch.available_harts)) continue; #endif