Add a hotplug device for machine virt. This can be used for virt to support device hotplug. At the moment this hotplug device just include a mmio region which shows the present status of cpus.
Signed-off-by: Shannon Zhao <zhaoshengl...@huawei.com> --- default-configs/arm-softmmu.mak | 2 + hw/acpi/Makefile.objs | 1 + hw/acpi/cpu_hotplug.c | 16 +---- hw/acpi/ich9.c | 12 ++++ hw/acpi/piix4.c | 12 ++++ hw/acpi/virt-hotplug.c | 130 +++++++++++++++++++++++++++++++++++++++ include/hw/acpi/cpu_hotplug.h | 6 +- include/hw/acpi/virt-hotplug.h | 10 +++ 8 files changed, 172 insertions(+), 17 deletions(-) create mode 100644 hw/acpi/virt-hotplug.c create mode 100644 include/hw/acpi/virt-hotplug.h diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak index 3c89f53..bb74707 100644 --- a/default-configs/arm-softmmu.mak +++ b/default-configs/arm-softmmu.mak @@ -89,3 +89,5 @@ CONFIG_ALLWINNER_A10_PIT=y CONFIG_ALLWINNER_A10_PIC=y CONFIG_ALLWINNER_A10=y CONFIG_ACPI=y +CONFIG_VIRT_HOTPLUG=y +CONFIG_ACPI_CPU_HOTPLUG=y diff --git a/hw/acpi/Makefile.objs b/hw/acpi/Makefile.objs index 511771a..4bc5a4d 100644 --- a/hw/acpi/Makefile.objs +++ b/hw/acpi/Makefile.objs @@ -4,3 +4,4 @@ common-obj-$(CONFIG_ACPI_MEMORY_HOTPLUG) += memory_hotplug.o common-obj-$(CONFIG_ACPI) += acpi_interface.o common-obj-$(CONFIG_ACPI) += bios-linker-loader.o common-obj-$(CONFIG_ACPI) += aml-build.o +common-obj-$(CONFIG_VIRT_HOTPLUG) += virt-hotplug.o diff --git a/hw/acpi/cpu_hotplug.c b/hw/acpi/cpu_hotplug.c index b8ebfad..dbc7e94 100644 --- a/hw/acpi/cpu_hotplug.c +++ b/hw/acpi/cpu_hotplug.c @@ -36,7 +36,7 @@ static const MemoryRegionOps AcpiCpuHotplug_ops = { }, }; -static void acpi_set_cpu_present_bit(AcpiCpuHotplug *g, CPUState *cpu, +void acpi_set_cpu_present_bit(AcpiCpuHotplug *g, CPUState *cpu, Error **errp) { CPUClass *k = CPU_GET_CLASS(cpu); @@ -51,20 +51,8 @@ static void acpi_set_cpu_present_bit(AcpiCpuHotplug *g, CPUState *cpu, g->sts[cpu_id / 8] |= (1 << (cpu_id % 8)); } -void acpi_cpu_plug_cb(ACPIREGS *ar, qemu_irq irq, - AcpiCpuHotplug *g, DeviceState *dev, Error **errp) -{ - acpi_set_cpu_present_bit(g, CPU(dev), errp); - if (*errp != NULL) { - return; - } - - ar->gpe.sts[0] |= ACPI_CPU_HOTPLUG_STATUS; - acpi_update_sci(ar, irq); -} - void acpi_cpu_hotplug_init(MemoryRegion *parent, Object *owner, - AcpiCpuHotplug *gpe_cpu, uint16_t base) + AcpiCpuHotplug *gpe_cpu, uint64_t base) { CPUState *cpu; diff --git a/hw/acpi/ich9.c b/hw/acpi/ich9.c index 5352e19..6c4422a 100644 --- a/hw/acpi/ich9.c +++ b/hw/acpi/ich9.c @@ -383,6 +383,18 @@ void ich9_pm_add_properties(Object *obj, ICH9LPCPMRegs *pm, Error **errp) NULL, pm, NULL); } +static void acpi_cpu_plug_cb(ACPIREGS *ar, qemu_irq irq, + AcpiCpuHotplug *g, DeviceState *dev, Error **errp) +{ + acpi_set_cpu_present_bit(g, CPU(dev), errp); + if (*errp != NULL) { + return; + } + + ar->gpe.sts[0] |= ACPI_CPU_HOTPLUG_STATUS; + acpi_update_sci(ar, irq); +} + void ich9_pm_device_plug_cb(ICH9LPCPMRegs *pm, DeviceState *dev, Error **errp) { if (pm->acpi_memory_hotplug.is_enabled && diff --git a/hw/acpi/piix4.c b/hw/acpi/piix4.c index d1f1179..6faca8a 100644 --- a/hw/acpi/piix4.c +++ b/hw/acpi/piix4.c @@ -337,6 +337,18 @@ static void piix4_pm_powerdown_req(Notifier *n, void *opaque) acpi_pm1_evt_power_down(&s->ar); } +static void acpi_cpu_plug_cb(ACPIREGS *ar, qemu_irq irq, + AcpiCpuHotplug *g, DeviceState *dev, Error **errp) +{ + acpi_set_cpu_present_bit(g, CPU(dev), errp); + if (*errp != NULL) { + return; + } + + ar->gpe.sts[0] |= ACPI_CPU_HOTPLUG_STATUS; + acpi_update_sci(ar, irq); +} + static void piix4_device_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp) { diff --git a/hw/acpi/virt-hotplug.c b/hw/acpi/virt-hotplug.c new file mode 100644 index 0000000..47da078 --- /dev/null +++ b/hw/acpi/virt-hotplug.c @@ -0,0 +1,130 @@ +/* + * + * Copyright (c) 2015 HUAWEI TECHNOLOGIES CO.,LTD. + * + * Author: Shannon Zhao <zhaoshengl...@huawei.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2 or later, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "hw/hw.h" +#include "hw/acpi/acpi.h" +#include "sysemu/sysemu.h" +#include "qemu/range.h" +#include "exec/address-spaces.h" +#include "hw/acpi/cpu_hotplug.h" +#include "hw/hotplug.h" +#include "hw/acpi/acpi_dev_interface.h" +#include "hw/sysbus.h" +#include "hw/acpi/virt-hotplug.h" + +/* #define DEBUG */ + +#ifdef DEBUG +# define VIRT_HOTPLUG_DPRINTF(format, ...) printf(format, ## __VA_ARGS__) +#else +# define VIRT_HOTPLUG_DPRINTF(format, ...) do { } while (0) +#endif + +typedef struct VIRTHOTPLUGState { + /*< private >*/ + SysBusDevice parent_obj; + /*< public >*/ + AcpiCpuHotplug gpe_cpu; +} VIRTHOTPLUGState; + +#define TYPE_VIRT_HOTPLUG "VIRT_HOTPLUG" + +#define VIRT_HOTPLUG(obj) \ + OBJECT_CHECK(VIRTHOTPLUGState, (obj), TYPE_VIRT_HOTPLUG) + +static void virt_acpi_cpu_plug_cb(AcpiCpuHotplug *g, + DeviceState *dev, Error **errp) +{ + acpi_set_cpu_present_bit(g, CPU(dev), errp); + if (*errp != NULL) { + return; + } + + bool ambig; + Object *o = object_resolve_path_type("", "pl061", &ambig); + /* use gpio 2 for cpu plug event */ + qemu_set_irq(qdev_get_gpio_in(DEVICE(o), 2), 1); +} + +static void virt_device_plug_cb(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) +{ + VIRTHOTPLUGState *s = VIRT_HOTPLUG(hotplug_dev); + + if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { + virt_acpi_cpu_plug_cb(&s->gpe_cpu, dev, errp); + } else { + error_setg(errp, "acpi: device plug request for not supported device" + " type: %s", object_get_typename(OBJECT(dev))); + } +} + +static int virt_hotplug_initfn(SysBusDevice *sbd) +{ + DeviceState *dev = DEVICE(sbd); + VIRTHOTPLUGState *s = VIRT_HOTPLUG(dev); + + acpi_cpu_hotplug_init(get_system_memory(), OBJECT(s), + &s->gpe_cpu, VIRT_CPU_HOTPLUG_MMIO_BASE); + return 0; +} + +void virt_hotplug_init(DeviceState **virt_hotplug) +{ + DeviceState *dev; + + dev = qdev_create(NULL, TYPE_VIRT_HOTPLUG); + if (virt_hotplug) { + *virt_hotplug = dev; + } + qdev_init_nofail(dev); +} + +static void virt_hotplug_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass); + + k->init = virt_hotplug_initfn; + + dc->desc = "VIRT_HOTPLUG"; + dc->cannot_instantiate_with_device_add_yet = true; + dc->hotpluggable = false; + hc->plug = virt_device_plug_cb; +} + +static const TypeInfo virt_hotplug_info = { + .name = TYPE_VIRT_HOTPLUG, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(VIRTHOTPLUGState), + .class_init = virt_hotplug_class_init, + .interfaces = (InterfaceInfo[]) { + { TYPE_HOTPLUG_HANDLER }, + { TYPE_ACPI_DEVICE_IF }, + { } + } +}; + +static void virt_hotplug_register_types(void) +{ + type_register_static(&virt_hotplug_info); +} + +type_init(virt_hotplug_register_types) diff --git a/include/hw/acpi/cpu_hotplug.h b/include/hw/acpi/cpu_hotplug.h index f6d358d..5cb43f4 100644 --- a/include/hw/acpi/cpu_hotplug.h +++ b/include/hw/acpi/cpu_hotplug.h @@ -20,9 +20,9 @@ typedef struct AcpiCpuHotplug { uint8_t sts[ACPI_GPE_PROC_LEN]; } AcpiCpuHotplug; -void acpi_cpu_plug_cb(ACPIREGS *ar, qemu_irq irq, - AcpiCpuHotplug *g, DeviceState *dev, Error **errp); +void acpi_set_cpu_present_bit(AcpiCpuHotplug *g, CPUState *cpu, + Error **errp); void acpi_cpu_hotplug_init(MemoryRegion *parent, Object *owner, - AcpiCpuHotplug *gpe_cpu, uint16_t base); + AcpiCpuHotplug *gpe_cpu, uint64_t base); #endif diff --git a/include/hw/acpi/virt-hotplug.h b/include/hw/acpi/virt-hotplug.h new file mode 100644 index 0000000..a668d16 --- /dev/null +++ b/include/hw/acpi/virt-hotplug.h @@ -0,0 +1,10 @@ +#ifndef HW_ACPI_VIRT_HOTPLUG_H +#define HW_ACPI_VIRT_HOTPLUG_H + +#include "qemu/typedefs.h" + +#define VIRT_CPU_HOTPLUG_MMIO_BASE 0x09600000 + +void virt_hotplug_init(DeviceState **virt_hotplug); + +#endif -- 1.7.1