Skip to contentSkip to conversation

acpi: robust notifications

PATCH In review Michael S. Tsirkin 2 participants 4 messages Mar 18, 2012 – Mar 19, 2012

lore
Share & tools
lore
#0 lore raw

cover acpi: robust notifications

acpi currently clears up/down registers on each hotplug request. This loses events if they are done quickly. It's easy to clear down on ej write.
To detect that guest was notified of device addition, we track configuration accesses since system reset.

Michael S. Tsirkin (2):
pci: track function accesses
acpi: don't clear up/down on each host change

 hw/acpi_piix4.c |   32 +++++++++++++++++++++++++++-----
 hw/pci.c        |   26 ++++++++++++++++++++++++++
 hw/pci.h        |    3 +++
 hw/pci_host.c   |    2 ++
 4 files changed, 58 insertions(+), 5 deletions(-)
Signature · 1 line
1.7.9.111.gf3fb0
#1 lore raw

PATCH 1/2 pci: track function accesses

Set a flag when function is first accessed after system reset.

---
 hw/pci.c      |   26 ++++++++++++++++++++++++++
 hw/pci.h      |    3 +++
 hw/pci_host.c |    2 ++
 3 files changed, 31 insertions(+), 0 deletions(-)
hw/pci.c +26 -0
index b706e69..2aaa45e 100644
@@ -407,6 +407,17 @@ static VMStateInfo vmstate_info_pci_irq_state = {
     .put  = put_pci_irq_state,
 };
 
+static const VMStateDescription pci_vmstate_accessed_since_reset ={
+    .name = "pci/accessed_since_reset",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField []) {
+        VMSTATE_BOOL(accessed_since_reset, PCIDevice),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
 const VMStateDescription vmstate_pci_device = {
     .name = "PCIDevice",
     .version_id = 2,
@@ -421,6 +432,12 @@ const VMStateDescription vmstate_pci_device = {
 				   vmstate_info_pci_irq_state,
 				   PCI_NUM_PINS * sizeof(int32_t)),
         VMSTATE_END_OF_LIST()
+    },
+    .subsections = (VMStateSubsection[]) {
+        {
+            .vmsd = &pci_vmstate_accessed_since_reset,
+        },
+        VMSTATE_END_OF_LIST()
     }
 };
 
@@ -738,6 +755,12 @@ static void pci_config_free(PCIDevice *pci_dev)
     g_free(pci_dev->used);
 }
 
+static void pci_system_reset_fn(void *opaque)
+{
+    PCIDevice *dev = opaque;
+    dev->accessed_since_reset = false;
+}
+
 /* -1 for devfn means auto assign */
 static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus,
                                          const char *name, int devfn)
@@ -805,11 +828,14 @@ static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus,
     bus->devices[devfn] = pci_dev;
     pci_dev->irq = qemu_allocate_irqs(pci_set_irq, pci_dev, PCI_NUM_PINS);
     pci_dev->version_id = 2; /* Current pci device vmstate version */
+    pci_dev->accessed_since_reset = false;
+    qemu_register_reset(pci_system_reset_fn, pci_dev);
     return pci_dev;
 }
 
 static void do_pci_unregister_device(PCIDevice *pci_dev)
 {
+    qemu_unregister_reset(pci_system_reset_fn, pci_dev);
     qemu_free_irqs(pci_dev->irq);
     pci_dev->bus->devices[pci_dev->devfn] = NULL;
     pci_config_free(pci_dev);
hw/pci.h +3 -0
index 8d0aa49..3fdd1dc 100644
@@ -243,6 +243,9 @@ struct PCIDevice {
     bool has_rom;
     MemoryRegion rom;
     uint32_t rom_bar;
+
+    /* Cleared on first access after system reset */
+    bool accessed_since_reset;
 };
 
 void pci_register_bar(PCIDevice *pci_dev, int region_num,
hw/pci_host.c +2 -0
index 44c6c20..3019d72 100644
@@ -51,6 +51,7 @@ void pci_host_config_write_common(PCIDevice *pci_dev, uint32_t addr,
                                   uint32_t limit, uint32_t val, uint32_t len)
 {
     assert(len <= 4);
+    pci_dev->accessed_since_reset = true;
     pci_dev->config_write(pci_dev, addr, val, MIN(len, limit - addr));
 }
 
@@ -58,6 +59,7 @@ uint32_t pci_host_config_read_common(PCIDevice *pci_dev, uint32_t addr,
                                      uint32_t limit, uint32_t len)
 {
     assert(len <= 4);
+    pci_dev->accessed_since_reset = true;
     return pci_dev->config_read(pci_dev, addr, MIN(len, limit - addr));
 }
 
Signature · 1 line
1.7.9.111.gf3fb0
#2 lore raw

PATCH 2/2 acpi: don't clear up/down on each host change

In reply to Michael S. Tsirkin

Instead of clearing up slot on each change, we clear:
- up: when slot is accessed
- down: when device is ejected

---
 hw/acpi_piix4.c |   32 +++++++++++++++++++++++++++-----
 1 files changed, 27 insertions(+), 5 deletions(-)
hw/acpi_piix4.c +27 -5
index 797ed24..b6bb486 100644
@@ -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 {
Signature · 1 line
1.7.9.111.gf3fb0
#3 lore raw
In reply to Michael S. Tsirkin
Quoted 6 lines · Michael S. Tsirkin

acpi currently clears up/down registers on each hotplug request. This loses events if they are done quickly. It's easy to clear down on ej write.
To detect that guest was notified of device addition, we track configuration accesses since system reset.

This is hack. This is not how real HW works, why do we needed it? If up/down thing is so broken that this is required lets move to how cpu hot-plug works and maintain slot status bit map instead. BTW we discussed that with Alex last week. Have you followed that thread.

Quoted 4 lines

Michael S. Tsirkin (2):
pci: track function accesses
acpi: don't clear up/down on each host change

Quoted 8 lines
 hw/acpi_piix4.c |   32 +++++++++++++++++++++++++++-----
 hw/pci.c        |   26 ++++++++++++++++++++++++++
 hw/pci.h        |    3 +++
 hw/pci_host.c   |    2 ++
 4 files changed, 58 insertions(+), 5 deletions(-)
Signature · 1 line
1.7.9.111.gf3fb0

--
Gleb.