Received: by 2002:a25:c205:0:0:0:0:0 with SMTP id s5csp331111ybf; Wed, 26 Feb 2020 14:03:59 -0800 (PST) X-Google-Smtp-Source: APXvYqweK5EDGIBIdLGqMj4SOCF2uSdSYick0spkdAeAfxeWxztqSKG0aBqdoA4HMUtpiFpebuIu X-Received: by 2002:a9d:6c9:: with SMTP id 67mr343339otx.363.1582754639318; Wed, 26 Feb 2020 14:03:59 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1582754639; cv=none; d=google.com; s=arc-20160816; b=za0eTKPbEIRWb6uMN9GEpS/EeO8dlE/7eU217VAIF2sMt/VkyZOjncceGlAYrWz0+h zipWjGd3DfbmiDaQZ4V1ebzCUFCfoXXYzFIFxiV6kqHagD61667DJydApW+Xg8ygf80a TlwjHZAQ6G9VNGPiCP5No7Fmv7dQsj2TZaEWDKd2Kl8f+kmQVd/8DlCwUSZUoL3MAdyg /zjhVyjZNmCeFI3Ic2+TzAvbYjJLf0h6wvISVI0MMShzwuFV39YtkmI7oVm1sLjJgHBq 7pXF3wO3V3cWEFhcDUK4v2G5WDIX0HwOKsomqQ3hE2dwOfKCUtOJnuGFzMLT0ZZ9WlyD wc4A== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :wdcironportexception:ironport-sdr:ironport-sdr:ironport-sdr :dkim-signature; bh=EArDtTEFSjiCr8ZKA0QfGfepIjQLoAQmH+xRDep+TPg=; b=pkJRKiY1liiik9u5R8ITjcO4Dkt4tHoN/gwlcTf5Wajf/rmFmaEoK4w54UwtxpoYvO rJJRULZaNed/IxN5IFt1zkcs5RvwxiSHmAQ1xFCe0XCF10vBOB7HuYxA1DBS2QyhHcDU ltPcXzM5yBgd2/HPnXArnuuDISM3odGxr65NpCqKRdi6PLmULH75Y5/EXNyWps3/s/wQ SSIR3d9psh8bpHxDwbQF9311T7yx3XEAh9xDf/YH+hwZpKa97YK3ibbrAN9t/Dle1e+b Pt395gb/ND8m+qQIHL7TLakUcWbyokRFCctqKaVEesAGR+LB/SNFn1GjJT7y9cJpBgXw 50yQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=fail header.i=@wdc.com header.s=dkim.wdc.com header.b=QSI63F2m; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=wdc.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id z14si414977oth.15.2020.02.26.14.03.46; Wed, 26 Feb 2020 14:03:59 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=fail header.i=@wdc.com header.s=dkim.wdc.com header.b=QSI63F2m; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=wdc.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727889AbgBZWC0 (ORCPT + 99 others); Wed, 26 Feb 2020 17:02:26 -0500 Received: from esa6.hgst.iphmx.com ([216.71.154.45]:45037 "EHLO esa6.hgst.iphmx.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727849AbgBZWCY (ORCPT ); Wed, 26 Feb 2020 17:02:24 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=wdc.com; i=@wdc.com; q=dns/txt; s=dkim.wdc.com; t=1582754544; x=1614290544; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=ppdd/KmLP3L/YfNatyXwLu2cXwjc99cL+VCNoHNDlAU=; b=QSI63F2mBPIEzqZhi98PiUqp7Byp2p5yz30gB2NKeCvU3Gdmu8PlcLSd SZJBMOjWjJS07ZY5+5xwo+MJKKqpcTNtBzRjw4W5dvNq3MIWvlyzPTw30 M+/foA/t6pxJpEUT9LU3jnaqbEjjGs0Y68GVQgNoDs2vkudaYyr7GVKeV t3RinuEqfQ0abYpCSToKq3aGdqCEey29ODc2ljHSmh9502r+XPxixgjWJ zFLtwSn6dAsbw4HEuNVNCBszIaD3lgJ6cbU/7FoStpsFQKhIw/iJ0KIBT 6c2x7vDkVW7piuxBYxP2yDY3CJg2uScdl5S0RoabWXqdK3X1/JrVlifiZ w==; IronPort-SDR: vRsneTESHlZl7cxDjWNRPrIhBqIbudIDkACQU9ISroI6lwh6Zv88jISor4taVedUf2gPC5E4Cp qlqFDW88IZuiin285vjH/DPzfjFDKr+Pemw58vH3D19z1aIX98tKSxfrp1hV86qw3R5XoiFqU+ P9T9cOuMtwFWtUXw47AlT3hdazzYSBnxmk7HG/Ds1qIeI2DfMxWfjQ01NDqO9mpKPdsaOnZz7T DgO8A0BaHIWGUC8eNZK5MdWmULudvp8sHv21YV4ZxZuNyKXhxK9BDfxgS48RGssBOVh6C+p9Vk FCA= X-IronPort-AV: E=Sophos;i="5.70,489,1574092800"; d="scan'208";a="132290735" Received: from uls-op-cesaip01.wdc.com (HELO uls-op-cesaep01.wdc.com) ([199.255.45.14]) by ob1.hgst.iphmx.com with ESMTP; 27 Feb 2020 06:02:24 +0800 IronPort-SDR: DSNnLcr0ANAhP7HTusmmuL4KbjJaskOEYnwRWH+IFrpnekw41qKnjDkkJR/rsJzomkon2yZR3q FIQwn4llTfg0q0GVq7rDuXUQMw9KFoA/ZNTViZ8dVSFUj9TFDjh7gGYDFWpZ670F0JE5JF6J6y wmij00DPu5MGb2oqVwB8lWlMV13TmLvWGLl50t22Dsjd20i9K2pSmsT0RixvDNxameV/B58E1C mPp8H16Jx5Y2FFvY9hXTSrK+n+ayBBs6aN8YDmeOe4kGq00hDp0VJyL9oRy5J1MGFoATPJXown J0MZ8/QBw4VW+qJsMWY4bTh2 Received: from uls-op-cesaip02.wdc.com ([10.248.3.37]) by uls-op-cesaep01.wdc.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 26 Feb 2020 13:54:48 -0800 IronPort-SDR: +ESXG76l/zzWesS2B+VNsorTSBhBeD3jA5+RBRZYMn/GIacwH12JttYoY3HlWnAwFQt6+3O+Mi a6jsJD1vwLtwRqw9qEpOQue9OzHsYPmh12u12gl0LMmfV/3CssI0gOCQ6uk5W4BErJR5Kuabrr SUcV0q6tF+1ELVJbrkyNTHynr8W61MnKqcdWh6JYz6HGkUGwZIJppJsw0+y+0gQWrJ4uPpSn+i By9Z+eAuB/ypokXwhewrwhsko6GnbFBP7E6lkPL4YtvaYe/V1xPDKGptIVQyZgIudgLTN/pqrH 2AI= WDCIronportException: Internal Received: from yoda.sdcorp.global.sandisk.com (HELO yoda.int.fusionio.com) ([10.196.158.80]) by uls-op-cesaip02.wdc.com with ESMTP; 26 Feb 2020 14:02:23 -0800 From: Atish Patra To: linux-kernel@vger.kernel.org Cc: Atish Patra , Anup Patel , Albert Ou , Alexios Zavras , Borislav Petkov , Daniel Jordan , "Eric W. Biederman" , Gary Guo , Geert Uytterhoeven , Greentime Hu , Greg Kroah-Hartman , Heiko Carstens , Jason Cooper , Kate Stewart , Kees Cook , linux-riscv@lists.infradead.org, Madhavan Srinivasan , Mao Han , Marc Zyngier , Michael Kelley , Mike Rapoport , Nick Hu , Palmer Dabbelt , Paul Walmsley , "Rafael J. Wysocki" , Steven Price , Sudeep Holla , Thomas Gleixner , Vincent Chen , Zong Li Subject: [PATCH v10 07/12] RISC-V: Add cpu_ops and modify default booting method Date: Wed, 26 Feb 2020 14:02:08 -0800 Message-Id: <20200226220213.27423-8-atish.patra@wdc.com> X-Mailer: git-send-email 2.25.0 In-Reply-To: <20200226220213.27423-1-atish.patra@wdc.com> References: <20200226220213.27423-1-atish.patra@wdc.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Currently, all non-booting harts start booting after the booting hart updates the per-hart stack pointer. This is done in a way that, it's difficult to implement any other booting method without breaking the backward compatibility. Define a cpu_ops method that allows to introduce other booting methods in future. Modify the current booting method to be compatible with cpu_ops. Signed-off-by: Atish Patra Reviewed-by: Anup Patel --- arch/riscv/include/asm/cpu_ops.h | 34 +++++++++++++++++++ arch/riscv/kernel/Makefile | 2 ++ arch/riscv/kernel/cpu_ops.c | 38 +++++++++++++++++++++ arch/riscv/kernel/cpu_ops_spinwait.c | 42 +++++++++++++++++++++++ arch/riscv/kernel/smpboot.c | 51 ++++++++++++++++------------ 5 files changed, 146 insertions(+), 21 deletions(-) create mode 100644 arch/riscv/include/asm/cpu_ops.h create mode 100644 arch/riscv/kernel/cpu_ops.c create mode 100644 arch/riscv/kernel/cpu_ops_spinwait.c diff --git a/arch/riscv/include/asm/cpu_ops.h b/arch/riscv/include/asm/cpu_ops.h new file mode 100644 index 000000000000..5ce81a28e1d9 --- /dev/null +++ b/arch/riscv/include/asm/cpu_ops.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2020 Western Digital Corporation or its affiliates. + * Based on arch/arm64/include/asm/cpu_ops.h + */ +#ifndef __ASM_CPU_OPS_H +#define __ASM_CPU_OPS_H + +#include +#include +#include + +/** + * struct cpu_operations - Callback operations for hotplugging CPUs. + * + * @name: Name of the boot protocol. + * @cpu_prepare: Early one-time preparation step for a cpu. If there + * is a mechanism for doing so, tests whether it is + * possible to boot the given HART. + * @cpu_start: Boots a cpu into the kernel. + */ +struct cpu_operations { + const char *name; + int (*cpu_prepare)(unsigned int cpu); + int (*cpu_start)(unsigned int cpu, + struct task_struct *tidle); +}; + +extern const struct cpu_operations *cpu_ops[NR_CPUS]; +void __init cpu_set_ops(int cpu); +void cpu_update_secondary_bootdata(unsigned int cpuid, + struct task_struct *tidle); + +#endif /* ifndef __ASM_CPU_OPS_H */ diff --git a/arch/riscv/kernel/Makefile b/arch/riscv/kernel/Makefile index f40205cb9a22..f81a6ff88005 100644 --- a/arch/riscv/kernel/Makefile +++ b/arch/riscv/kernel/Makefile @@ -32,6 +32,8 @@ obj-$(CONFIG_RISCV_M_MODE) += clint.o obj-$(CONFIG_FPU) += fpu.o obj-$(CONFIG_SMP) += smpboot.o obj-$(CONFIG_SMP) += smp.o +obj-$(CONFIG_SMP) += cpu_ops.o +obj-$(CONFIG_SMP) += cpu_ops_spinwait.o obj-$(CONFIG_MODULES) += module.o obj-$(CONFIG_MODULE_SECTIONS) += module-sections.o diff --git a/arch/riscv/kernel/cpu_ops.c b/arch/riscv/kernel/cpu_ops.c new file mode 100644 index 000000000000..e950ae5bee9c --- /dev/null +++ b/arch/riscv/kernel/cpu_ops.c @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020 Western Digital Corporation or its affiliates. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 const struct cpu_operations cpu_ops_spinwait; + +void cpu_update_secondary_bootdata(unsigned int cpuid, + struct task_struct *tidle) +{ + int hartid = cpuid_to_hartid_map(cpuid); + + /* 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); +} + +void __init cpu_set_ops(int cpuid) +{ + cpu_ops[cpuid] = &cpu_ops_spinwait; +} diff --git a/arch/riscv/kernel/cpu_ops_spinwait.c b/arch/riscv/kernel/cpu_ops_spinwait.c new file mode 100644 index 000000000000..f828e660294e --- /dev/null +++ b/arch/riscv/kernel/cpu_ops_spinwait.c @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020 Western Digital Corporation or its affiliates. + */ + +#include +#include +#include +#include +#include +#include + +const struct cpu_operations cpu_ops_spinwait; + +static int spinwait_cpu_prepare(unsigned int cpuid) +{ + if (!cpu_ops_spinwait.cpu_start) { + pr_err("cpu start method not defined for CPU [%d]\n", cpuid); + return -ENODEV; + } + return 0; +} + +static int spinwait_cpu_start(unsigned int cpuid, struct task_struct *tidle) +{ + /* + * In this protocol, all cpus boot on their own accord. _start + * selects the first cpu to boot the kernel and causes the remainder + * of the cpus to spin in a loop waiting for their stack pointer to be + * setup by that main cpu. Writing to bootdata (i.e __cpu_up_stack_pointer) signals to + * the spinning cpus that they can continue the boot process. + */ + cpu_update_secondary_bootdata(cpuid, tidle); + + return 0; +} + +const struct cpu_operations cpu_ops_spinwait = { + .name = "spinwait", + .cpu_prepare = spinwait_cpu_prepare, + .cpu_start = spinwait_cpu_start, +}; diff --git a/arch/riscv/kernel/smpboot.c b/arch/riscv/kernel/smpboot.c index 8bc01f0ca73b..e89396a2a1af 100644 --- a/arch/riscv/kernel/smpboot.c +++ b/arch/riscv/kernel/smpboot.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -34,8 +35,6 @@ #include "head.h" -void *__cpu_up_stack_pointer[NR_CPUS]; -void *__cpu_up_task_pointer[NR_CPUS]; static DECLARE_COMPLETION(cpu_running); void __init smp_prepare_boot_cpu(void) @@ -46,6 +45,7 @@ void __init smp_prepare_boot_cpu(void) void __init smp_prepare_cpus(unsigned int max_cpus) { int cpuid; + int ret; /* This covers non-smp usecase mandated by "nosmp" option */ if (max_cpus == 0) @@ -54,6 +54,11 @@ void __init smp_prepare_cpus(unsigned int max_cpus) for_each_possible_cpu(cpuid) { if (cpuid == smp_processor_id()) continue; + if (cpu_ops[cpuid]->cpu_prepare) { + ret = cpu_ops[cpuid]->cpu_prepare(cpuid); + if (ret) + continue; + } set_cpu_present(cpuid, true); } } @@ -65,6 +70,8 @@ void __init setup_smp(void) bool found_boot_cpu = false; int cpuid = 1; + cpu_set_ops(0); + for_each_of_cpu_node(dn) { hart = riscv_of_processor_hartid(dn); if (hart < 0) @@ -92,36 +99,38 @@ void __init setup_smp(void) cpuid, nr_cpu_ids); for (cpuid = 1; cpuid < nr_cpu_ids; cpuid++) { - if (cpuid_to_hartid_map(cpuid) != INVALID_HARTID) + if (cpuid_to_hartid_map(cpuid) != INVALID_HARTID) { + cpu_set_ops(cpuid); set_cpu_possible(cpuid, true); + } } } +int start_secondary_cpu(int cpu, struct task_struct *tidle) +{ + if (cpu_ops[cpu]->cpu_start) + return cpu_ops[cpu]->cpu_start(cpu, tidle); + + return -EOPNOTSUPP; +} + int __cpu_up(unsigned int cpu, struct task_struct *tidle) { int ret = 0; - int hartid = cpuid_to_hartid_map(cpu); tidle->thread_info.cpu = cpu; - /* - * On RISC-V systems, all harts boot on their own accord. Our _start - * selects the first hart to boot the kernel and causes the remainder - * of the harts to spin in a loop waiting for their stack pointer to be - * setup by that main hart. Writing __cpu_up_stack_pointer signals to - * the spinning harts that they can continue the boot process. - */ - smp_mb(); - WRITE_ONCE(__cpu_up_stack_pointer[hartid], - task_stack_page(tidle) + THREAD_SIZE); - WRITE_ONCE(__cpu_up_task_pointer[hartid], tidle); - - lockdep_assert_held(&cpu_running); - wait_for_completion_timeout(&cpu_running, + ret = start_secondary_cpu(cpu, tidle); + if (!ret) { + lockdep_assert_held(&cpu_running); + wait_for_completion_timeout(&cpu_running, msecs_to_jiffies(1000)); - if (!cpu_online(cpu)) { - pr_crit("CPU%u: failed to come online\n", cpu); - ret = -EIO; + if (!cpu_online(cpu)) { + pr_crit("CPU%u: failed to come online\n", cpu); + ret = -EIO; + } + } else { + pr_crit("CPU%u: failed to start\n", cpu); } return ret; -- 2.25.0