Messages in this thread Patch in this message |  | | From | Atish Patra <> | Subject | [PATCH v7 09/10] RISC-V: Add supported for ordered booting method using HSM | Date | Mon, 27 Jan 2020 18:27:36 -0800 |
| |
Currently, all harts have to jump Linux in RISC-V. This complicates the multi-stage boot process as every transient stage also has to ensure all harts enter to that stage and jump to Linux afterwards. It also obstructs a clean Kexec implementation.
SBI HSM extension provides alternate solutions where only a single hart need to boot and enter Linux. The booting hart can bring up secondary harts one by one afterwards.
Add SBI HSM based cpu_ops that implements an ordered booting method in RISC-V. This change is also backward compatible with older firmware not implementing HSM extension. If a latest kernel is used with older firmware, it will continue to use the default spinning booting method.
Signed-off-by: Atish Patra <atish.patra@wdc.com> --- arch/riscv/kernel/cpu_ops.c | 41 ++++++++++++++++++++++++++++++++++++- arch/riscv/kernel/head.S | 25 ++++++++++++++++++++++ arch/riscv/kernel/smpboot.c | 2 +- arch/riscv/kernel/traps.c | 2 +- 4 files changed, 67 insertions(+), 3 deletions(-)
diff --git a/arch/riscv/kernel/cpu_ops.c b/arch/riscv/kernel/cpu_ops.c index 099dbb6ff9f0..454df032066f 100644 --- a/arch/riscv/kernel/cpu_ops.c +++ b/arch/riscv/kernel/cpu_ops.c @@ -17,9 +17,13 @@ const struct cpu_operations *cpu_ops[NR_CPUS] __ro_after_init; void *__cpu_up_stack_pointer[NR_CPUS]; void *__cpu_up_task_pointer[NR_CPUS]; +extern char secondary_start_sbi[]; +const struct cpu_operations cpu_sbi_ops; const struct cpu_operations cpu_spinwait_ops; +#define RISCV_HART_FIRMWARE_STOPPED 0 + static int spinwait_cpu_prepare(unsigned int cpuid) { if (!cpu_spinwait_ops.cpu_start) { @@ -29,6 +33,32 @@ static int spinwait_cpu_prepare(unsigned int cpuid) return 0; } +static int sbi_cpu_prepare(unsigned int cpuid) +{ + if (!cpu_sbi_ops.cpu_start) { + pr_err("cpu start method not defined for CPU [%d]\n", cpuid); + return -ENODEV; + } + return 0; +} + +static int sbi_cpu_start(unsigned int cpuid, struct task_struct *tidle) +{ + int rc; + int hartid = cpuid_to_hartid_map(cpuid); + unsigned long boot_addr = __pa_symbol(secondary_start_sbi); + + /* Make sure tidle is updated */ + smp_mb(); + WRITE_ONCE(__cpu_up_stack_pointer[hartid], + task_stack_page(tidle) + THREAD_SIZE); + WRITE_ONCE(__cpu_up_task_pointer[hartid], tidle); + + rc = sbi_hsm_hart_start(hartid, boot_addr, 0); + + return rc; +} + static int spinwait_cpu_start(unsigned int cpuid, struct task_struct *tidle) { int hartid = cpuid_to_hartid_map(cpuid); @@ -48,6 +78,12 @@ static int spinwait_cpu_start(unsigned int cpuid, struct task_struct *tidle) return 0; } +const struct cpu_operations cpu_sbi_ops = { + .name = "sbi", + .cpu_prepare = sbi_cpu_prepare, + .cpu_start = sbi_cpu_start, +}; + const struct cpu_operations cpu_spinwait_ops = { .name = "spinwait", .cpu_prepare = spinwait_cpu_prepare, @@ -56,6 +92,9 @@ const struct cpu_operations cpu_spinwait_ops = { int __init cpu_set_ops(int cpuid) { - cpu_ops[cpuid] = &cpu_spinwait_ops; + if (sbi_hsm_is_available()) + cpu_ops[cpuid] = &cpu_sbi_ops; + else + cpu_ops[cpuid] = &cpu_spinwait_ops; return 0; } diff --git a/arch/riscv/kernel/head.S b/arch/riscv/kernel/head.S index 9d7f084a50cc..3c93973667c8 100644 --- a/arch/riscv/kernel/head.S +++ b/arch/riscv/kernel/head.S @@ -210,11 +210,36 @@ relocate: ret #endif /* CONFIG_MMU */ #ifdef CONFIG_SMP + .global secondary_start_sbi +secondary_start_sbi: + /* Mask all interrupts */ + csrw CSR_IE, zero + csrw CSR_IP, zero + + /* Load the global pointer */ + .option push + .option norelax + la gp, __global_pointer$ + .option pop + + /* + * Disable FPU to detect illegal usage of + * floating point in kernel space + */ + li t0, SR_FS + csrc CSR_STATUS, t0 + /* Set trap vector to spin forever to help debug */ la a3, .Lsecondary_park csrw CSR_TVEC, a3 slli a3, a0, LGREG + la a4, __cpu_up_stack_pointer + la a5, __cpu_up_task_pointer + add a4, a3, a4 + add a5, a3, a5 + REG_L sp, (a4) + REG_L tp, (a5) .global secondary_start_common secondary_start_common: diff --git a/arch/riscv/kernel/smpboot.c b/arch/riscv/kernel/smpboot.c index f2cf541bc895..8ac9115001b9 100644 --- a/arch/riscv/kernel/smpboot.c +++ b/arch/riscv/kernel/smpboot.c @@ -144,7 +144,7 @@ void __init smp_cpus_done(unsigned int max_cpus) /* * C entry point for a secondary processor. */ -asmlinkage __visible void __init smp_callin(void) +asmlinkage __visible void smp_callin(void) { struct mm_struct *mm = &init_mm; diff --git a/arch/riscv/kernel/traps.c b/arch/riscv/kernel/traps.c index f4cad5163bf2..0063dd7318d6 100644 --- a/arch/riscv/kernel/traps.c +++ b/arch/riscv/kernel/traps.c @@ -147,7 +147,7 @@ int is_valid_bugaddr(unsigned long pc) } #endif /* CONFIG_GENERIC_BUG */ -void __init trap_init(void) +void trap_init(void) { /* * Set sup0 scratch register to 0, indicating to exception vector -- 2.24.0
|  |