qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH 4/6] acpi_piix4: Track PCI hotplug status and allow


From: Alex Williamson
Subject: [Qemu-devel] [PATCH 4/6] acpi_piix4: Track PCI hotplug status and allow non-ACPI remove path
Date: Tue, 06 Mar 2012 17:14:51 -0700
User-agent: StGIT/0.14.3

When a guest probes a device, clear the "up" bit in the hotplug
register.  This allows us to enable a non-ACPI remove path for
devices added, but never accessed by the guest.  This is useful
when a guest does not have ACPI PCI hotplug support to avoid losing
devices to a guest.  We also now individually track bits for "up"
and "down" rather than clearing both on each PCI hotplug action.

Signed-off-by: Alex Williamson <address@hidden>
---

 hw/acpi_piix4.c |   58 ++++++++++++++++++++++++++++++++++++++++++++-----------
 1 files changed, 46 insertions(+), 12 deletions(-)

diff --git a/hw/acpi_piix4.c b/hw/acpi_piix4.c
index 4d88e23..7e766e5 100644
--- a/hw/acpi_piix4.c
+++ b/hw/acpi_piix4.c
@@ -27,6 +27,7 @@
 #include "sysemu.h"
 #include "range.h"
 #include "ioport.h"
+#include "pci_host.h"
 
 //#define DEBUG
 
@@ -75,6 +76,7 @@ typedef struct PIIX4PMState {
     qemu_irq smi_irq;
     int kvm_enabled;
     Notifier machine_ready;
+    Notifier device_probe;
 
     /* for pci hotplug */
     ACPIGPE gpe;
@@ -336,6 +338,16 @@ static void piix4_pm_machine_ready(Notifier *n, void 
*opaque)
 
 }
 
+static void piix4_pm_device_probe(Notifier *n, void *opaque)
+{
+    PIIX4PMState *s = container_of(n, PIIX4PMState, device_probe);
+    PCIDevice *pdev = opaque;
+
+    if (pci_find_domain(pdev->bus) == 0 && pci_bus_num(pdev->bus) == 0) {
+        s->pci0_status.up &= ~(1U << PCI_SLOT(pdev->devfn));
+    }
+}
+
 static PIIX4PMState *global_piix4_pm_state; /* cpu hotadd */
 
 static int piix4_pm_initfn(PCIDevice *dev)
@@ -383,6 +395,8 @@ static int piix4_pm_initfn(PCIDevice *dev)
     qemu_add_machine_init_done_notifier(&s->machine_ready);
     qemu_register_reset(piix4_reset, s);
     piix4_acpi_system_hot_add_init(dev->bus, s);
+    s->device_probe.notify = piix4_pm_device_probe;
+    pci_host_add_dev_probe_notifier(&s->device_probe);
 
     return 0;
 }
@@ -502,6 +516,7 @@ static void pciej_write(void *opaque, uint32_t addr, 
uint32_t val)
         PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev);
         if (PCI_SLOT(dev->devfn) == slot && !pc->no_hotplug) {
             qdev_free(qdev);
+            s->pci0_status.down &= ~(1U << slot);
         }
     }
 
@@ -594,16 +609,41 @@ void qemu_system_cpu_hot_add(int cpu, int state)
 }
 #endif
 
-static void enable_device(PIIX4PMState *s, int slot)
+static int enable_device(PIIX4PMState *s, int slot)
 {
+    uint32_t mask = 1U << slot;
+
+    if ((s->pci0_status.up | s->pci0_status.down) & mask) {
+        return -1;
+    }
+
     s->gpe.sts[0] |= PIIX4_PCI_HOTPLUG_STATUS;
-    s->pci0_status.up |= (1 << slot);
+    s->pci0_status.up |= mask;
+
+    pm_update_sci(s);
+    return 0;
 }
 
-static void disable_device(PIIX4PMState *s, int slot)
+static int disable_device(PIIX4PMState *s, int slot)
 {
+    uint32_t mask = 1U << slot;
+
+    if (s->pci0_status.up & mask) {
+        s->pci0_status.up &= ~mask;
+        pciej_write(s, PCI_EJ_BASE, mask);
+
+        /* Clear GPE PCI hotplug status if nothing left pending */
+        if (!(s->pci0_status.up | s->pci0_status.down)) {
+            s->gpe.sts[0] &= ~PIIX4_PCI_HOTPLUG_STATUS;
+        }
+        return 0;
+    }
+
     s->gpe.sts[0] |= PIIX4_PCI_HOTPLUG_STATUS;
-    s->pci0_status.down |= (1 << slot);
+    s->pci0_status.down |= mask;
+
+    pm_update_sci(s);
+    return 0;
 }
 
 static int piix4_device_hotplug(DeviceState *qdev, PCIDevice *dev,
@@ -620,15 +660,9 @@ 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);
+        return enable_device(s, slot);
     } else {
-        disable_device(s, slot);
+        return disable_device(s, slot);
     }
-
-    pm_update_sci(s);
-
-    return 0;
 }




reply via email to

[Prev in Thread] Current Thread [Next in Thread]