Signed-off-by: Gerd Hoffmann <kra...@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 --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); } -- 1.7.1