From a1aa1309892581972b5019ef65fd0a12cd69cc28 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Tue, 14 Jun 2016 19:23:03 +0200 Subject: hw/ppc/spapr: Silence deprecation message in qtest mode When running "make check", there is currently always an error message saying "spapr-pci-vfio-host-bridge is deprecated". This happens because the QOM tests are instantiating all possible devices, and the error message is currently located in the instance_init() function of the device. Since it is legal for the tests to instantiate a device without using it, the error message should be silenced when we're running in test mode. Signed-off-by: Thomas Huth Signed-off-by: David Gibson --- hw/ppc/spapr_pci_vfio.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'hw') diff --git a/hw/ppc/spapr_pci_vfio.c b/hw/ppc/spapr_pci_vfio.c index cbd3d23..f3cb141 100644 --- a/hw/ppc/spapr_pci_vfio.c +++ b/hw/ppc/spapr_pci_vfio.c @@ -27,6 +27,7 @@ #include "linux/vfio.h" #include "hw/vfio/vfio.h" #include "qemu/error-report.h" +#include "sysemu/qtest.h" #define TYPE_SPAPR_PCI_VFIO_HOST_BRIDGE "spapr-pci-vfio-host-bridge" @@ -48,7 +49,9 @@ static Property spapr_phb_vfio_properties[] = { static void spapr_phb_vfio_instance_init(Object *obj) { - error_report("spapr-pci-vfio-host-bridge is deprecated"); + if (!qtest_enabled()) { + error_report("spapr-pci-vfio-host-bridge is deprecated"); + } } bool spapr_phb_eeh_available(sPAPRPHBState *sphb) -- cgit v1.1 From d917e88d85a147a99f38a62a4f95cac21e366d51 Mon Sep 17 00:00:00 2001 From: Gavin Shan Date: Wed, 15 Jun 2016 14:28:27 +1000 Subject: vfio: Fix broken EEH vfio_eeh_container_op() is the backend that communicates with host kernel to support EEH functionality in QEMU. However, the functon should return the value from host kernel instead of 0 unconditionally. dwg: Specifically the problem occurs for the handful of EEH sub-operations which can return a non-zero, non-error result. Signed-off-by: Gavin Shan Acked-by: Alex Williamson [dwg: clarification to commit message] Signed-off-by: David Gibson --- hw/vfio/common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'hw') diff --git a/hw/vfio/common.c b/hw/vfio/common.c index 5ff5e92..1898f1f 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -1257,7 +1257,7 @@ static int vfio_eeh_container_op(VFIOContainer *container, uint32_t op) return -errno; } - return 0; + return ret; } static VFIOContainer *vfio_eeh_as_container(AddressSpace *as) -- cgit v1.1 From 41346263c4039fd2edca61c031c9396577693036 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Thu, 12 May 2016 09:18:15 +0530 Subject: qdev: hotplug: Introduce HotplugHandler.pre_plug() callback pre_plug callback is to be called before device.realize() is executed. This would allow to check/set device's properties from HotplugHandler. Signed-off-by: Igor Mammedov Signed-off-by: Bharata B Rao Reviewed-by: David Gibson Signed-off-by: David Gibson --- hw/core/hotplug.c | 11 +++++++++++ hw/core/qdev.c | 9 ++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) (limited to 'hw') diff --git a/hw/core/hotplug.c b/hw/core/hotplug.c index 645cfca..17ac986 100644 --- a/hw/core/hotplug.c +++ b/hw/core/hotplug.c @@ -13,6 +13,17 @@ #include "hw/hotplug.h" #include "qemu/module.h" +void hotplug_handler_pre_plug(HotplugHandler *plug_handler, + DeviceState *plugged_dev, + Error **errp) +{ + HotplugHandlerClass *hdc = HOTPLUG_HANDLER_GET_CLASS(plug_handler); + + if (hdc->pre_plug) { + hdc->pre_plug(plug_handler, plugged_dev, errp); + } +} + void hotplug_handler_plug(HotplugHandler *plug_handler, DeviceState *plugged_dev, Error **errp) diff --git a/hw/core/qdev.c b/hw/core/qdev.c index dcc00f8..6680089 100644 --- a/hw/core/qdev.c +++ b/hw/core/qdev.c @@ -902,6 +902,14 @@ static void device_set_realized(Object *obj, bool value, Error **errp) g_free(name); } + hotplug_ctrl = qdev_get_hotplug_handler(dev); + if (hotplug_ctrl) { + hotplug_handler_pre_plug(hotplug_ctrl, dev, &local_err); + if (local_err != NULL) { + goto fail; + } + } + if (dc->realize) { dc->realize(dev, &local_err); } @@ -912,7 +920,6 @@ static void device_set_realized(Object *obj, bool value, Error **errp) DEVICE_LISTENER_CALL(realize, Forward, dev); - hotplug_ctrl = qdev_get_hotplug_handler(dev); if (hotplug_ctrl) { hotplug_handler_plug(hotplug_ctrl, dev, &local_err); } -- cgit v1.1 From f1020c2c2647a62df870ce243424ee23ea95ae6f Mon Sep 17 00:00:00 2001 From: Bharata B Rao Date: Thu, 12 May 2016 09:18:16 +0530 Subject: cpu: Abstract CPU core type Add an abstract CPU core type that could be used by machines that want to define and hotplug CPUs in core granularity. Signed-off-by: Bharata B Rao Signed-off-by: Igor Mammedov [Integer core property] Reviewed-by: David Gibson Reviewed-by: Igor Mammedov [dwg: changed property names to 'core-id' and 'nr-threads'] Signed-off-by: David Gibson --- hw/cpu/Makefile.objs | 1 + hw/cpu/core.c | 88 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+) create mode 100644 hw/cpu/core.c (limited to 'hw') diff --git a/hw/cpu/Makefile.objs b/hw/cpu/Makefile.objs index 0954a18..942a4bb 100644 --- a/hw/cpu/Makefile.objs +++ b/hw/cpu/Makefile.objs @@ -2,4 +2,5 @@ obj-$(CONFIG_ARM11MPCORE) += arm11mpcore.o obj-$(CONFIG_REALVIEW) += realview_mpcore.o obj-$(CONFIG_A9MPCORE) += a9mpcore.o obj-$(CONFIG_A15MPCORE) += a15mpcore.o +obj-y += core.o diff --git a/hw/cpu/core.c b/hw/cpu/core.c new file mode 100644 index 0000000..eff90c1 --- /dev/null +++ b/hw/cpu/core.c @@ -0,0 +1,88 @@ +/* + * CPU core abstract 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. + */ +#include "hw/cpu/core.h" +#include "qapi/visitor.h" +#include "qapi/error.h" +#include "sysemu/cpus.h" + +static void core_prop_get_core_id(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + CPUCore *core = CPU_CORE(obj); + int64_t value = core->core_id; + + visit_type_int(v, name, &value, errp); +} + +static void core_prop_set_core_id(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + CPUCore *core = CPU_CORE(obj); + Error *local_err = NULL; + int64_t value; + + visit_type_int(v, name, &value, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + + core->core_id = value; +} + +static void core_prop_get_nr_threads(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + CPUCore *core = CPU_CORE(obj); + int64_t value = core->nr_threads; + + visit_type_int(v, name, &value, errp); +} + +static void core_prop_set_nr_threads(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + CPUCore *core = CPU_CORE(obj); + Error *local_err = NULL; + int64_t value; + + visit_type_int(v, name, &value, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + + core->nr_threads = value; +} + +static void cpu_core_instance_init(Object *obj) +{ + CPUCore *core = CPU_CORE(obj); + + object_property_add(obj, "core-id", "int", core_prop_get_core_id, + core_prop_set_core_id, NULL, NULL, NULL); + object_property_add(obj, "nr-threads", "int", core_prop_get_nr_threads, + core_prop_set_nr_threads, NULL, NULL, NULL); + core->nr_threads = smp_threads; +} + +static const TypeInfo cpu_core_type_info = { + .name = TYPE_CPU_CORE, + .parent = TYPE_DEVICE, + .abstract = true, + .instance_size = sizeof(CPUCore), + .instance_init = cpu_core_instance_init, +}; + +static void cpu_core_register_types(void) +{ + type_register_static(&cpu_core_type_info); +} + +type_init(cpu_core_register_types) -- cgit v1.1 From 4a4b344c7ccdeac28c2e65e51ddbe3acfb41b883 Mon Sep 17 00:00:00 2001 From: Bharata B Rao Date: Thu, 12 May 2016 09:18:20 +0530 Subject: xics,xics_kvm: Handle CPU unplug correctly XICS is setup for each CPU during initialization. Provide a routine to undo the same when CPU is unplugged. While here, move ss->cs management into xics from xics_kvm since there is nothing KVM specific in it. Also ensure xics reset doesn't set irq for CPUs that are already unplugged. This allows reboot of a VM that has undergone CPU hotplug and unplug to work correctly. Signed-off-by: Bharata B Rao Reviewed-by: David Gibson Signed-off-by: David Gibson --- hw/intc/xics.c | 14 ++++++++++++++ hw/intc/xics_kvm.c | 8 ++++---- 2 files changed, 18 insertions(+), 4 deletions(-) (limited to 'hw') diff --git a/hw/intc/xics.c b/hw/intc/xics.c index 8659be0..cce7f3d 100644 --- a/hw/intc/xics.c +++ b/hw/intc/xics.c @@ -48,6 +48,18 @@ static int get_cpu_index_by_dt_id(int cpu_dt_id) return -1; } +void xics_cpu_destroy(XICSState *icp, PowerPCCPU *cpu) +{ + CPUState *cs = CPU(cpu); + ICPState *ss = &icp->ss[cs->cpu_index]; + + assert(cs->cpu_index < icp->nr_servers); + assert(cs == ss->cs); + + ss->output = NULL; + ss->cs = NULL; +} + void xics_cpu_setup(XICSState *icp, PowerPCCPU *cpu) { CPUState *cs = CPU(cpu); @@ -57,6 +69,8 @@ void xics_cpu_setup(XICSState *icp, PowerPCCPU *cpu) assert(cs->cpu_index < icp->nr_servers); + ss->cs = cs; + if (info->cpu_setup) { info->cpu_setup(icp, cpu); } diff --git a/hw/intc/xics_kvm.c b/hw/intc/xics_kvm.c index 55fd801..b17d6a9 100644 --- a/hw/intc/xics_kvm.c +++ b/hw/intc/xics_kvm.c @@ -114,8 +114,10 @@ static void icp_kvm_reset(DeviceState *dev) icp->pending_priority = 0xff; icp->mfrr = 0xff; - /* Make all outputs are deasserted */ - qemu_set_irq(icp->output, 0); + /* Make all outputs as deasserted only if the CPU thread is in use */ + if (icp->output) { + qemu_set_irq(icp->output, 0); + } icp_set_kvm_state(icp, 1); } @@ -348,8 +350,6 @@ static void xics_kvm_cpu_setup(XICSState *icp, PowerPCCPU *cpu) if (icpkvm->kernel_xics_fd != -1) { int ret; - ss->cs = cs; - ret = kvm_vcpu_enable_cap(cs, KVM_CAP_IRQ_XICS, 0, icpkvm->kernel_xics_fd, kvm_arch_vcpu_id(cs)); if (ret < 0) { -- cgit v1.1 From aab99135b63522267c6fdae04712cb2f02c8c7de Mon Sep 17 00:00:00 2001 From: Bharata B Rao Date: Thu, 12 May 2016 09:18:21 +0530 Subject: spapr_drc: Prevent detach racing against attach for CPU DR If a CPU is hot removed while hotplug of the same is still in progress, the guest crashes. Prevent this by ensuring that detach is done only after attach has completed. The existing code already prevents such race for PCI hotplug. However given that CPU is a logical DR unlike PCI and starts with ISOLATED state, we need a logic that works for CPU too. Signed-off-by: Bharata B Rao Reviewed-by: Michael Roth Signed-off-by: Michael Roth [Don't set awaiting_attach for PCI devices] Signed-off-by: David Gibson --- hw/ppc/spapr_drc.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'hw') diff --git a/hw/ppc/spapr_drc.c b/hw/ppc/spapr_drc.c index 94c875d..d276db3a 100644 --- a/hw/ppc/spapr_drc.c +++ b/hw/ppc/spapr_drc.c @@ -140,6 +140,8 @@ static uint32_t set_allocation_state(sPAPRDRConnector *drc, DPRINTFN("finalizing device removal"); drck->detach(drc, DEVICE(drc->dev), drc->detach_cb, drc->detach_cb_opaque, NULL); + } else if (drc->allocation_state == SPAPR_DR_ALLOCATION_STATE_USABLE) { + drc->awaiting_allocation = false; } } return RTAS_OUT_SUCCESS; @@ -373,6 +375,10 @@ static void attach(sPAPRDRConnector *drc, DeviceState *d, void *fdt, drc->signalled = (drc->type != SPAPR_DR_CONNECTOR_TYPE_PCI) ? true : coldplug; + if (drc->type != SPAPR_DR_CONNECTOR_TYPE_PCI) { + drc->awaiting_allocation = true; + } + object_property_add_link(OBJECT(drc), "device", object_get_typename(OBJECT(drc->dev)), (Object **)(&drc->dev), @@ -421,6 +427,12 @@ static void detach(sPAPRDRConnector *drc, DeviceState *d, return; } + if (drc->awaiting_allocation) { + drc->awaiting_release = true; + DPRINTFN("awaiting allocation to complete before removal"); + return; + } + drc->indicator_state = SPAPR_DR_INDICATOR_STATE_INACTIVE; if (drc->detach_cb) { -- cgit v1.1 From 3b542549661eb216580e8b7683e13caa3950da45 Mon Sep 17 00:00:00 2001 From: Bharata B Rao Date: Fri, 10 Jun 2016 06:29:01 +0530 Subject: spapr: Abstract CPU core device and type specific core devices Add sPAPR specific abastract CPU core device that is based on generic CPU core device. Use this as base type to create sPAPR CPU specific core devices. TODO: - Add core types for other remaining CPU types - Handle CPU model alias correctly Signed-off-by: Bharata B Rao Signed-off-by: David Gibson --- hw/ppc/Makefile.objs | 1 + hw/ppc/spapr.c | 3 +- hw/ppc/spapr_cpu_core.c | 160 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 162 insertions(+), 2 deletions(-) create mode 100644 hw/ppc/spapr_cpu_core.c (limited to 'hw') 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 9a4a803..48df0e4 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -1623,8 +1623,7 @@ 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) +void spapr_cpu_init(sPAPRMachineState *spapr, PowerPCCPU *cpu, Error **errp) { CPUPPCState *env = &cpu->env; diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c new file mode 100644 index 0000000..719777a --- /dev/null +++ b/hw/ppc/spapr_cpu_core.c @@ -0,0 +1,160 @@ +/* + * 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 "target-ppc/cpu.h" +#include "hw/ppc/spapr.h" +#include "hw/boards.h" +#include "qapi/error.h" +#include +#include "target-ppc/kvm_ppc.h" + +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; + } + return 0; +} + +static void spapr_cpu_core_realize(DeviceState *dev, Error **errp) +{ + sPAPRCPUCore *sc = SPAPR_CPU_CORE(OBJECT(dev)); + CPUCore *cc = CPU_CORE(OBJECT(dev)); + const char *typename = object_class_get_name(sc->cpu_class); + size_t size = object_type_get_instance_size(typename); + Error *local_err = NULL; + Object *obj; + int i; + + sc->threads = g_malloc0(size * cc->nr_threads); + for (i = 0; i < cc->nr_threads; i++) { + char id[32]; + void *obj = sc->threads + i * size; + + object_initialize(obj, size, typename); + snprintf(id, sizeof(id), "thread[%d]", i); + object_property_add_child(OBJECT(sc), id, obj, &local_err); + if (local_err) { + goto err; + } + } + object_child_foreach(OBJECT(dev), spapr_cpu_core_realize_child, &local_err); + if (local_err) { + goto err; + } else { + return; + } + +err: + while (i >= 0) { + obj = sc->threads + i * size; + object_unparent(obj); + i--; + } + g_free(sc->threads); + error_propagate(errp, local_err); +} + +static void spapr_cpu_core_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + dc->realize = spapr_cpu_core_realize; +} + +/* + * instance_init routines from different flavours of sPAPR CPU cores. + * TODO: Add support for 'host' core type. + */ +#define SPAPR_CPU_CORE_INITFN(_type, _fname) \ +static void glue(glue(spapr_cpu_core_, _fname), _initfn(Object *obj)) \ +{ \ + sPAPRCPUCore *core = SPAPR_CPU_CORE(obj); \ + char *name = g_strdup_printf("%s-" TYPE_POWERPC_CPU, stringify(_type)); \ + ObjectClass *oc = object_class_by_name(name); \ + g_assert(oc); \ + g_free((void *)name); \ + core->cpu_class = oc; \ +} + +SPAPR_CPU_CORE_INITFN(POWER7_v2.3, POWER7); +SPAPR_CPU_CORE_INITFN(POWER7+_v2.1, POWER7plus); +SPAPR_CPU_CORE_INITFN(POWER8_v2.0, POWER8); +SPAPR_CPU_CORE_INITFN(POWER8E_v2.1, POWER8E); + +typedef struct SPAPRCoreInfo { + const char *name; + void (*initfn)(Object *obj); +} SPAPRCoreInfo; + +static const SPAPRCoreInfo spapr_cores[] = { + /* POWER7 and aliases */ + { .name = "POWER7_v2.3", .initfn = spapr_cpu_core_POWER7_initfn }, + { .name = "POWER7", .initfn = spapr_cpu_core_POWER7_initfn }, + + /* POWER7+ and aliases */ + { .name = "POWER7+_v2.1", .initfn = spapr_cpu_core_POWER7plus_initfn }, + { .name = "POWER7+", .initfn = spapr_cpu_core_POWER7plus_initfn }, + + /* POWER8 and aliases */ + { .name = "POWER8_v2.0", .initfn = spapr_cpu_core_POWER8_initfn }, + { .name = "POWER8", .initfn = spapr_cpu_core_POWER8_initfn }, + { .name = "power8", .initfn = spapr_cpu_core_POWER8_initfn }, + + /* POWER8E and aliases */ + { .name = "POWER8E_v2.1", .initfn = spapr_cpu_core_POWER8E_initfn }, + { .name = "POWER8E", .initfn = spapr_cpu_core_POWER8E_initfn }, + + { .name = NULL } +}; + +static void spapr_cpu_core_register(const SPAPRCoreInfo *info) +{ + TypeInfo type_info = { + .parent = TYPE_SPAPR_CPU_CORE, + .instance_size = sizeof(sPAPRCPUCore), + .instance_init = info->initfn, + }; + + type_info.name = g_strdup_printf("%s-" TYPE_SPAPR_CPU_CORE, info->name); + type_register(&type_info); + g_free((void *)type_info.name); +} + +static const TypeInfo spapr_cpu_core_type_info = { + .name = TYPE_SPAPR_CPU_CORE, + .parent = TYPE_CPU_CORE, + .abstract = true, + .instance_size = sizeof(sPAPRCPUCore), + .class_init = spapr_cpu_core_class_init, +}; + +static void spapr_cpu_core_register_types(void) +{ + const SPAPRCoreInfo *info = spapr_cores; + + type_register_static(&spapr_cpu_core_type_info); + while (info->name) { + spapr_cpu_core_register(info); + info++; + } +} + +type_init(spapr_cpu_core_register_types) -- cgit v1.1 From afd10a0fa6e90b79bad981c7334df2995d667de2 Mon Sep 17 00:00:00 2001 From: Bharata B Rao Date: Fri, 10 Jun 2016 06:29:02 +0530 Subject: spapr: Move spapr_cpu_init() to spapr_cpu_core.c Start consolidating CPU init related routines in spapr_cpu_core.c. As part of this, move spapr_cpu_init() and its dependencies from spapr.c to spapr_cpu_core.c No functionality change in this patch. Signed-off-by: Bharata B Rao [dwg: Rename TIMEBASE_FREQ to SPAPR_TIMEBASE_FREQ, since it's now in a public(ish) header] Signed-off-by: David Gibson --- hw/ppc/spapr.c | 50 ++----------------------------------------------- hw/ppc/spapr_cpu_core.c | 48 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 48 deletions(-) (limited to 'hw') diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 48df0e4..b04a389 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -89,8 +89,6 @@ #define MIN_RMA_SLOF 128UL -#define TIMEBASE_FREQ 512000000ULL - #define PHANDLE_XICP 0x00001111 #define HTAB_SIZE(spapr) (1ULL << ((spapr)->htab_shift)) @@ -599,7 +597,8 @@ static void spapr_populate_cpu_dt(CPUState *cs, void *fdt, int offset, int index = ppc_get_vcpu_dt_id(cpu); uint32_t segs[] = {cpu_to_be32(28), cpu_to_be32(40), 0xffffffff, 0xffffffff}; - uint32_t tbfreq = kvm_enabled() ? kvmppc_get_tbfreq() : TIMEBASE_FREQ; + uint32_t tbfreq = kvm_enabled() ? kvmppc_get_tbfreq() + : SPAPR_TIMEBASE_FREQ; uint32_t cpufreq = kvm_enabled() ? kvmppc_get_clockfreq() : 1000000000; uint32_t page_sizes_prop[64]; size_t page_sizes_prop_size; @@ -1198,26 +1197,6 @@ static void ppc_spapr_reset(void) } -static void spapr_cpu_reset(void *opaque) -{ - sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine()); - PowerPCCPU *cpu = opaque; - CPUState *cs = CPU(cpu); - CPUPPCState *env = &cpu->env; - - cpu_reset(cs); - - /* All CPUs start halted. CPU0 is unhalted from the machine level - * reset code and the rest are explicitly started up by the guest - * using an RTAS call */ - cs->halted = 1; - - env->spr[SPR_HIOR] = 0; - - ppc_hash64_set_external_hpt(cpu, spapr->htab, spapr->htab_shift, - &error_fatal); -} - static void spapr_create_nvram(sPAPRMachineState *spapr) { DeviceState *dev = qdev_create(&spapr->vio_bus->bus, "spapr-nvram"); @@ -1623,31 +1602,6 @@ static void spapr_boot_set(void *opaque, const char *boot_device, machine->boot_order = g_strdup(boot_device); } -void spapr_cpu_init(sPAPRMachineState *spapr, PowerPCCPU *cpu, Error **errp) -{ - CPUPPCState *env = &cpu->env; - - /* Set time-base frequency to 512 MHz */ - cpu_ppc_tb_init(env, TIMEBASE_FREQ); - - /* Enable PAPR mode in TCG or KVM */ - cpu_ppc_set_papr(cpu); - - if (cpu->max_compat) { - Error *local_err = NULL; - - ppc_set_compat(cpu, cpu->max_compat, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } - } - - xics_cpu_setup(spapr->icp, cpu); - - qemu_register_reset(spapr_cpu_reset, cpu); -} - /* * Reset routine for LMB DR devices. * diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c index 719777a..2e24e39 100644 --- a/hw/ppc/spapr_cpu_core.c +++ b/hw/ppc/spapr_cpu_core.c @@ -14,6 +14,54 @@ #include "qapi/error.h" #include #include "target-ppc/kvm_ppc.h" +#include "hw/ppc/ppc.h" +#include "target-ppc/mmu-hash64.h" +#include + +static void spapr_cpu_reset(void *opaque) +{ + sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine()); + PowerPCCPU *cpu = opaque; + CPUState *cs = CPU(cpu); + CPUPPCState *env = &cpu->env; + + cpu_reset(cs); + + /* All CPUs start halted. CPU0 is unhalted from the machine level + * reset code and the rest are explicitly started up by the guest + * using an RTAS call */ + cs->halted = 1; + + env->spr[SPR_HIOR] = 0; + + ppc_hash64_set_external_hpt(cpu, spapr->htab, spapr->htab_shift, + &error_fatal); +} + +void spapr_cpu_init(sPAPRMachineState *spapr, PowerPCCPU *cpu, Error **errp) +{ + CPUPPCState *env = &cpu->env; + + /* Set time-base frequency to 512 MHz */ + cpu_ppc_tb_init(env, SPAPR_TIMEBASE_FREQ); + + /* Enable PAPR mode in TCG or KVM */ + cpu_ppc_set_papr(cpu); + + if (cpu->max_compat) { + Error *local_err = NULL; + + ppc_set_compat(cpu, cpu->max_compat, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + } + + xics_cpu_setup(spapr->icp, cpu); + + qemu_register_reset(spapr_cpu_reset, cpu); +} static int spapr_cpu_core_realize_child(Object *child, void *opaque) { -- cgit v1.1 From 94a94e4c49197d10e5ee7710bb0538ddeff75ba9 Mon Sep 17 00:00:00 2001 From: Bharata B Rao Date: Fri, 10 Jun 2016 06:29:03 +0530 Subject: spapr: convert boot CPUs into CPU core devices 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. TODO: We derive sPAPR core type by looking at -cpu . However we don't take care of "compat=" feature yet for boot time as well as hotplug CPUs. Signed-off-by: Bharata B Rao Reviewed-by: David Gibson Signed-off-by: David Gibson --- hw/ppc/spapr.c | 73 ++++++++++++++++++++++++++++++++++++++++++------- hw/ppc/spapr_cpu_core.c | 58 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 121 insertions(+), 10 deletions(-) (limited to 'hw') diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index b04a389..52e89af 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -66,6 +66,7 @@ #include "hw/compat.h" #include "qemu/cutils.h" +#include "hw/ppc/spapr_cpu_core.h" #include @@ -1683,7 +1684,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(); @@ -1697,6 +1697,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_nonbroken = true; @@ -1743,8 +1759,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) { @@ -1755,13 +1770,37 @@ 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) { + char *type = spapr_get_cpu_core_type(machine->cpu_model); + + spapr->cores = g_new0(Object *, spapr_max_cores); + for (i = 0; i < spapr_cores; i++) { + int core_dt_id = i * smt; + Object *core; + + if (!object_class_by_name(type)) { + error_report("Unable to find sPAPR CPU Core definition"); + exit(1); + } + + core = object_new(type); + object_property_set_int(core, smp_threads, "nr-threads", + &error_fatal); + object_property_set_int(core, core_dt_id, CPU_CORE_PROP_CORE_ID, + &error_fatal); + object_property_set_bool(core, true, "realized", &error_fatal); } - spapr_cpu_init(spapr, cpu, &error_fatal); + g_free(type); + } 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()) { @@ -2227,10 +2266,19 @@ static void spapr_machine_device_unplug(HotplugHandler *hotplug_dev, } } +static void spapr_machine_device_pre_plug(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) +{ + if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_CPU_CORE)) { + spapr_core_pre_plug(hotplug_dev, dev, errp); + } +} + 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; @@ -2269,11 +2317,13 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data) mc->has_dynamic_sysbus = true; mc->pci_allow_0_address = true; mc->get_hotplug_handler = spapr_get_hotpug_handler; + hc->pre_plug = spapr_machine_device_pre_plug; hc->plug = spapr_machine_device_plug; hc->unplug = spapr_machine_device_unplug; 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; } @@ -2349,7 +2399,10 @@ static void spapr_machine_2_6_instance_options(MachineState *machine) static void spapr_machine_2_6_class_options(MachineClass *mc) { + sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc); + spapr_machine_2_7_class_options(mc); + smc->dr_cpu_enabled = false; SET_MACHINE_COMPAT(mc, SPAPR_COMPAT_2_6); } diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c index 2e24e39..d747c26 100644 --- a/hw/ppc/spapr_cpu_core.c +++ b/hw/ppc/spapr_cpu_core.c @@ -63,6 +63,64 @@ void spapr_cpu_init(sPAPRMachineState *spapr, PowerPCCPU *cpu, Error **errp) qemu_register_reset(spapr_cpu_reset, cpu); } +/* + * Return the sPAPR CPU core type for @model which essentially is the CPU + * model specified with -cpu cmdline option. + */ +char *spapr_get_cpu_core_type(const char *model) +{ + char *core_type; + gchar **model_pieces = g_strsplit(model, ",", 2); + + core_type = g_strdup_printf("%s-%s", model_pieces[0], TYPE_SPAPR_CPU_CORE); + g_strfreev(model_pieces); + return core_type; +} + +void spapr_core_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev, + Error **errp) +{ + MachineState *machine = MACHINE(OBJECT(hotplug_dev)); + sPAPRMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev)); + int spapr_max_cores = max_cpus / smp_threads; + int index; + int smt = kvmppc_smt_threads(); + Error *local_err = NULL; + CPUCore *cc = CPU_CORE(dev); + char *base_core_type = spapr_get_cpu_core_type(machine->cpu_model); + const char *type = object_get_typename(OBJECT(dev)); + + if (strcmp(base_core_type, type)) { + error_setg(&local_err, "CPU core type should be %s", base_core_type); + goto out; + } + + if (cc->nr_threads != smp_threads) { + error_setg(&local_err, "threads must be %d", smp_threads); + goto out; + } + + if (cc->core_id % smt) { + error_setg(&local_err, "invalid core id %d\n", cc->core_id); + goto out; + } + + index = cc->core_id / smt; + if (index < 0 || index >= spapr_max_cores) { + error_setg(&local_err, "core id %d out of range", cc->core_id); + goto out; + } + + if (spapr->cores[index]) { + error_setg(&local_err, "core %d already populated", cc->core_id); + goto out; + } + +out: + g_free(base_core_type); + error_propagate(errp, local_err); +} + static int spapr_cpu_core_realize_child(Object *child, void *opaque) { Error **errp = opaque; -- cgit v1.1 From af81cf323c17083a3e016f9556c521357b46ab40 Mon Sep 17 00:00:00 2001 From: Bharata B Rao Date: Fri, 10 Jun 2016 06:29:04 +0530 Subject: spapr: CPU hotplug support Set up device tree entries for the hotplugged CPU core and use the exising RTAS event logging infrastructure to send CPU hotplug notification to the guest. Signed-off-by: Bharata B Rao Reviewed-by: David Gibson Signed-off-by: David Gibson --- hw/ppc/spapr.c | 78 +++++++++++++++++++++++++++++++++++++++-------- hw/ppc/spapr_cpu_core.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++++ hw/ppc/spapr_events.c | 3 ++ hw/ppc/spapr_rtas.c | 24 +++++++++++++++ 4 files changed, 172 insertions(+), 13 deletions(-) (limited to 'hw') diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 52e89af..c444a86 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -605,6 +605,16 @@ static void spapr_populate_cpu_dt(CPUState *cs, void *fdt, int offset, size_t page_sizes_prop_size; uint32_t vcpus_per_socket = smp_threads * smp_cores; uint32_t pft_size_prop[] = {0, cpu_to_be32(spapr->htab_shift)}; + sPAPRDRConnector *drc; + sPAPRDRConnectorClass *drck; + int drc_index; + + drc = spapr_dr_connector_by_id(SPAPR_DR_CONNECTOR_TYPE_CPU, index); + if (drc) { + drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc); + drc_index = drck->get_index(drc); + _FDT((fdt_setprop_cell(fdt, offset, "ibm,my-drc-index", drc_index))); + } /* Note: we keep CI large pages off for now because a 64K capable guest * provisioned with large pages might otherwise try to map a qemu @@ -1005,6 +1015,16 @@ static void spapr_finalize_fdt(sPAPRMachineState *spapr, _FDT(spapr_drc_populate_dt(fdt, 0, NULL, SPAPR_DR_CONNECTOR_TYPE_LMB)); } + if (smc->dr_cpu_enabled) { + int offset = fdt_path_offset(fdt, "/cpus"); + ret = spapr_drc_populate_dt(fdt, offset, NULL, + SPAPR_DR_CONNECTOR_TYPE_CPU); + if (ret < 0) { + error_report("Couldn't set up CPU DR device tree properties"); + exit(1); + } + } + _FDT((fdt_pack(fdt))); if (fdt_totalsize(fdt) > FDT_MAX_SIZE) { @@ -1775,21 +1795,30 @@ static void ppc_spapr_init(MachineState *machine) char *type = spapr_get_cpu_core_type(machine->cpu_model); spapr->cores = g_new0(Object *, spapr_max_cores); - for (i = 0; i < spapr_cores; i++) { + for (i = 0; i < spapr_max_cores; i++) { int core_dt_id = i * smt; - Object *core; - - if (!object_class_by_name(type)) { - error_report("Unable to find sPAPR CPU Core definition"); - exit(1); + sPAPRDRConnector *drc = + spapr_dr_connector_new(OBJECT(spapr), + SPAPR_DR_CONNECTOR_TYPE_CPU, core_dt_id); + + qemu_register_reset(spapr_drc_reset, drc); + + if (i < spapr_cores) { + char *type = spapr_get_cpu_core_type(machine->cpu_model); + Object *core; + + if (!object_class_by_name(type)) { + error_report("Unable to find sPAPR CPU Core definition"); + exit(1); + } + + core = object_new(type); + object_property_set_int(core, smp_threads, "nr-threads", + &error_fatal); + object_property_set_int(core, core_dt_id, CPU_CORE_PROP_CORE_ID, + &error_fatal); + object_property_set_bool(core, true, "realized", &error_fatal); } - - core = object_new(type); - object_property_set_int(core, smp_threads, "nr-threads", - &error_fatal); - object_property_set_int(core, core_dt_id, CPU_CORE_PROP_CORE_ID, - &error_fatal); - object_property_set_bool(core, true, "realized", &error_fatal); } g_free(type); } else { @@ -2211,6 +2240,27 @@ out: error_propagate(errp, local_err); } +void *spapr_populate_hotplug_cpu_dt(CPUState *cs, int *fdt_offset, + sPAPRMachineState *spapr) +{ + PowerPCCPU *cpu = POWERPC_CPU(cs); + DeviceClass *dc = DEVICE_GET_CLASS(cs); + int id = ppc_get_vcpu_dt_id(cpu); + void *fdt; + int offset, fdt_size; + char *nodename; + + fdt = create_device_tree(&fdt_size); + nodename = g_strdup_printf("%s@%x", dc->fw_name, id); + offset = fdt_add_subnode(fdt, 0, nodename); + + spapr_populate_cpu_dt(cs, fdt, offset, spapr); + g_free(nodename); + + *fdt_offset = offset; + return fdt; +} + static void spapr_machine_device_plug(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp) { @@ -2255,6 +2305,8 @@ static void spapr_machine_device_plug(HotplugHandler *hotplug_dev, } spapr_memory_plug(hotplug_dev, dev, node, errp); + } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_CPU_CORE)) { + spapr_core_plug(hotplug_dev, dev, errp); } } diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c index d747c26..d5fa4e6 100644 --- a/hw/ppc/spapr_cpu_core.c +++ b/hw/ppc/spapr_cpu_core.c @@ -41,6 +41,8 @@ static void spapr_cpu_reset(void *opaque) void spapr_cpu_init(sPAPRMachineState *spapr, PowerPCCPU *cpu, Error **errp) { CPUPPCState *env = &cpu->env; + CPUState *cs = CPU(cpu); + int i; /* Set time-base frequency to 512 MHz */ cpu_ppc_tb_init(env, SPAPR_TIMEBASE_FREQ); @@ -58,9 +60,18 @@ void spapr_cpu_init(sPAPRMachineState *spapr, PowerPCCPU *cpu, Error **errp) } } + /* Set NUMA node for the added CPUs */ + for (i = 0; i < nb_numa_nodes; i++) { + if (test_bit(cs->cpu_index, numa_info[i].node_cpu)) { + cs->numa_node = i; + break; + } + } + xics_cpu_setup(spapr->icp, cpu); qemu_register_reset(spapr_cpu_reset, cpu); + spapr_cpu_reset(cpu); } /* @@ -77,10 +88,74 @@ char *spapr_get_cpu_core_type(const char *model) return core_type; } +void spapr_core_plug(HotplugHandler *hotplug_dev, DeviceState *dev, + Error **errp) +{ + sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(OBJECT(hotplug_dev)); + sPAPRMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev)); + sPAPRCPUCore *core = SPAPR_CPU_CORE(OBJECT(dev)); + CPUCore *cc = CPU_CORE(dev); + CPUState *cs = CPU(core->threads); + sPAPRDRConnector *drc; + sPAPRDRConnectorClass *drck; + Error *local_err = NULL; + void *fdt = NULL; + int fdt_offset = 0; + int index; + int smt = kvmppc_smt_threads(); + + drc = spapr_dr_connector_by_id(SPAPR_DR_CONNECTOR_TYPE_CPU, cc->core_id); + index = cc->core_id / smt; + spapr->cores[index] = OBJECT(dev); + + if (!smc->dr_cpu_enabled) { + /* + * This is a cold plugged CPU core but the machine doesn't support + * DR. So skip the hotplug path ensuring that the core is brought + * up online with out an associated DR connector. + */ + return; + } + + g_assert(drc); + + /* + * Setup CPU DT entries only for hotplugged CPUs. For boot time or + * coldplugged CPUs DT entries are setup in spapr_finalize_fdt(). + */ + if (dev->hotplugged) { + fdt = spapr_populate_hotplug_cpu_dt(cs, &fdt_offset, spapr); + } + + drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc); + drck->attach(drc, dev, fdt, fdt_offset, !dev->hotplugged, &local_err); + if (local_err) { + g_free(fdt); + spapr->cores[index] = NULL; + error_propagate(errp, local_err); + return; + } + + if (dev->hotplugged) { + /* + * Send hotplug notification interrupt to the guest only in case + * of hotplugged CPUs. + */ + spapr_hotplug_req_add_by_index(drc); + } else { + /* + * Set the right DRC states for cold plugged CPU. + */ + drck->set_allocation_state(drc, SPAPR_DR_ALLOCATION_STATE_USABLE); + drck->set_isolation_state(drc, SPAPR_DR_ISOLATION_STATE_UNISOLATED); + } +} + void spapr_core_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp) { MachineState *machine = MACHINE(OBJECT(hotplug_dev)); + sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(OBJECT(hotplug_dev)); sPAPRMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev)); int spapr_max_cores = max_cpus / smp_threads; int index; @@ -95,6 +170,11 @@ void spapr_core_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev, goto out; } + if (!smc->dr_cpu_enabled && dev->hotplugged) { + error_setg(&local_err, "CPU hotplug not supported for this machine"); + goto out; + } + if (cc->nr_threads != smp_threads) { error_setg(&local_err, "threads must be %d", smp_threads); goto out; diff --git a/hw/ppc/spapr_events.c b/hw/ppc/spapr_events.c index 049fb1b..af80992 100644 --- a/hw/ppc/spapr_events.c +++ b/hw/ppc/spapr_events.c @@ -449,6 +449,9 @@ static void spapr_hotplug_req_event(uint8_t hp_id, uint8_t hp_action, case SPAPR_DR_CONNECTOR_TYPE_LMB: hp->hotplug_type = RTAS_LOG_V6_HP_TYPE_MEMORY; break; + case SPAPR_DR_CONNECTOR_TYPE_CPU: + hp->hotplug_type = RTAS_LOG_V6_HP_TYPE_CPU; + break; default: /* we shouldn't be signaling hotplug events for resources * that don't support them diff --git a/hw/ppc/spapr_rtas.c b/hw/ppc/spapr_rtas.c index 43e2c68..dc058e5 100644 --- a/hw/ppc/spapr_rtas.c +++ b/hw/ppc/spapr_rtas.c @@ -36,6 +36,7 @@ #include "hw/ppc/spapr.h" #include "hw/ppc/spapr_vio.h" +#include "hw/ppc/ppc.h" #include "qapi-event.h" #include "hw/boards.h" @@ -164,6 +165,27 @@ static void rtas_query_cpu_stopped_state(PowerPCCPU *cpu_, rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); } +/* + * Set the timebase offset of the CPU to that of first CPU. + * This helps hotplugged CPU to have the correct timebase offset. + */ +static void spapr_cpu_update_tb_offset(PowerPCCPU *cpu) +{ + PowerPCCPU *fcpu = POWERPC_CPU(first_cpu); + + cpu->env.tb_env->tb_offset = fcpu->env.tb_env->tb_offset; +} + +static void spapr_cpu_set_endianness(PowerPCCPU *cpu) +{ + PowerPCCPU *fcpu = POWERPC_CPU(first_cpu); + PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(fcpu); + + if (!pcc->interrupts_big_endian(fcpu)) { + cpu->env.spr[SPR_LPCR] |= LPCR_ILE; + } +} + static void rtas_start_cpu(PowerPCCPU *cpu_, sPAPRMachineState *spapr, uint32_t token, uint32_t nargs, target_ulong args, @@ -200,6 +222,8 @@ static void rtas_start_cpu(PowerPCCPU *cpu_, sPAPRMachineState *spapr, env->nip = start; env->gpr[3] = r3; cs->halted = 0; + spapr_cpu_set_endianness(cpu); + spapr_cpu_update_tb_offset(cpu); qemu_cpu_kick(cs); -- cgit v1.1 From 6f4b5c3ec590b04ba58fda753a81a93f316b77a4 Mon Sep 17 00:00:00 2001 From: Bharata B Rao Date: Fri, 10 Jun 2016 06:29:05 +0530 Subject: spapr: CPU hot unplug support Remove the CPU core device by removing the underlying CPU thread devices. Hot removal of CPU for sPAPR guests is achieved by sending the hot unplug notification to the guest. Release the vCPU object after CPU hot unplug so that vCPU fd can be parked and reused. Signed-off-by: Bharata B Rao Signed-off-by: David Gibson --- hw/ppc/spapr.c | 8 +++++++ hw/ppc/spapr_cpu_core.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+) (limited to 'hw') diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index c444a86..1dcb9f6 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -2313,8 +2313,16 @@ static void spapr_machine_device_plug(HotplugHandler *hotplug_dev, static void spapr_machine_device_unplug(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp) { + sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(qdev_get_machine()); + if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { error_setg(errp, "Memory hot unplug not supported by sPAPR"); + } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_CPU_CORE)) { + if (!smc->dr_cpu_enabled) { + error_setg(errp, "CPU hot unplug not supported on this machine"); + return; + } + spapr_core_unplug(hotplug_dev, dev, errp); } } diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c index d5fa4e6..3a5da09 100644 --- a/hw/ppc/spapr_cpu_core.c +++ b/hw/ppc/spapr_cpu_core.c @@ -38,6 +38,14 @@ static void spapr_cpu_reset(void *opaque) &error_fatal); } +static void spapr_cpu_destroy(PowerPCCPU *cpu) +{ + sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine()); + + xics_cpu_destroy(spapr->icp, cpu); + qemu_unregister_reset(spapr_cpu_reset, cpu); +} + void spapr_cpu_init(sPAPRMachineState *spapr, PowerPCCPU *cpu, Error **errp) { CPUPPCState *env = &cpu->env; @@ -88,6 +96,57 @@ char *spapr_get_cpu_core_type(const char *model) return core_type; } +static void spapr_core_release(DeviceState *dev, void *opaque) +{ + sPAPRCPUCore *sc = SPAPR_CPU_CORE(OBJECT(dev)); + const char *typename = object_class_get_name(sc->cpu_class); + size_t size = object_type_get_instance_size(typename); + sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine()); + sPAPRCPUCore *core = SPAPR_CPU_CORE(OBJECT(dev)); + CPUCore *cc = CPU_CORE(dev); + int smt = kvmppc_smt_threads(); + int i; + + for (i = 0; i < cc->nr_threads; i++) { + void *obj = sc->threads + i * size; + DeviceState *dev = DEVICE(obj); + CPUState *cs = CPU(dev); + PowerPCCPU *cpu = POWERPC_CPU(cs); + + spapr_cpu_destroy(cpu); + cpu_remove_sync(cs); + object_unparent(obj); + } + + spapr->cores[cc->core_id / smt] = NULL; + + g_free(core->threads); + object_unparent(OBJECT(dev)); +} + +void spapr_core_unplug(HotplugHandler *hotplug_dev, DeviceState *dev, + Error **errp) +{ + sPAPRCPUCore *core = SPAPR_CPU_CORE(OBJECT(dev)); + PowerPCCPU *cpu = POWERPC_CPU(core->threads); + int id = ppc_get_vcpu_dt_id(cpu); + sPAPRDRConnector *drc = + spapr_dr_connector_by_id(SPAPR_DR_CONNECTOR_TYPE_CPU, id); + sPAPRDRConnectorClass *drck; + Error *local_err = NULL; + + g_assert(drc); + + drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc); + drck->detach(drc, dev, spapr_core_release, NULL, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + + spapr_hotplug_req_remove_by_index(drc); +} + void spapr_core_plug(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp) { -- cgit v1.1 From 2474bfd4603b2d354fdb4001b083b7c72bff627f Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Fri, 10 Jun 2016 06:29:08 +0530 Subject: spapr: implement query-hotpluggable-cpus callback It returns a list of present/possible to hotplug CPU objects with a list of properties to use with device_add. in spapr case returned list would looks like: -> { "execute": "query-hotpluggable-cpus" } <- {"return": [ { "props": { "core": 8 }, "type": "POWER8-spapr-cpu-core", "vcpus-count": 2 }, { "props": { "core": 0 }, "type": "POWER8-spapr-cpu-core", "vcpus-count": 2, "qom-path": "/machine/unattached/device[0]"} ]}' TODO: add 'node' property for core <-> numa node mapping Signed-off-by: Igor Mammedov Signed-off-by: Bharata B Rao Signed-off-by: David Gibson --- hw/ppc/spapr.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) (limited to 'hw') diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 1dcb9f6..778fa25 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -67,6 +67,7 @@ #include "hw/compat.h" #include "qemu/cutils.h" #include "hw/ppc/spapr_cpu_core.h" +#include "qmp-commands.h" #include @@ -2351,6 +2352,38 @@ static unsigned spapr_cpu_index_to_socket_id(unsigned cpu_index) return cpu_index / smp_threads / smp_cores; } +static HotpluggableCPUList *spapr_query_hotpluggable_cpus(MachineState *machine) +{ + int i; + HotpluggableCPUList *head = NULL; + sPAPRMachineState *spapr = SPAPR_MACHINE(machine); + int spapr_max_cores = max_cpus / smp_threads; + int smt = kvmppc_smt_threads(); + + for (i = 0; i < spapr_max_cores; i++) { + HotpluggableCPUList *list_item = g_new0(typeof(*list_item), 1); + HotpluggableCPU *cpu_item = g_new0(typeof(*cpu_item), 1); + CpuInstanceProperties *cpu_props = g_new0(typeof(*cpu_props), 1); + + cpu_item->type = spapr_get_cpu_core_type(machine->cpu_model); + cpu_item->vcpus_count = smp_threads; + cpu_props->has_core = true; + cpu_props->core = i * smt; + /* TODO: add 'has_node/node' here to describe + to which node core belongs */ + + cpu_item->props = cpu_props; + if (spapr->cores[i]) { + cpu_item->has_qom_path = true; + cpu_item->qom_path = object_get_canonical_path(spapr->cores[i]); + } + list_item->value = cpu_item; + list_item->next = head; + head = list_item; + } + return head; +} + static void spapr_machine_class_init(ObjectClass *oc, void *data) { MachineClass *mc = MACHINE_CLASS(oc); @@ -2381,6 +2414,7 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data) hc->plug = spapr_machine_device_plug; hc->unplug = spapr_machine_device_unplug; mc->cpu_index_to_socket_id = spapr_cpu_index_to_socket_id; + mc->query_hotpluggable_cpus = spapr_query_hotpluggable_cpus; smc->dr_lmb_enabled = true; smc->dr_cpu_enabled = true; -- cgit v1.1