RISC-V: Avoid using per cpu array for ordered booting
authorAtish Patra <atishp@rivosinc.com>
Mon, 30 May 2022 04:33:31 +0000 (12:33 +0800)
committermason.huo <mason.huo@starfivetech.com>
Thu, 27 Oct 2022 05:54:44 +0000 (13:54 +0800)
Currently both order booting and spinwait approach uses a per cpu
array to update stack & task pointer. This approach will not work for the
following cases.
1. If NR_CPUs are configured to be less than highest hart id.
2. A platform has sparse hartid.

This issue can be fixed for ordered booting as the booting cpu brings up
one cpu at a time using SBI HSM extension which has opaque parameter
that is unused until now.

Introduce a common secondary boot data structure that can store the stack
and task pointer. Secondary harts will use this data while booting up
to setup the sp & tp.

Reviewed-by: Anup Patel <anup@brainfault.org>
Signed-off-by: Palmer Dabbelt <palmer@rivosinc.com>
From 9a2451f1866344d38b4a1dc20396e3a03954fcd7
Resolved merge conflict.

Signed-off-by: <jeeheng.sia@starfivetech.com>
Signed-off-by: minda.chen <minda.chen@starfivetech.com>
arch/riscv/include/asm/cpu_ops_sbi.h [new file with mode: 0644]
arch/riscv/kernel/asm-offsets.c
arch/riscv/kernel/cpu_ops_sbi.c
arch/riscv/kernel/head.S

diff --git a/arch/riscv/include/asm/cpu_ops_sbi.h b/arch/riscv/include/asm/cpu_ops_sbi.h
new file mode 100644 (file)
index 0000000..56e4b76
--- /dev/null
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2021 by Rivos Inc.
+ */
+#ifndef __ASM_CPU_OPS_SBI_H
+#define __ASM_CPU_OPS_SBI_H
+
+#ifndef __ASSEMBLY__
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/threads.h>
+
+/**
+ * struct sbi_hart_boot_data - Hart specific boot used during booting and
+ *                            cpu hotplug.
+ * @task_ptr: A pointer to the hart specific tp
+ * @stack_ptr: A pointer to the hart specific sp
+ */
+struct sbi_hart_boot_data {
+       void *task_ptr;
+       void *stack_ptr;
+};
+#endif
+
+#endif /* ifndef __ASM_CPU_OPS_SBI_H */
index 5eae199..9ec6731 100644 (file)
@@ -11,6 +11,7 @@
 #include <asm/thread_info.h>
 #include <asm/ptrace.h>
 #include <asm/suspend.h>
+#include <asm/cpu_ops_sbi.h>
 
 void asm_offsets(void);
 
@@ -316,4 +317,6 @@ void asm_offsets(void)
        DEFINE(PT_SIZE_ON_STACK, ALIGN(sizeof(struct pt_regs), STACK_ALIGN));
 
        OFFSET(KERNEL_MAP_VIRT_ADDR, kernel_mapping, virt_addr);
+       OFFSET(SBI_HART_BOOT_TASK_PTR_OFFSET, sbi_hart_boot_data, task_ptr);
+       OFFSET(SBI_HART_BOOT_STACK_PTR_OFFSET, sbi_hart_boot_data, stack_ptr);
 }
index 5fd90f0..2e16f67 100644 (file)
@@ -7,13 +7,22 @@
 
 #include <linux/init.h>
 #include <linux/mm.h>
+#include <linux/sched/task_stack.h>
 #include <asm/cpu_ops.h>
+#include <asm/cpu_ops_sbi.h>
 #include <asm/sbi.h>
 #include <asm/smp.h>
 
 extern char secondary_start_sbi[];
 const struct cpu_operations cpu_ops_sbi;
 
+/*
+ * Ordered booting via HSM brings one cpu at a time. However, cpu hotplug can
+ * be invoked from multiple threads in parallel. Define a per cpu data
+ * to handle that.
+ */
+DEFINE_PER_CPU(struct sbi_hart_boot_data, boot_data);
+
 static int sbi_hsm_hart_start(unsigned long hartid, unsigned long saddr,
                              unsigned long priv)
 {
@@ -55,14 +64,19 @@ static int sbi_hsm_hart_get_status(unsigned long hartid)
 
 static int sbi_cpu_start(unsigned int cpuid, struct task_struct *tidle)
 {
-       int rc;
        unsigned long boot_addr = __pa_symbol(secondary_start_sbi);
        int hartid = cpuid_to_hartid_map(cpuid);
-
-       cpu_update_secondary_bootdata(cpuid, tidle);
-       rc = sbi_hsm_hart_start(hartid, boot_addr, 0);
-
-       return rc;
+       unsigned long hsm_data;
+       struct sbi_hart_boot_data *bdata = &per_cpu(boot_data, cpuid);
+
+       /* Make sure tidle is updated */
+       smp_mb();
+       bdata->task_ptr = tidle;
+       bdata->stack_ptr = task_stack_page(tidle) + THREAD_SIZE;
+       /* Make sure boot data is updated */
+       smp_mb();
+       hsm_data = __pa(bdata);
+       return sbi_hsm_hart_start(hartid, boot_addr, hsm_data);
 }
 
 static int sbi_cpu_prepare(unsigned int cpuid)
index 25baa19..2fc8617 100644 (file)
@@ -11,6 +11,7 @@
 #include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/csr.h>
+#include <asm/cpu_ops_sbi.h>
 #include <asm/hwcap.h>
 #include <asm/image.h>
 #include "efi-header.S"
@@ -147,18 +148,17 @@ secondary_start_sbi:
        la a3, .Lsecondary_park
        csrw CSR_TVEC, a3
 
-       slli a3, a0, LGREG
-       la a4, __cpu_up_stack_pointer
-       XIP_FIXUP_OFFSET a4
-       la a5, __cpu_up_task_pointer
-       XIP_FIXUP_OFFSET a5
-       add a4, a3, a4
-       add a5, a3, a5
-       REG_L sp, (a4)
-       REG_L tp, (a5)
-
-       .global secondary_start_common
-secondary_start_common:
+       /* a0 contains the hartid & a1 contains boot data */
+       li a2, SBI_HART_BOOT_TASK_PTR_OFFSET
+       XIP_FIXUP_OFFSET a2
+       add a2, a2, a1
+       REG_L tp, (a2)
+       li a3, SBI_HART_BOOT_STACK_PTR_OFFSET
+       XIP_FIXUP_OFFSET a3
+       add a3, a3, a1
+       REG_L sp, (a3)
+
+.Lsecondary_start_common:
 
 #ifdef CONFIG_MMU
        /* Enable virtual memory and relocate to virtual address */
@@ -344,7 +344,7 @@ clear_bss_done:
        beqz tp, .Lwait_for_cpu_up
        fence
 
-       tail secondary_start_common
+       tail .Lsecondary_start_common
 #endif
 
 END(_start_kernel)