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

Reply via email to