@@ -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
@@ -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
@@ -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;
@@ -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 &&
@@ -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)
{
new file mode 100644
@@ -0,0 +1,130 @@
+/*
+ *
+ * Copyright (c) 2015 HUAWEI TECHNOLOGIES CO.,LTD.
+ *
+ * Author: Shannon Zhao <zhaoshenglong@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)
@@ -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
new file mode 100644
@@ -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
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 <zhaoshenglong@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