[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [RFC PATCH 6/7] hw/arm/virt: Add cpu hotplug support
From: |
Shannon Zhao |
Subject: |
[Qemu-devel] [RFC PATCH 6/7] hw/arm/virt: Add cpu hotplug support |
Date: |
Tue, 17 Feb 2015 18:10:05 +0800 |
Add a hotplug device in machine virt and add cpu hotplug support
using cpu-add.
Signed-off-by: Shannon Zhao <address@hidden>
---
hw/arm/virt.c | 159 +++++++++++++++++++++++++++++++++++++++-
include/hw/acpi/virt-hotplug.h | 1 +
2 files changed, 159 insertions(+), 1 deletions(-)
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index f689bc3..760afbb 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -43,6 +43,8 @@
#include "qemu/bitops.h"
#include "qemu/error-report.h"
#include "hw/arm/virt-acpi-build.h"
+#include "hw/acpi/virt-hotplug.h"
+#include "hw/hotplug.h"
#define NUM_VIRTIO_TRANSPORTS 32
@@ -76,6 +78,7 @@ enum {
VIRT_RTC,
VIRT_FW_CFG,
VIRT_GPIO,
+ VIRT_CPU_HOTPLUG,
};
typedef struct MemMapEntry {
@@ -102,8 +105,11 @@ typedef struct {
typedef struct {
MachineState parent;
bool secure;
+ HotplugHandler *acpi_dev;
} VirtMachineState;
+#define VIRT_MACHINE_ACPI_DEVICE_PROP "acpi-device"
+
#define TYPE_VIRT_MACHINE "virt"
#define VIRT_MACHINE(obj) \
OBJECT_CHECK(VirtMachineState, (obj), TYPE_VIRT_MACHINE)
@@ -135,6 +141,7 @@ static const MemMapEntry a15memmap[] = {
[VIRT_RTC] = { 0x09010000, 0x00001000 },
[VIRT_FW_CFG] = { 0x09020000, 0x0000000a },
[VIRT_GPIO] = { 0x09500000, 0x00001000 },
+ [VIRT_CPU_HOTPLUG] = { 0x09600000, 0x00000020 },
[VIRT_MMIO] = { 0x0a000000, 0x00000200 },
/* ...repeating for a total of NUM_VIRTIO_TRANSPORTS, each of that size */
/* 0x10000000 .. 0x40000000 reserved for PCI */
@@ -381,7 +388,7 @@ static void create_gic(const VirtBoardInfo *vbi, qemu_irq
*pic)
gicdev = qdev_create(NULL, gictype);
qdev_prop_set_uint32(gicdev, "revision", 2);
- qdev_prop_set_uint32(gicdev, "num-cpu", smp_cpus);
+ qdev_prop_set_uint32(gicdev, "num-cpu", max_cpus);
/* Note that the num-irq property counts both internal and external
* interrupts; there are always 32 of the former (mandated by GIC spec).
*/
@@ -630,6 +637,136 @@ void virt_guest_info_machine_done(Notifier *notifier,
void *data)
virt_acpi_setup(&guest_info_state->info);
}
+static void virt_new_cpu(const char *cpu_model, int64_t apic_id,
+ Error **errp)
+{
+ ObjectClass *oc = cpu_class_by_name(TYPE_ARM_CPU, cpu_model);
+ Object *cpuobj;
+ VirtBoardInfo *vbi;
+ SysBusDevice *gicbusdev;
+
+ vbi = find_machine_info(cpu_model);
+
+ if (!oc) {
+ fprintf(stderr, "Unable to find CPU definition\n");
+ exit(1);
+ }
+ cpuobj = object_new(object_class_get_name(oc));
+
+ object_property_set_int(cpuobj, QEMU_PSCI_CONDUIT_HVC, "psci-conduit",
+ NULL);
+
+ /* Secondary CPUs start in PSCI powered-down state */
+ object_property_set_bool(cpuobj, true, "start-powered-off", NULL);
+
+ if (object_property_find(cpuobj, "reset-cbar", NULL)) {
+ object_property_set_int(cpuobj, vbi->memmap[VIRT_CPUPERIPHS].base,
+ "reset-cbar", &error_abort);
+ }
+
+ object_property_set_bool(cpuobj, true, "realized", NULL);
+
+ const char *gictype = "arm_gic";
+ if (kvm_irqchip_in_kernel()) {
+ gictype = "kvm-arm-gic";
+ }
+
+ bool ambig;
+ Object *o = object_resolve_path_type("", gictype, &ambig);
+ DeviceState *gicdev = DEVICE(o);
+ DeviceState *cpudev = DEVICE(cpuobj);
+ gicbusdev = SYS_BUS_DEVICE(gicdev);
+ int ppibase = NUM_IRQS + apic_id * 32;
+ /* physical timer; we wire it up to the non-secure timer's ID,
+ * since a real A15 always has TrustZone but QEMU doesn't.
+ */
+ qdev_connect_gpio_out(cpudev, 0,
+ qdev_get_gpio_in(gicdev, ppibase + 30));
+ /* virtual timer */
+ qdev_connect_gpio_out(cpudev, 1,
+ qdev_get_gpio_in(gicdev, ppibase + 27));
+
+ sysbus_connect_irq(gicbusdev, apic_id,
+ qdev_get_gpio_in(cpudev, ARM_CPU_IRQ));
+}
+
+static const char *current_cpu_model;
+
+static void virt_hot_add_cpu(const int64_t id, Error **errp)
+{
+ int64_t apic_id = arm_cpu_apic_id_from_index(id);
+ if (id < 0) {
+ error_setg(errp, "Invalid CPU id: %" PRIi64, id);
+ return;
+ }
+
+ if (cpu_exists(apic_id)) {
+ error_setg(errp, "Unable to add CPU: %" PRIi64
+ ", it already exists", id);
+ return;
+ }
+
+ if (id >= max_cpus) {
+ error_setg(errp, "Unable to add CPU: %" PRIi64
+ ", max allowed: %d", id, max_cpus - 1);
+ return;
+ }
+
+ if (apic_id >= VIRT_ACPI_CPU_HOTPLUG_ID_LIMIT) {
+ error_setg(errp, "Unable to add CPU: %" PRIi64
+ ", resulting APIC ID (%" PRIi64 ") is too large",
+ id, apic_id);
+ return;
+ }
+
+ virt_new_cpu(current_cpu_model, apic_id, errp);
+}
+
+static void virt_cpu_plug(HotplugHandler *hotplug_dev,
+ DeviceState *dev, Error **errp)
+{
+ HotplugHandlerClass *hhc;
+ Error *local_err = NULL;
+ VirtMachineState *virtms = VIRT_MACHINE(hotplug_dev);
+
+ if (!dev->hotplugged) {
+ goto out;
+ }
+
+ if (!virtms->acpi_dev) {
+ error_setg(&local_err,
+ "cpu hotplug is not enabled: missing acpi device");
+ goto out;
+ }
+
+ hhc = HOTPLUG_HANDLER_GET_CLASS(virtms->acpi_dev);
+ hhc->plug(HOTPLUG_HANDLER(virtms->acpi_dev), dev, &local_err);
+ if (local_err) {
+ goto out;
+ }
+
+out:
+ error_propagate(errp, local_err);
+}
+
+static void virt_machine_device_plug_cb(HotplugHandler *hotplug_dev,
+ DeviceState *dev, Error **errp)
+{
+ if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
+ virt_cpu_plug(hotplug_dev, dev, errp);
+ }
+}
+
+static HotplugHandler *virt_get_hotpug_handler(MachineState *machine,
+ DeviceState *dev)
+{
+ if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
+ return HOTPLUG_HANDLER(machine);
+ }
+
+ return NULL;
+}
+
static void machvirt_init(MachineState *machine)
{
VirtMachineState *vms = VIRT_MACHINE(machine);
@@ -641,10 +778,12 @@ static void machvirt_init(MachineState *machine)
VirtBoardInfo *vbi;
VirtGuestInfoState *guest_info_state = g_malloc0(sizeof *guest_info_state);
VirtGuestInfo *guest_info = &guest_info_state->info;
+ DeviceState *virt_hotplug;
if (!cpu_model) {
cpu_model = "cortex-a15";
}
+ current_cpu_model = cpu_model;
vbi = find_machine_info(cpu_model);
@@ -710,6 +849,16 @@ static void machvirt_init(MachineState *machine)
create_gpio(vbi, pic);
+ virt_hotplug_init(&virt_hotplug);
+
+ object_property_add_link(OBJECT(machine), VIRT_MACHINE_ACPI_DEVICE_PROP,
+ TYPE_HOTPLUG_HANDLER,
+ (Object **)&vms->acpi_dev,
+ object_property_allow_set_link,
+ OBJ_PROP_LINK_UNREF_ON_RELEASE, &error_abort);
+ object_property_set_link(OBJECT(machine), OBJECT(virt_hotplug),
+ VIRT_MACHINE_ACPI_DEVICE_PROP, &error_abort);
+
/* Create mmio transports, so the user can create virtio backends
* (which will be automatically plugged in to the transports). If
* no backend is created the transport will just sit harmlessly idle.
@@ -772,11 +921,15 @@ static void virt_instance_init(Object *obj)
static void virt_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
+ HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc);
mc->name = TYPE_VIRT_MACHINE;
mc->desc = "ARM Virtual Machine",
mc->init = machvirt_init;
+ mc->hot_add_cpu = virt_hot_add_cpu,
mc->max_cpus = 8;
+ mc->get_hotplug_handler = virt_get_hotpug_handler;
+ hc->plug = virt_machine_device_plug_cb;
}
static const TypeInfo machvirt_info = {
@@ -786,6 +939,10 @@ static const TypeInfo machvirt_info = {
.instance_init = virt_instance_init,
.class_size = sizeof(VirtMachineClass),
.class_init = virt_class_init,
+ .interfaces = (InterfaceInfo[]) {
+ { TYPE_HOTPLUG_HANDLER },
+ { }
+ },
};
static void machvirt_machine_init(void)
diff --git a/include/hw/acpi/virt-hotplug.h b/include/hw/acpi/virt-hotplug.h
index a668d16..8f94235 100644
--- a/include/hw/acpi/virt-hotplug.h
+++ b/include/hw/acpi/virt-hotplug.h
@@ -3,6 +3,7 @@
#include "qemu/typedefs.h"
+#define VIRT_ACPI_CPU_HOTPLUG_ID_LIMIT 256
#define VIRT_CPU_HOTPLUG_MMIO_BASE 0x09600000
void virt_hotplug_init(DeviceState **virt_hotplug);
--
1.7.1
- [Qemu-devel] [RFC PATCH 0/7] hw/arm/virt: Add cpu-add way cpu hotplug support, Shannon Zhao, 2015/02/17
- [Qemu-devel] [RFC PATCH 1/7] hw/arm/virt: Add a GPIO controller, Shannon Zhao, 2015/02/17
- [Qemu-devel] [RFC PATCH 2/7] hw/arm/virt-acpi-build: Add GPIO controller in ACPI DSDT table, Shannon Zhao, 2015/02/17
- [Qemu-devel] [RFC PATCH 4/7] topology: Move topology.h to an arch-independent location, Shannon Zhao, 2015/02/17
- [Qemu-devel] [RFC PATCH 3/7] hw/acpi/virt-hotplug: Add a hotplug device for machine virt, Shannon Zhao, 2015/02/17
- [Qemu-devel] [RFC PATCH 6/7] hw/arm/virt: Add cpu hotplug support,
Shannon Zhao <=
- [Qemu-devel] [RFC PATCH 5/7] target-arm/cpu: Add apic_id property for ARMCPU, Shannon Zhao, 2015/02/17
- [Qemu-devel] [RFC PATCH 7/7] hw/arm/virt-acpi-build: Add cpu hotplug support in ACPI, Shannon Zhao, 2015/02/17
- Re: [Qemu-devel] [RFC PATCH 0/7] hw/arm/virt: Add cpu-add way cpu hotplug support, Wei Huang, 2015/02/18