198 lines
7.6 KiB
Diff
198 lines
7.6 KiB
Diff
|
|
From 724ab355c047cfb3e970d9ea78577087568eb095 Mon Sep 17 00:00:00 2001
|
||
|
|
From: Salil Mehta <salil.mehta@huawei.com>
|
||
|
|
Date: Fri, 8 May 2020 18:40:19 +0100
|
||
|
|
Subject: [PATCH] arm/virt: Add/update basic hot-(un)plug framework
|
||
|
|
|
||
|
|
Add CPU hot-unplug hooks and update hotplug hooks with additional sanity checks
|
||
|
|
for use in hotplug paths.
|
||
|
|
|
||
|
|
Note, Functional contents of the hooks(now left with TODO comment) shall be
|
||
|
|
gradually filled in the subsequent patches in an incremental approach to patch
|
||
|
|
and logic building which would be roughly as follows:
|
||
|
|
1. (Un-)wiring of interrupts between vCPU<->GIC
|
||
|
|
2. Sending events to Guest for hot-(un)plug so that guest can take appropriate
|
||
|
|
actions.
|
||
|
|
3. Notifying GIC about hot-(un)plug action so that vCPU could be (un-)stitched
|
||
|
|
to the GIC CPU interface.
|
||
|
|
4. Updating the Guest with Next boot info for this vCPU in the firmware.
|
||
|
|
|
||
|
|
Co-developed-by: Salil Mehta <salil.mehta@huawei.com>
|
||
|
|
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
|
||
|
|
Co-developed-by: Keqian Zhu <zhukeqian1@huawei.com>
|
||
|
|
Signed-off-by: Keqian Zhu <zhukeqian1@huawei.com>
|
||
|
|
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
|
||
|
|
---
|
||
|
|
hw/arm/virt.c | 104 ++++++++++++++++++++++++++++++++++++++++++++++++++
|
||
|
|
1 file changed, 104 insertions(+)
|
||
|
|
|
||
|
|
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
|
||
|
|
index bf385a469c..ed354be326 100644
|
||
|
|
--- a/hw/arm/virt.c
|
||
|
|
+++ b/hw/arm/virt.c
|
||
|
|
@@ -83,6 +83,7 @@
|
||
|
|
#include "hw/virtio/virtio-iommu.h"
|
||
|
|
#include "hw/char/pl011.h"
|
||
|
|
#include "qemu/guest-random.h"
|
||
|
|
+#include "qapi/qmp/qdict.h"
|
||
|
|
|
||
|
|
#define DEFINE_VIRT_MACHINE_LATEST(major, minor, latest) \
|
||
|
|
static void virt_##major##_##minor##_class_init(ObjectClass *oc, \
|
||
|
|
@@ -3083,12 +3084,23 @@ static void virt_cpu_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
|
||
|
|
{
|
||
|
|
VirtMachineState *vms = VIRT_MACHINE(hotplug_dev);
|
||
|
|
MachineState *ms = MACHINE(hotplug_dev);
|
||
|
|
+ MachineClass *mc = MACHINE_GET_CLASS(ms);
|
||
|
|
ARMCPU *cpu = ARM_CPU(dev);
|
||
|
|
CPUState *cs = CPU(dev);
|
||
|
|
CPUArchId *cpu_slot;
|
||
|
|
int32_t min_cpuid = 0;
|
||
|
|
int32_t max_cpuid;
|
||
|
|
|
||
|
|
+ if (dev->hotplugged && !vms->acpi_dev) {
|
||
|
|
+ error_setg(errp, "GED acpi device does not exists");
|
||
|
|
+ return;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (dev->hotplugged && !mc->has_hotpluggable_cpus) {
|
||
|
|
+ error_setg(errp, "CPU hotplug not supported on this machine");
|
||
|
|
+ return;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
/* sanity check the cpu */
|
||
|
|
if (!object_dynamic_cast(OBJECT(cpu), ms->cpu_type)) {
|
||
|
|
error_setg(errp, "Invalid CPU type, expected cpu type: '%s'",
|
||
|
|
@@ -3137,6 +3149,22 @@ static void virt_cpu_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
|
||
|
|
}
|
||
|
|
virt_cpu_set_properties(OBJECT(cs), cpu_slot, errp);
|
||
|
|
|
||
|
|
+ /*
|
||
|
|
+ * Fix the GIC for this new vCPU being plugged. The QOM CPU object for the
|
||
|
|
+ * new vCPU need to be updated in the corresponding QOM GICv3CPUState object
|
||
|
|
+ * We also need to re-wire the IRQs for this new CPU object. This update
|
||
|
|
+ * is limited to the QOM only and does not affects the KVM. Later has
|
||
|
|
+ * already been pre-sized with possible CPU at VM init time. This is a
|
||
|
|
+ * workaround to the constraints posed by ARM architecture w.r.t supporting
|
||
|
|
+ * CPU Hotplug. Specification does not exist for the later.
|
||
|
|
+ * This patch-up is required both for {cold,hot}-plugged vCPUs. Cold-inited
|
||
|
|
+ * vCPUs have their GIC state initialized during machvit_init().
|
||
|
|
+ */
|
||
|
|
+ if (vms->acpi_dev) {
|
||
|
|
+ /* TODO: update GIC about this hotplug change here */
|
||
|
|
+ /* TODO: wire the GIC<->CPU irqs */
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
/*
|
||
|
|
* To give persistent presence view of vCPUs to the guest, ACPI might need
|
||
|
|
* to fake the presence of the vCPUs to the guest but keep them disabled.
|
||
|
|
@@ -3148,6 +3176,7 @@ static void virt_cpu_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
|
||
|
|
static void virt_cpu_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
|
||
|
|
Error **errp)
|
||
|
|
{
|
||
|
|
+ VirtMachineState *vms = VIRT_MACHINE(hotplug_dev);
|
||
|
|
MachineState *ms = MACHINE(hotplug_dev);
|
||
|
|
CPUState *cs = CPU(dev);
|
||
|
|
CPUArchId *cpu_slot;
|
||
|
|
@@ -3156,10 +3185,81 @@ static void virt_cpu_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
|
||
|
|
cpu_slot = virt_find_cpu_slot(ms, cs->cpu_index);
|
||
|
|
cpu_slot->cpu = OBJECT(dev);
|
||
|
|
|
||
|
|
+ /*
|
||
|
|
+ * Update the ACPI Hotplug state both for vCPUs being {hot,cold}-plugged.
|
||
|
|
+ * vCPUs can be cold-plugged using '-device' option. For vCPUs being hot
|
||
|
|
+ * plugged, guest is also notified.
|
||
|
|
+ */
|
||
|
|
+ if (vms->acpi_dev) {
|
||
|
|
+ /* TODO: update acpi hotplug state. Send cpu hotplug event to guest */
|
||
|
|
+ /* TODO: register cpu for reset & update F/W info for the next boot */
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
cs->disabled = false;
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
+static void virt_cpu_unplug_request(HotplugHandler *hotplug_dev,
|
||
|
|
+ DeviceState *dev, Error **errp)
|
||
|
|
+{
|
||
|
|
+ MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine());
|
||
|
|
+ VirtMachineState *vms = VIRT_MACHINE(hotplug_dev);
|
||
|
|
+ ARMCPU *cpu = ARM_CPU(dev);
|
||
|
|
+ CPUState *cs = CPU(dev);
|
||
|
|
+
|
||
|
|
+ if (!vms->acpi_dev || !dev->realized) {
|
||
|
|
+ error_setg(errp, "GED does not exists or device is not realized!");
|
||
|
|
+ return;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (!mc->has_hotpluggable_cpus) {
|
||
|
|
+ error_setg(errp, "CPU hot(un)plug not supported on this machine");
|
||
|
|
+ return;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (cs->cpu_index == first_cpu->cpu_index) {
|
||
|
|
+ error_setg(errp, "Boot CPU(id%d=%d:%d:%d:%d) hot-unplug not supported",
|
||
|
|
+ first_cpu->cpu_index, cpu->socket_id, cpu->cluster_id,
|
||
|
|
+ cpu->core_id, cpu->thread_id);
|
||
|
|
+ return;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ /* TODO: request cpu hotplug from guest */
|
||
|
|
+
|
||
|
|
+ return;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+static void virt_cpu_unplug(HotplugHandler *hotplug_dev, DeviceState *dev,
|
||
|
|
+ Error **errp)
|
||
|
|
+{
|
||
|
|
+ VirtMachineState *vms = VIRT_MACHINE(hotplug_dev);
|
||
|
|
+ MachineState *ms = MACHINE(hotplug_dev);
|
||
|
|
+ CPUState *cs = CPU(dev);
|
||
|
|
+ CPUArchId *cpu_slot;
|
||
|
|
+
|
||
|
|
+ if (!vms->acpi_dev || !dev->realized) {
|
||
|
|
+ error_setg(errp, "GED does not exists or device is not realized!");
|
||
|
|
+ return;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ cpu_slot = virt_find_cpu_slot(ms, cs->cpu_index);
|
||
|
|
+
|
||
|
|
+ /* TODO: update the acpi cpu hotplug state for cpu hot-unplug */
|
||
|
|
+
|
||
|
|
+ /* TODO: unwire the gic-cpu irqs here */
|
||
|
|
+ /* TODO: update the GIC about this hot unplug change */
|
||
|
|
+
|
||
|
|
+ /* TODO: unregister cpu for reset & update F/W info for the next boot */
|
||
|
|
+
|
||
|
|
+ qobject_unref(dev->opts);
|
||
|
|
+ dev->opts = NULL;
|
||
|
|
+
|
||
|
|
+ cpu_slot->cpu = NULL;
|
||
|
|
+ cs->disabled = true;
|
||
|
|
+
|
||
|
|
+ return;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
static void virt_machine_device_pre_plug_cb(HotplugHandler *hotplug_dev,
|
||
|
|
DeviceState *dev, Error **errp)
|
||
|
|
{
|
||
|
|
@@ -3284,6 +3384,8 @@ static void virt_machine_device_unplug_request_cb(HotplugHandler *hotplug_dev,
|
||
|
|
} else if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_MD_PCI)) {
|
||
|
|
virtio_md_pci_unplug_request(VIRTIO_MD_PCI(dev), MACHINE(hotplug_dev),
|
||
|
|
errp);
|
||
|
|
+ } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
|
||
|
|
+ virt_cpu_unplug_request(hotplug_dev, dev, errp);
|
||
|
|
} else {
|
||
|
|
error_setg(errp, "device unplug request for unsupported device"
|
||
|
|
" type: %s", object_get_typename(OBJECT(dev)));
|
||
|
|
@@ -3297,6 +3399,8 @@ static void virt_machine_device_unplug_cb(HotplugHandler *hotplug_dev,
|
||
|
|
virt_dimm_unplug(hotplug_dev, dev, errp);
|
||
|
|
} else if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_MD_PCI)) {
|
||
|
|
virtio_md_pci_unplug(VIRTIO_MD_PCI(dev), MACHINE(hotplug_dev), errp);
|
||
|
|
+ } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
|
||
|
|
+ virt_cpu_unplug(hotplug_dev, dev, errp);
|
||
|
|
} else {
|
||
|
|
error_setg(errp, "virt: device unplug for unsupported device"
|
||
|
|
" type: %s", object_get_typename(OBJECT(dev)));
|
||
|
|
--
|
||
|
|
2.27.0
|
||
|
|
|