Instead of clearing up slot on each change, we clear: - up: when slot is accessed - down: when device is ejected
Signed-off-by: Michael S. Tsirkin <m...@redhat.com> --- hw/acpi_piix4.c | 32 +++++++++++++++++++++++++++----- 1 files changed, 27 insertions(+), 5 deletions(-) diff --git a/hw/acpi_piix4.c b/hw/acpi_piix4.c index 797ed24..b6bb486 100644 --- a/hw/acpi_piix4.c +++ b/hw/acpi_piix4.c @@ -49,6 +49,7 @@ struct pci_status { uint32_t up; uint32_t down; + BusState *bus; }; typedef struct PIIX4PMState { @@ -268,6 +269,21 @@ static const VMStateDescription vmstate_acpi = { } }; +/* Did guest access any devices in a slot? If yes, clear the up bit. */ +static void piix4_update_up(struct pci_status *s) +{ + DeviceState *qdev, *next; + int slot; + + QTAILQ_FOREACH_SAFE(qdev, &s->bus->children, sibling, next) { + PCIDevice *pdev = PCI_DEVICE(qdev); + slot = PCI_SLOT(pdev->devfn); + if (pdev->accessed_since_reset) { + s->up &= ~(1 << slot); + } + } +} + static void piix4_update_hotplug(PIIX4PMState *s) { PCIDevice *dev = &s->dev; @@ -290,6 +306,7 @@ static void piix4_update_hotplug(PIIX4PMState *s) static void piix4_reset(void *opaque) { PIIX4PMState *s = opaque; + struct pci_status *pci0_status = &s->pci0_status; uint8_t *pci_conf = s->dev.config; pci_conf[0x58] = 0; @@ -301,6 +318,8 @@ static void piix4_reset(void *opaque) /* Mark SMM as already inited (until KVM supports SMM). */ pci_conf[0x5B] = 0x02; } + pci0_status->up = 0; + pci0_status->down = 0; piix4_update_hotplug(s); } @@ -454,6 +473,7 @@ static uint32_t pcihotplug_read(void *opaque, uint32_t addr) struct pci_status *g = opaque; switch (addr) { case PCI_BASE: + piix4_update_up(g); val = g->up; break; case PCI_BASE + 4: @@ -490,10 +510,13 @@ static uint32_t pciej_read(void *opaque, uint32_t addr) static void pciej_write(void *opaque, uint32_t addr, uint32_t val) { - BusState *bus = opaque; + struct pci_status *s = opaque; + BusState *bus = s->bus; DeviceState *qdev, *next; int slot = ffs(val) - 1; + s->down &= ~(1 << slot); + s->up &= ~(1 << slot); QTAILQ_FOREACH_SAFE(qdev, &bus->children, sibling, next) { PCIDevice *dev = PCI_DEVICE(qdev); PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev); @@ -524,6 +547,7 @@ static int piix4_device_hotplug(DeviceState *qdev, PCIDevice *dev, static void piix4_acpi_system_hot_add_init(PCIBus *bus, PIIX4PMState *s) { struct pci_status *pci0_status = &s->pci0_status; + pci0_status->bus = qdev_get_parent_bus(&s->dev.qdev); register_ioport_write(GPE_BASE, GPE_LEN, 1, gpe_writeb, s); register_ioport_read(GPE_BASE, GPE_LEN, 1, gpe_readb, s); @@ -532,8 +556,8 @@ static void piix4_acpi_system_hot_add_init(PCIBus *bus, PIIX4PMState *s) register_ioport_write(PCI_BASE, 8, 4, pcihotplug_write, pci0_status); register_ioport_read(PCI_BASE, 8, 4, pcihotplug_read, pci0_status); - register_ioport_write(PCI_EJ_BASE, 4, 4, pciej_write, bus); - register_ioport_read(PCI_EJ_BASE, 4, 4, pciej_read, bus); + register_ioport_write(PCI_EJ_BASE, 4, 4, pciej_write, pci0_status); + register_ioport_read(PCI_EJ_BASE, 4, 4, pciej_read, pci0_status); register_ioport_write(PCI_RMV_BASE, 4, 4, pcirmv_write, s); register_ioport_read(PCI_RMV_BASE, 4, 4, pcirmv_read, s); @@ -567,8 +591,6 @@ static int piix4_device_hotplug(DeviceState *qdev, PCIDevice *dev, return 0; } - s->pci0_status.up = 0; - s->pci0_status.down = 0; if (state == PCI_HOTPLUG_ENABLED) { enable_device(s, slot); } else { -- 1.7.9.111.gf3fb0