diff mbox

[3/3] q35: add & windup ich9-pci-hotplug device

Message ID 1357746097-23338-4-git-send-email-kraxel@redhat.com
State New
Headers show

Commit Message

Gerd Hoffmann Jan. 9, 2013, 3:41 p.m. UTC
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 hw/acpi_ich9.c |   89 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 hw/acpi_ich9.h |    1 +
 hw/lpc_ich9.c  |    5 ++-
 3 files changed, 94 insertions(+), 1 deletions(-)
diff mbox

Patch

diff --git a/hw/acpi_ich9.c b/hw/acpi_ich9.c
index d2f9808..5977d4b 100644
--- a/hw/acpi_ich9.c
+++ b/hw/acpi_ich9.c
@@ -33,6 +33,7 @@ 
 #include "exec/address-spaces.h"
 
 #include "ich9.h"
+#include "acpi_pci_hotplug.h"
 
 //#define DEBUG
 
@@ -202,9 +203,97 @@  static void pm_powerdown_req(Notifier *n, void *opaque)
     acpi_pm1_evt_power_down(&pm->acpi_regs);
 }
 
+/* ------------------------------------------------------------------ */
+
+#define TYPE_ICH9_PCI_HOTPLUG_DEVICE "ich9-pci-hotplug"
+#define ICH9_PCI_HOTPLUG_DEVICE(obj) \
+     OBJECT_CHECK(ICH9PCIHotplugState, (obj), TYPE_ICH9_PCI_HOTPLUG_DEVICE)
+
+#define ICH9_PCI_HOTPLUG_STATUS 2
+
+typedef struct ICH9PCIHotplugState {
+    PCIDevice parent_obj;
+
+    ICH9LPCPMRegs *pm;
+    ACPIPCI       pci;
+} ICH9PCIHotplugState;
+
+static const VMStateDescription vmstate_ich9_pci_hotplug = {
+    .name = TYPE_ICH9_PCI_HOTPLUG_DEVICE,
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_STRUCT(pci.pci0_status, ICH9PCIHotplugState, 2,
+                       vmstate_pci_status, struct pci_status),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int ich9_device_hotplug(DeviceState *qdev, PCIDevice *dev,
+                               PCIHotplugState state)
+{
+    ICH9PCIHotplugState *s = ICH9_PCI_HOTPLUG_DEVICE(qdev);
+
+    if (acpi_pci_hotplug_device(&s->pci, dev, state)) {
+        s->pm->acpi_regs.gpe.sts[0] |= ICH9_PCI_HOTPLUG_STATUS;
+        pm_update_sci(s->pm);
+    }
+
+    return 0;
+}
+
+static int ich9_pci_hotplug_initfn(PCIDevice *d)
+{
+    ICH9PCIHotplugState *s = ICH9_PCI_HOTPLUG_DEVICE(d);
+
+    acpi_pci_hotplug_init(&s->pci, &d->qdev);
+    pci_register_bar(d, 0, PCI_BASE_ADDRESS_SPACE_IO,
+                     &s->pci.io);
+    pci_bus_hotplug(d->bus, ich9_device_hotplug, &d->qdev);
+    return 0;
+}
+
+static void ich9_pci_hotplug_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->vendor_id = 0x1b36; /* Red Hat */
+    k->device_id = 0x0005;
+    k->class_id = PCI_CLASS_BRIDGE_OTHER;
+    k->revision = 1;
+    dc->no_user = 1;
+    dc->vmsd = &vmstate_ich9_pci_hotplug;
+    dc->desc = "ICH9 PCI Hotplug Device";
+    k->init = ich9_pci_hotplug_initfn;
+}
+
+static const TypeInfo ich9_pci_hotplug_info = {
+    .name   = TYPE_ICH9_PCI_HOTPLUG_DEVICE,
+    .parent = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(ICH9PCIHotplugState),
+    .class_init = ich9_pci_hotplug_class_init,
+};
+
+static void ich9_pci_hotplug_register(void)
+{
+    type_register_static(&ich9_pci_hotplug_info);
+}
+
+type_init(ich9_pci_hotplug_register);
+
+/* ------------------------------------------------------------------ */
+
 void ich9_pm_init(PCIDevice *lpc_pci, ICH9LPCPMRegs *pm,
+                  PCIDevice *hotplug_pci,
                   qemu_irq sci_irq, qemu_irq cmos_s3)
 {
+    if (hotplug_pci) {
+        ICH9PCIHotplugState *s = ICH9_PCI_HOTPLUG_DEVICE(hotplug_pci);
+        s->pm = pm;
+    }
+
     memory_region_init(&pm->io, "ich9-pm", ICH9_PMIO_SIZE);
     memory_region_set_enabled(&pm->io, false);
     memory_region_add_subregion(pci_address_space_io(lpc_pci),
diff --git a/hw/acpi_ich9.h b/hw/acpi_ich9.h
index ecb82ab..2594eab 100644
--- a/hw/acpi_ich9.h
+++ b/hw/acpi_ich9.h
@@ -45,6 +45,7 @@  typedef struct ICH9LPCPMRegs {
 } ICH9LPCPMRegs;
 
 void ich9_pm_init(PCIDevice *lpc_pci, ICH9LPCPMRegs *pm,
+                  PCIDevice *hotplug_pci,
                   qemu_irq sci_irq, qemu_irq cmos_s3_resume);
 void ich9_pm_iospace_update(ICH9LPCPMRegs *pm, uint32_t pm_io_base);
 extern const VMStateDescription vmstate_ich9_pm;
diff --git a/hw/lpc_ich9.c b/hw/lpc_ich9.c
index 16843d7..0ba0303 100644
--- a/hw/lpc_ich9.c
+++ b/hw/lpc_ich9.c
@@ -333,10 +333,13 @@  static void ich9_set_sci(void *opaque, int irq_num, int level)
 void ich9_lpc_pm_init(PCIDevice *lpc_pci, qemu_irq cmos_s3)
 {
     ICH9LPCState *lpc = ICH9_LPC_DEVICE(lpc_pci);
+    PCIDevice *hp;
     qemu_irq *sci_irq;
 
+    hp = pci_create_simple_multifunction(lpc_pci->bus, PCI_DEVFN(0x1f, 7),
+                                         true, "ich9-pci-hotplug");
     sci_irq = qemu_allocate_irqs(ich9_set_sci, lpc, 1);
-    ich9_pm_init(lpc_pci, &lpc->pm, sci_irq[0], cmos_s3);
+    ich9_pm_init(lpc_pci, &lpc->pm, hp, sci_irq[0], cmos_s3);
 
     ich9_lpc_reset(&lpc->d.qdev);
 }