From patchwork Fri Mar 11 04:54:35 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Bharata B Rao X-Patchwork-Id: 8562141 Return-Path: X-Original-To: patchwork-qemu-devel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id D4070C0553 for ; Fri, 11 Mar 2016 04:57:27 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id AAD3620122 for ; Fri, 11 Mar 2016 04:57:26 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 4DD91200F0 for ; Fri, 11 Mar 2016 04:57:25 +0000 (UTC) Received: from localhost ([::1]:52719 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aeF8e-0000CA-PW for patchwork-qemu-devel@patchwork.kernel.org; Thu, 10 Mar 2016 23:57:24 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:37823) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aeF6W-0004rK-Cz for qemu-devel@nongnu.org; Thu, 10 Mar 2016 23:55:15 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1aeF6T-0004An-0a for qemu-devel@nongnu.org; Thu, 10 Mar 2016 23:55:12 -0500 Received: from e28smtp05.in.ibm.com ([125.16.236.5]:55209) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aeF6S-00049R-B2 for qemu-devel@nongnu.org; Thu, 10 Mar 2016 23:55:08 -0500 Received: from localhost by e28smtp05.in.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Fri, 11 Mar 2016 10:25:06 +0530 Received: from d28relay02.in.ibm.com (9.184.220.59) by e28smtp05.in.ibm.com (192.168.1.135) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; Fri, 11 Mar 2016 10:25:05 +0530 X-IBM-Helo: d28relay02.in.ibm.com X-IBM-MailFrom: bharata@linux.vnet.ibm.com X-IBM-RcptTo: qemu-ppc@nongnu.org;qemu-devel@nongnu.org Received: from d28av05.in.ibm.com (d28av05.in.ibm.com [9.184.220.67]) by d28relay02.in.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id u2B4smcG24773086; Fri, 11 Mar 2016 10:24:48 +0530 Received: from d28av05.in.ibm.com (localhost [127.0.0.1]) by d28av05.in.ibm.com (8.14.4/8.14.4/NCO v10.0 AVout) with ESMTP id u2B4t2LT022027; Fri, 11 Mar 2016 10:25:04 +0530 Received: from bharata.in.ibm.com ([9.77.192.47]) by d28av05.in.ibm.com (8.14.4/8.14.4/NCO v10.0 AVin) with ESMTP id u2B4se3T021136; Fri, 11 Mar 2016 10:25:00 +0530 From: Bharata B Rao To: qemu-devel@nongnu.org Date: Fri, 11 Mar 2016 10:24:35 +0530 Message-Id: <1457672078-17307-7-git-send-email-bharata@linux.vnet.ibm.com> X-Mailer: git-send-email 2.1.0 In-Reply-To: <1457672078-17307-1-git-send-email-bharata@linux.vnet.ibm.com> References: <1457672078-17307-1-git-send-email-bharata@linux.vnet.ibm.com> X-TM-AS-MML: disable x-cbid: 16031104-0017-0000-0000-00000A94B9D5 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x X-Received-From: 125.16.236.5 Cc: mjrosato@linux.vnet.ibm.com, thuth@redhat.com, pkrempa@redhat.com, ehabkost@redhat.com, aik@ozlabs.ru, Bharata B Rao , armbru@redhat.com, agraf@suse.de, borntraeger@de.ibm.com, qemu-ppc@nongnu.org, pbonzini@redhat.com, imammedo@redhat.com, mdroth@linux.vnet.ibm.com, afaerber@suse.de, david@gibson.dropbear.id.au Subject: [Qemu-devel] [RFC PATCH v2 6/9] spapr: CPU core device X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Add sPAPR specific CPU core device that is based on generic CPU core device. Creating this core device will result in creation of all the CPU thread devices that are part of this core. Introduce sPAPRMachineClass.dr_cpu_enabled to indicate support for CPU core hotplug. Initialize boot time CPUs as core deivces and prevent topologies that result in partially filled cores. Both of these are done only if CPU core hotplug is supported. Note: An unrelated change in the call to xics_system_init() is done in this patch as it makes sense to use the local variable smt introduced in this patch instead of kvmppc_smt_threads() call here. Signed-off-by: Bharata B Rao --- hw/ppc/Makefile.objs | 1 + hw/ppc/spapr.c | 68 +++++++++++--- hw/ppc/spapr_cpu_core.c | 199 ++++++++++++++++++++++++++++++++++++++++ include/hw/ppc/spapr.h | 4 + include/hw/ppc/spapr_cpu_core.h | 28 ++++++ 5 files changed, 287 insertions(+), 13 deletions(-) create mode 100644 hw/ppc/spapr_cpu_core.c create mode 100644 include/hw/ppc/spapr_cpu_core.h diff --git a/hw/ppc/Makefile.objs b/hw/ppc/Makefile.objs index c1ffc77..5cc6608 100644 --- a/hw/ppc/Makefile.objs +++ b/hw/ppc/Makefile.objs @@ -4,6 +4,7 @@ obj-y += ppc.o ppc_booke.o obj-$(CONFIG_PSERIES) += spapr.o spapr_vio.o spapr_events.o obj-$(CONFIG_PSERIES) += spapr_hcall.o spapr_iommu.o spapr_rtas.o obj-$(CONFIG_PSERIES) += spapr_pci.o spapr_rtc.o spapr_drc.o spapr_rng.o +obj-$(CONFIG_PSERIES) += spapr_cpu_core.o ifeq ($(CONFIG_PCI)$(CONFIG_PSERIES)$(CONFIG_LINUX), yyy) obj-y += spapr_pci_vfio.o endif diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 64c4acc..cffe8c8 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -64,6 +64,7 @@ #include "hw/compat.h" #include "qemu-common.h" +#include "hw/ppc/spapr_cpu_core.h" #include @@ -1180,7 +1181,7 @@ static void ppc_spapr_reset(void) } -static void spapr_cpu_reset(void *opaque) +void spapr_cpu_reset(void *opaque) { sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine()); PowerPCCPU *cpu = opaque; @@ -1614,8 +1615,11 @@ static void spapr_boot_set(void *opaque, const char *boot_device, machine->boot_order = g_strdup(boot_device); } -static void spapr_cpu_init(sPAPRMachineState *spapr, PowerPCCPU *cpu, - Error **errp) +/* + * TODO: Check if some of these can be moved to rtas_start_cpu() where + * a few other things required for hotplugged CPUs are being done. + */ +void spapr_cpu_init(sPAPRMachineState *spapr, PowerPCCPU *cpu, Error **errp) { CPUPPCState *env = &cpu->env; @@ -1728,7 +1732,6 @@ static void ppc_spapr_init(MachineState *machine) const char *kernel_filename = machine->kernel_filename; const char *kernel_cmdline = machine->kernel_cmdline; const char *initrd_filename = machine->initrd_filename; - PowerPCCPU *cpu; PCIHostState *phb; int i; MemoryRegion *sysmem = get_system_memory(); @@ -1742,6 +1745,22 @@ static void ppc_spapr_init(MachineState *machine) long load_limit, fw_size; bool kernel_le = false; char *filename; + int smt = kvmppc_smt_threads(); + int spapr_cores = smp_cpus / smp_threads; + int spapr_max_cores = max_cpus / smp_threads; + + if (smc->dr_cpu_enabled) { + if (smp_cpus % smp_threads) { + error_report("smp_cpus (%u) must be multiple of threads (%u)", + smp_cpus, smp_threads); + exit(1); + } + if (max_cpus % smp_threads) { + error_report("max_cpus (%u) must be multiple of threads (%u)", + max_cpus, smp_threads); + exit(1); + } + } msi_supported = true; @@ -1788,8 +1807,7 @@ static void ppc_spapr_init(MachineState *machine) /* Set up Interrupt Controller before we create the VCPUs */ spapr->icp = xics_system_init(machine, - DIV_ROUND_UP(max_cpus * kvmppc_smt_threads(), - smp_threads), + DIV_ROUND_UP(max_cpus * smt, smp_threads), XICS_IRQS, &error_fatal); if (smc->dr_lmb_enabled) { @@ -1800,13 +1818,34 @@ static void ppc_spapr_init(MachineState *machine) if (machine->cpu_model == NULL) { machine->cpu_model = kvm_enabled() ? "host" : "POWER7"; } - for (i = 0; i < smp_cpus; i++) { - cpu = cpu_ppc_init(machine->cpu_model); - if (cpu == NULL) { - error_report("Unable to find PowerPC CPU definition"); - exit(1); + + if (smc->dr_cpu_enabled) { + spapr->cores = g_new0(Object *, spapr_max_cores); + + for (i = 0; i < spapr_max_cores; i++) { + int core_dt_id = i * smt; + + if (i < spapr_cores) { + Object *core = object_new(TYPE_SPAPR_CPU_CORE); + + object_property_set_str(core, machine->cpu_model, "cpu_model", + &error_fatal); + object_property_set_int(core, smp_threads, "threads", + &error_fatal); + object_property_set_int(core, core_dt_id, CPU_CORE_PROP_CORE, + &error_fatal); + object_property_set_bool(core, true, "realized", &error_fatal); + } } - spapr_cpu_init(spapr, cpu, &error_fatal); + } else { + for (i = 0; i < smp_cpus; i++) { + PowerPCCPU *cpu = cpu_ppc_init(machine->cpu_model); + if (cpu == NULL) { + error_report("Unable to find PowerPC CPU definition"); + exit(1); + } + spapr_cpu_init(spapr, cpu, &error_fatal); + } } if (kvm_enabled()) { @@ -2261,7 +2300,8 @@ static void spapr_machine_device_unplug(HotplugHandler *hotplug_dev, static HotplugHandler *spapr_get_hotpug_handler(MachineState *machine, DeviceState *dev) { - if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { + if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM) || + object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_CPU_CORE)) { return HOTPLUG_HANDLER(machine); } return NULL; @@ -2305,6 +2345,7 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data) mc->cpu_index_to_socket_id = spapr_cpu_index_to_socket_id; smc->dr_lmb_enabled = true; + smc->dr_cpu_enabled = true; fwc->get_dev_path = spapr_get_fw_dev_path; nc->nmi_monitor_handler = spapr_nmi; } @@ -2384,6 +2425,7 @@ static void spapr_machine_2_5_class_options(MachineClass *mc) spapr_machine_2_6_class_options(mc); smc->use_ohci_by_default = true; + smc->dr_cpu_enabled = false; SET_MACHINE_COMPAT(mc, SPAPR_COMPAT_2_5); } diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c new file mode 100644 index 0000000..8c6d71d --- /dev/null +++ b/hw/ppc/spapr_cpu_core.c @@ -0,0 +1,199 @@ +/* + * sPAPR CPU core device, acts as container of CPU thread devices. + * + * Copyright (C) 2016 Bharata B Rao + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ +#include "hw/cpu/core.h" +#include "hw/ppc/spapr_cpu_core.h" +#include "hw/ppc/spapr.h" +#include "hw/boards.h" +#include "qemu/error-report.h" +#include "qapi/visitor.h" +#include +#include "target-ppc/kvm_ppc.h" + +static void spapr_cpu_core_create_threads(sPAPRCPUCore *core, int threads, + Error **errp) +{ + int i; + Error *local_err = NULL; + + for (i = 0; i < threads; i++) { + char id[32]; + + object_initialize(&core->threads[i], sizeof(core->threads[i]), + object_class_get_name(core->oc)); + snprintf(id, sizeof(id), "thread[%d]", i); + object_property_add_child(OBJECT(core), id, OBJECT(&core->threads[i]), + &local_err); + if (local_err) { + goto err; + } + } + return; + +err: + while (--i) { + object_unparent(OBJECT(&core->threads[i])); + } + error_propagate(errp, local_err); +} + +static int spapr_cpu_core_realize_child(Object *child, void *opaque) +{ + Error **errp = opaque; + sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine()); + CPUState *cs = CPU(child); + PowerPCCPU *cpu = POWERPC_CPU(cs); + + object_property_set_bool(child, true, "realized", errp); + if (*errp) { + return 1; + } + + spapr_cpu_init(spapr, cpu, errp); + if (*errp) { + return 1; + } + + spapr_cpu_reset(cpu); + return 0; +} + +static void spapr_cpu_core_realize(DeviceState *dev, Error **errp) +{ + sPAPRCPUCore *core = SPAPR_CPU_CORE(OBJECT(dev)); + sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine()); + int spapr_max_cores = max_cpus / smp_threads; + Error *local_err = NULL; + int threads = 0; + int core_dt_id, core_id; + int smt = kvmppc_smt_threads(); + + threads = object_property_get_int(OBJECT(dev), "threads", &local_err); + if (local_err) { + goto out; + } + + if (threads != smp_threads) { + error_setg(&local_err, "threads must be %d", smp_threads); + goto out; + } + + if (!core->oc) { + error_setg(&local_err, "cpu_model property isn't set"); + goto out; + } + + core_dt_id = object_property_get_int(OBJECT(dev), "core", &local_err); + if (local_err) { + goto out; + } + + if (core_dt_id % smt) { + error_setg(&local_err, "invalid core id %d\n", core_dt_id); + goto out; + } + + core_id = core_dt_id / smt; + if (core_id < 0 || core_id >= spapr_max_cores) { + error_setg(&local_err, "core id %d out of range", core_dt_id); + goto out; + } + + /* + * TODO: This check will be moved to ->pre_plug() as suggested by Igor + * when there is consensus pre_plug hook. + */ + if (spapr->cores[core_id]) { + error_setg(&local_err, "core %d already populated", core_dt_id); + goto out; + } + + core->threads = g_new0(PowerPCCPU, threads); + spapr_cpu_core_create_threads(core, threads, &local_err); + if (local_err) { + goto out; + } + + object_child_foreach(OBJECT(dev), spapr_cpu_core_realize_child, &local_err); + if (local_err) { + goto out; + } + + return; + +out: + if (local_err) { + g_free(core->threads); + error_propagate(errp, local_err); + } +} + +static char *spapr_cpu_core_prop_get_cpu_model(Object *obj, Error **errp) +{ + sPAPRCPUCore *core = SPAPR_CPU_CORE(obj); + + /* + * TODO: This returns the full type instead of just cpu_model. For eg, + * host-powerpc64-cpu is returned where just "host" is expected. + */ + return g_strdup(object_class_get_name(core->oc)); +} + +static void spapr_cpu_core_prop_set_cpu_model(Object *obj, const char *val, + Error **errp) +{ + sPAPRCPUCore *core = SPAPR_CPU_CORE(obj); + MachineState *machine = MACHINE(qdev_get_machine()); + ObjectClass *oc = cpu_class_by_name(TYPE_POWERPC_CPU, val); + ObjectClass *oc_base = cpu_class_by_name(TYPE_POWERPC_CPU, + machine->cpu_model); + if (!oc) { + error_setg(errp, "Unknown CPU model %s", val); + return; + } + + /* + * Currently cpu_model can't be different from what is specified with -cpu + */ + if (strcmp(object_class_get_name(oc), object_class_get_name(oc_base))) { + error_setg(errp, "cpu_model must be %s", machine->cpu_model); + return; + } + + core->oc = oc; +} + +static void spapr_cpu_core_instance_init(Object *obj) +{ + object_property_add_str(obj, "cpu_model", + spapr_cpu_core_prop_get_cpu_model, + spapr_cpu_core_prop_set_cpu_model, + NULL); +} + +static void spapr_cpu_core_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + + dc->realize = spapr_cpu_core_realize; +} + +static const TypeInfo spapr_cpu_core_type_info = { + .name = TYPE_SPAPR_CPU_CORE, + .parent = TYPE_CPU_CORE, + .instance_init = spapr_cpu_core_instance_init, + .instance_size = sizeof(sPAPRCPUCore), + .class_init = spapr_cpu_core_class_init, +}; + +static void spapr_cpu_core_register_types(void) +{ + type_register_static(&spapr_cpu_core_type_info); +} + +type_init(spapr_cpu_core_register_types) diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h index 098d85d..c099c3c 100644 --- a/include/hw/ppc/spapr.h +++ b/include/hw/ppc/spapr.h @@ -36,6 +36,7 @@ struct sPAPRMachineClass { /*< public >*/ bool dr_lmb_enabled; /* enable dynamic-reconfig/hotplug of LMBs */ + bool dr_cpu_enabled; /* enable dynamic-reconfig/hotplug of CPUs */ bool use_ohci_by_default; /* use USB-OHCI instead of XHCI */ }; @@ -79,6 +80,7 @@ struct sPAPRMachineState { /*< public >*/ char *kvm_type; MemoryHotplugState hotplug_memory; + Object **cores; }; #define H_SUCCESS 0 @@ -585,6 +587,8 @@ void spapr_hotplug_req_add_by_count(sPAPRDRConnectorType drc_type, uint32_t count); void spapr_hotplug_req_remove_by_count(sPAPRDRConnectorType drc_type, uint32_t count); +void spapr_cpu_init(sPAPRMachineState *spapr, PowerPCCPU *cpu, Error **errp); +void spapr_cpu_reset(void *opaque); /* rtas-configure-connector state */ struct sPAPRConfigureConnectorState { diff --git a/include/hw/ppc/spapr_cpu_core.h b/include/hw/ppc/spapr_cpu_core.h new file mode 100644 index 0000000..48fb76a --- /dev/null +++ b/include/hw/ppc/spapr_cpu_core.h @@ -0,0 +1,28 @@ +/* + * sPAPR CPU core device. + * + * Copyright (C) 2016 Bharata B Rao + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ +#ifndef HW_SPAPR_CPU_CORE_H +#define HW_SPAPR_CPU_CORE_H + +#include "hw/qdev.h" +#include "hw/cpu/core.h" + +#define TYPE_SPAPR_CPU_CORE "spapr-cpu-core" +#define SPAPR_CPU_CORE(obj) \ + OBJECT_CHECK(sPAPRCPUCore, (obj), TYPE_SPAPR_CPU_CORE) + +typedef struct sPAPRCPUCore { + /*< private >*/ + CPUCore parent_obj; + + /*< public >*/ + ObjectClass *oc; + PowerPCCPU *threads; +} sPAPRCPUCore; + +#endif