pcihp: make pci_read() mmio calback compatible with legacy ACPI hotplug
authorIgor Mammedov <imammedo@redhat.com>
Mon, 3 Feb 2014 10:44:59 +0000 (11:44 +0100)
committerMichael S. Tsirkin <mst@redhat.com>
Wed, 5 Feb 2014 14:55:49 +0000 (16:55 +0200)
due to recent change introduced by:
"pcihp: reduce number of device check events"

'up' field is cleared right after it's read.
This is incompatible with legacy BIOS ACPI code
where PCNF ACPI method reads this field 32 times.

To make pci_read mmio callback compatible with legacy
'up' behavior, pcihp code will need to know in which
mode it runs add 'legacy_piix' field to AcpiPciHpState
structure and alter register behavior accordingly.

Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
hw/acpi/pcihp.c
hw/acpi/piix4.c
include/hw/acpi/pcihp.h

index 64c8cf28f1a34c268ae9a00e177626ee447890a7..974f01c114593c849f40c2ae54a36a3fd7d45624 100644 (file)
@@ -215,7 +215,9 @@ static uint64_t pci_read(void *opaque, hwaddr addr, unsigned int size)
     switch (addr) {
     case PCI_UP_BASE:
         val = s->acpi_pcihp_pci_status[bsel].up;
-        s->acpi_pcihp_pci_status[bsel].up = 0;
+        if (!s->legacy_piix) {
+            s->acpi_pcihp_pci_status[bsel].up = 0;
+        }
         ACPI_PCIHP_DPRINTF("pci_up_read %" PRIu32 "\n", val);
         break;
     case PCI_DOWN_BASE:
@@ -273,9 +275,10 @@ static const MemoryRegionOps acpi_pcihp_io_ops = {
 };
 
 void acpi_pcihp_init(AcpiPciHpState *s, PCIBus *root_bus,
-                     MemoryRegion *address_space_io)
+                     MemoryRegion *address_space_io, bool bridges_enabled)
 {
     s->root= root_bus;
+    s->legacy_piix = !bridges_enabled;
     memory_region_init_io(&s->io, NULL, &acpi_pcihp_io_ops, s,
                           "acpi-pci-hotplug",
                           PCI_HOTPLUG_SIZE);
index 5d55a3c222013d514e5f7ab58311c0174733dda3..2aedfe5998d9bb3877c0cbb3bfe4f5aa2779659c 100644 (file)
@@ -695,7 +695,8 @@ static void piix4_acpi_system_hot_add_init(MemoryRegion *parent,
     memory_region_add_subregion(parent, GPE_BASE, &s->io_gpe);
 
     if (s->use_acpi_pci_hotplug) {
-        acpi_pcihp_init(&s->acpi_pci_hotplug, bus, parent);
+        acpi_pcihp_init(&s->acpi_pci_hotplug, bus, parent,
+                        s->use_acpi_pci_hotplug);
     } else {
         memory_region_init_io(&s->io_pci, OBJECT(s), &piix4_pci_ops, s,
                               "acpi-pci-hotplug", PCI_HOTPLUG_SIZE);
index aa297c2450ec651843d00d00ffd47832b5573111..02d3ce33a144e98f9c97bb2f58c3ccccc94f37a6 100644 (file)
@@ -46,10 +46,11 @@ typedef struct AcpiPciHpState {
     uint32_t hotplug_select;
     PCIBus *root;
     MemoryRegion io;
+    bool legacy_piix;
 } AcpiPciHpState;
 
 void acpi_pcihp_init(AcpiPciHpState *, PCIBus *root,
-                     MemoryRegion *address_space_io);
+                     MemoryRegion *address_space_io, bool bridges_enabled);
 
 /* Invoke on device hotplug */
 int acpi_pcihp_device_hotplug(AcpiPciHpState *, PCIDevice *,