riscv: Introduce AVAILABLE_HARTS

In SMP all harts will register themself in available_hart
during start up. Then main hart will send IPI to other harts
according to this variables. But this mechanism may not
guarantee that all other harts can jump to next stage.

When main hart is sending IPI to other hart according to
available_harts, but other harts maybe still not finish the
registration. Then the SMP booting will miss some harts finally.
So let it become an option and it will be enabled by default.

Please refer to the discussion:
https://www.mail-archive.com/u-boot@lists.denx.de/msg449997.html

Signed-off-by: Rick Chen <rick@andestech.com>
Reviewed-by: Leo Yu-Chi Liang <ycliang@andestech.com>
This commit is contained in:
Rick Chen 2022-09-21 14:34:54 +08:00 committed by Leo Yu-Chi Liang
parent c2bdf02c9d
commit e0465f80bd
6 changed files with 23 additions and 5 deletions

View File

@ -276,6 +276,13 @@ config SPL_XIP
rely on lock variables (for example hart_lottery and available_harts_lock),
this affects only SPL, other stages should proceed as non-XIP.
config AVAILABLE_HARTS
bool "Send IPI by available harts"
default y
help
By default, IPI sending mechanism will depend on available_harts.
If disable this, it will send IPI by CPUs node numbers of device tree.
config SHOW_REGS
bool "Show registers on unhandled exception"

View File

@ -22,12 +22,14 @@
#if !CONFIG_IS_ENABLED(XIP)
u32 hart_lottery __section(".data") = 0;
#ifdef CONFIG_AVAILABLE_HARTS
/*
* The main hart running U-Boot has acquired available_harts_lock until it has
* finished initialization of global data.
*/
u32 available_harts_lock = 1;
#endif
#endif
static inline bool supports_extension(char ext)
{

View File

@ -153,21 +153,23 @@ call_harts_early_init:
SREG tp, GD_BOOT_HART(gp)
#if !CONFIG_IS_ENABLED(XIP)
#ifdef CONFIG_AVAILABLE_HARTS
la t0, available_harts_lock
amoswap.w.rl zero, zero, 0(t0)
#endif
wait_for_gd_init:
la t0, available_harts_lock
li t1, 1
1: amoswap.w.aq t1, t1, 0(t0)
bnez t1, 1b
/*
* Set the global data pointer only when gd_t has been initialized.
* This was already set by arch_setup_gd on the boot hart, but all other
* harts' global data pointers gets set here.
*/
mv gp, s0
#ifdef CONFIG_AVAILABLE_HARTS
la t0, available_harts_lock
li t1, 1
1: amoswap.w.aq t1, t1, 0(t0)
bnez t1, 1b
/* register available harts in the available_harts mask */
li t1, 1
@ -177,6 +179,7 @@ wait_for_gd_init:
SREG t2, GD_AVAILABLE_HARTS(gp)
amoswap.w.rl zero, zero, 0(t0)
#endif
/*
* Continue on hart lottery winner, others branch to

View File

@ -28,8 +28,10 @@ struct arch_global_data {
struct ipi_data ipi[CONFIG_NR_CPUS];
#endif
#if !CONFIG_IS_ENABLED(XIP)
#ifdef CONFIG_AVAILABLE_HARTS
ulong available_harts;
#endif
#endif
};
#include <asm-generic/global_data.h>

View File

@ -17,7 +17,9 @@ int main(void)
DEFINE(GD_BOOT_HART, offsetof(gd_t, arch.boot_hart));
DEFINE(GD_FIRMWARE_FDT_ADDR, offsetof(gd_t, arch.firmware_fdt_addr));
#if !CONFIG_IS_ENABLED(XIP)
#ifdef CONFIG_AVAILABLE_HARTS
DEFINE(GD_AVAILABLE_HARTS, offsetof(gd_t, arch.available_harts));
#endif
#endif
return 0;

View File

@ -46,9 +46,11 @@ static int send_ipi_many(struct ipi_data *ipi, int wait)
}
#if !CONFIG_IS_ENABLED(XIP)
#ifdef CONFIG_AVAILABLE_HARTS
/* skip if hart is not available */
if (!(gd->arch.available_harts & (1 << reg)))
continue;
#endif
#endif
gd->arch.ipi[reg].addr = ipi->addr;