@@ -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),
@@ -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;
@@ -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);
}
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(-)