aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--hw/ppc/spapr.c8
-rw-r--r--hw/ppc/spapr_cpu_core.c59
-rw-r--r--include/hw/ppc/spapr_cpu_core.h2
3 files changed, 69 insertions, 0 deletions
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index c444a86a59..1dcb9f6922 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 d5fa4e611c..3a5da09b99 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)
{
diff --git a/include/hw/ppc/spapr_cpu_core.h b/include/hw/ppc/spapr_cpu_core.h
index 7cb0515035..1c9b3195cc 100644
--- a/include/hw/ppc/spapr_cpu_core.h
+++ b/include/hw/ppc/spapr_cpu_core.h
@@ -31,4 +31,6 @@ void spapr_core_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
char *spapr_get_cpu_core_type(const char *model);
void spapr_core_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
Error **errp);
+void spapr_core_unplug(HotplugHandler *hotplug_dev, DeviceState *dev,
+ Error **errp);
#endif