diff mbox

[PULL,19/29] piix4: add acpi pci hotplug support

Message ID 1390226872-781-20-git-send-email-mst@redhat.com
State New
Headers show

Commit Message

Michael S. Tsirkin Jan. 20, 2014, 2:10 p.m. UTC
Add support for acpi pci hotplug using the
new infrastructure.
PIIX4 legacy interface is maintained as is for
machine types 1.6 and older.

Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
---
 include/hw/i386/pc.h |  5 ++++
 hw/acpi/piix4.c      | 75 +++++++++++++++++++++++++++++++++++++++++++++-------
 2 files changed, 70 insertions(+), 10 deletions(-)

Comments

Michael S. Tsirkin Jan. 20, 2014, 4:16 p.m. UTC | #1
On Mon, Jan 20, 2014 at 04:10:25PM +0200, Michael S. Tsirkin wrote:
> Add support for acpi pci hotplug using the
> new infrastructure.
> PIIX4 legacy interface is maintained as is for
> machine types 1.6 and older.

Actually that's wrong of course, should be off for 1.7
and older.
I'll send v2.

> 
> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
> ---
>  include/hw/i386/pc.h |  5 ++++
>  hw/acpi/piix4.c      | 75 +++++++++++++++++++++++++++++++++++++++++++++-------
>  2 files changed, 70 insertions(+), 10 deletions(-)
> 
> diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
> index eb3da96..71653e8 100644
> --- a/include/hw/i386/pc.h
> +++ b/include/hw/i386/pc.h
> @@ -261,6 +261,11 @@ int e820_add_entry(uint64_t, uint64_t, uint32_t);
>  
>  #define PC_COMPAT_1_6 \
>          {\
> +            .driver   = "PIIX4_PM",\
> +            .property = "acpi-pci-hotplug-with-bridge-support",\
> +            .value    = "off",\
> +        }, \
> +        {\
>              .driver   = "e1000",\
>              .property = "mitigation",\
>              .value    = "off",\
> diff --git a/hw/acpi/piix4.c b/hw/acpi/piix4.c
> index 20353b9..1aa35bc 100644
> --- a/hw/acpi/piix4.c
> +++ b/hw/acpi/piix4.c
> @@ -30,6 +30,7 @@
>  #include "hw/nvram/fw_cfg.h"
>  #include "exec/address-spaces.h"
>  #include "hw/acpi/piix4.h"
> +#include "hw/acpi/pcihp.h"
>  
>  //#define DEBUG
>  
> @@ -73,7 +74,6 @@ typedef struct PIIX4PMState {
>      uint32_t io_base;
>  
>      MemoryRegion io_gpe;
> -    MemoryRegion io_pci;
>      MemoryRegion io_cpu;
>      ACPIREGS ar;
>  
> @@ -88,11 +88,16 @@ typedef struct PIIX4PMState {
>      Notifier machine_ready;
>      Notifier powerdown_notifier;
>  
> -    /* for pci hotplug */
> +    /* for legacy pci hotplug (compatible with qemu 1.6 and older) */
> +    MemoryRegion io_pci;
>      struct pci_status pci0_status;
>      uint32_t pci0_hotplug_enable;
>      uint32_t pci0_slot_device_present;
>  
> +    /* for new pci hotplug (with PCI2PCI bridge support) */
> +    AcpiPciHpState acpi_pci_hotplug;
> +    bool use_acpi_pci_hotplug;
> +
>      uint8_t disable_s3;
>      uint8_t disable_s4;
>      uint8_t s4_val;
> @@ -263,6 +268,18 @@ static int acpi_load_old(QEMUFile *f, void *opaque, int version_id)
>      return ret;
>  }
>  
> +static bool vmstate_test_use_acpi_pci_hotplug(void *opaque, int version_id)
> +{
> +    PIIX4PMState *s = opaque;
> +    return s->use_acpi_pci_hotplug;
> +}
> +
> +static bool vmstate_test_no_use_acpi_pci_hotplug(void *opaque, int version_id)
> +{
> +    PIIX4PMState *s = opaque;
> +    return !s->use_acpi_pci_hotplug;
> +}
> +
>  /* qemu-kvm 1.2 uses version 3 but advertised as 2
>   * To support incoming qemu-kvm 1.2 migration, change version_id
>   * and minimum_version_id to 2 below (which breaks migration from
> @@ -285,8 +302,12 @@ static const VMStateDescription vmstate_acpi = {
>          VMSTATE_TIMER(ar.tmr.timer, PIIX4PMState),
>          VMSTATE_INT64(ar.tmr.overflow_time, PIIX4PMState),
>          VMSTATE_STRUCT(ar.gpe, PIIX4PMState, 2, vmstate_gpe, ACPIGPE),
> -        VMSTATE_STRUCT(pci0_status, PIIX4PMState, 2, vmstate_pci_status,
> -                       struct pci_status),
> +        VMSTATE_STRUCT_TEST(pci0_status, PIIX4PMState,
> +                            vmstate_test_no_use_acpi_pci_hotplug,
> +                            2, vmstate_pci_status,
> +                            struct pci_status),
> +        VMSTATE_PCI_HOTPLUG(acpi_pci_hotplug, PIIX4PMState,
> +                            vmstate_test_use_acpi_pci_hotplug),
>          VMSTATE_END_OF_LIST()
>      }
>  };
> @@ -364,7 +385,11 @@ static void piix4_reset(void *opaque)
>          pci_conf[0x5B] = 0x02;
>      }
>      pm_io_space_update(s);
> -    piix4_update_hotplug(s);
> +    if (s->use_acpi_pci_hotplug) {
> +        acpi_pcihp_reset(&s->acpi_pci_hotplug);
> +    } else {
> +        piix4_update_hotplug(s);
> +    }
>  }
>  
>  static void piix4_pm_powerdown_req(Notifier *n, void *opaque)
> @@ -375,6 +400,26 @@ static void piix4_pm_powerdown_req(Notifier *n, void *opaque)
>      acpi_pm1_evt_power_down(&s->ar);
>  }
>  
> +static int piix4_acpi_pci_hotplug(DeviceState *qdev, PCIDevice *dev,
> +                                  PCIHotplugState state)
> +{
> +    PIIX4PMState *s = PIIX4_PM(qdev);
> +    int ret = acpi_pcihp_device_hotplug(&s->acpi_pci_hotplug, dev, state);
> +    if (ret < 0) {
> +        return ret;
> +    }
> +    s->ar.gpe.sts[0] |= PIIX4_PCI_HOTPLUG_STATUS;
> +
> +    acpi_update_sci(&s->ar, s->irq);
> +    return 0;
> +}
> +
> +static void piix4_update_bus_hotplug(PCIBus *bus, void *opaque)
> +{
> +    PIIX4PMState *s = opaque;
> +    pci_bus_hotplug(bus, piix4_acpi_pci_hotplug, DEVICE(s));
> +}
> +
>  static void piix4_pm_machine_ready(Notifier *n, void *opaque)
>  {
>      PIIX4PMState *s = container_of(n, PIIX4PMState, machine_ready);
> @@ -388,6 +433,10 @@ static void piix4_pm_machine_ready(Notifier *n, void *opaque)
>      pci_conf[0x63] = 0x60;
>      pci_conf[0x67] = (memory_region_present(io_as, 0x3f8) ? 0x08 : 0) |
>          (memory_region_present(io_as, 0x2f8) ? 0x90 : 0);
> +
> +    if (s->use_acpi_pci_hotplug) {
> +        pci_for_each_bus(d->bus, piix4_update_bus_hotplug, s);
> +    }
>  }
>  
>  static void piix4_pm_add_propeties(PIIX4PMState *s)
> @@ -509,6 +558,8 @@ static Property piix4_pm_properties[] = {
>      DEFINE_PROP_UINT8(ACPI_PM_PROP_S3_DISABLED, PIIX4PMState, disable_s3, 0),
>      DEFINE_PROP_UINT8(ACPI_PM_PROP_S4_DISABLED, PIIX4PMState, disable_s4, 0),
>      DEFINE_PROP_UINT8(ACPI_PM_PROP_S4_VAL, PIIX4PMState, s4_val, 2),
> +    DEFINE_PROP_BOOL("acpi-pci-hotplug-with-bridge-support", PIIX4PMState,
> +                     use_acpi_pci_hotplug, true),
>      DEFINE_PROP_END_OF_LIST(),
>  };
>  
> @@ -701,11 +752,15 @@ static void piix4_acpi_system_hot_add_init(MemoryRegion *parent,
>                            "acpi-gpe0", GPE_LEN);
>      memory_region_add_subregion(parent, GPE_BASE, &s->io_gpe);
>  
> -    memory_region_init_io(&s->io_pci, OBJECT(s), &piix4_pci_ops, s,
> -                          "acpi-pci-hotplug", PCI_HOTPLUG_SIZE);
> -    memory_region_add_subregion(parent, PCI_HOTPLUG_ADDR,
> -                                &s->io_pci);
> -    pci_bus_hotplug(bus, piix4_device_hotplug, DEVICE(s));
> +    if (s->use_acpi_pci_hotplug) {
> +        acpi_pcihp_init(&s->acpi_pci_hotplug, bus, parent);
> +    } else {
> +        memory_region_init_io(&s->io_pci, OBJECT(s), &piix4_pci_ops, s,
> +                              "acpi-pci-hotplug", PCI_HOTPLUG_SIZE);
> +        memory_region_add_subregion(parent, PCI_HOTPLUG_ADDR,
> +                                    &s->io_pci);
> +        pci_bus_hotplug(bus, piix4_device_hotplug, DEVICE(s));
> +    }
>  
>      CPU_FOREACH(cpu) {
>          CPUClass *cc = CPU_GET_CLASS(cpu);
> -- 
> MST
>
Michael S. Tsirkin Jan. 20, 2014, 4:31 p.m. UTC | #2
On Mon, Jan 20, 2014 at 06:16:59PM +0200, Michael S. Tsirkin wrote:
> On Mon, Jan 20, 2014 at 04:10:25PM +0200, Michael S. Tsirkin wrote:
> > Add support for acpi pci hotplug using the
> > new infrastructure.
> > PIIX4 legacy interface is maintained as is for
> > machine types 1.6 and older.
> 
> Actually that's wrong of course, should be off for 1.7
> and older.
> I'll send v2.

Actually seems like it's too painful to do now that
everything has been pushed to a public branch.
:(
I'll just apply a fix on top.

> > 
> > Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
> > ---
> >  include/hw/i386/pc.h |  5 ++++
> >  hw/acpi/piix4.c      | 75 +++++++++++++++++++++++++++++++++++++++++++++-------
> >  2 files changed, 70 insertions(+), 10 deletions(-)
> > 
> > diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
> > index eb3da96..71653e8 100644
> > --- a/include/hw/i386/pc.h
> > +++ b/include/hw/i386/pc.h
> > @@ -261,6 +261,11 @@ int e820_add_entry(uint64_t, uint64_t, uint32_t);
> >  
> >  #define PC_COMPAT_1_6 \
> >          {\
> > +            .driver   = "PIIX4_PM",\
> > +            .property = "acpi-pci-hotplug-with-bridge-support",\
> > +            .value    = "off",\
> > +        }, \
> > +        {\
> >              .driver   = "e1000",\
> >              .property = "mitigation",\
> >              .value    = "off",\
> > diff --git a/hw/acpi/piix4.c b/hw/acpi/piix4.c
> > index 20353b9..1aa35bc 100644
> > --- a/hw/acpi/piix4.c
> > +++ b/hw/acpi/piix4.c
> > @@ -30,6 +30,7 @@
> >  #include "hw/nvram/fw_cfg.h"
> >  #include "exec/address-spaces.h"
> >  #include "hw/acpi/piix4.h"
> > +#include "hw/acpi/pcihp.h"
> >  
> >  //#define DEBUG
> >  
> > @@ -73,7 +74,6 @@ typedef struct PIIX4PMState {
> >      uint32_t io_base;
> >  
> >      MemoryRegion io_gpe;
> > -    MemoryRegion io_pci;
> >      MemoryRegion io_cpu;
> >      ACPIREGS ar;
> >  
> > @@ -88,11 +88,16 @@ typedef struct PIIX4PMState {
> >      Notifier machine_ready;
> >      Notifier powerdown_notifier;
> >  
> > -    /* for pci hotplug */
> > +    /* for legacy pci hotplug (compatible with qemu 1.6 and older) */
> > +    MemoryRegion io_pci;
> >      struct pci_status pci0_status;
> >      uint32_t pci0_hotplug_enable;
> >      uint32_t pci0_slot_device_present;
> >  
> > +    /* for new pci hotplug (with PCI2PCI bridge support) */
> > +    AcpiPciHpState acpi_pci_hotplug;
> > +    bool use_acpi_pci_hotplug;
> > +
> >      uint8_t disable_s3;
> >      uint8_t disable_s4;
> >      uint8_t s4_val;
> > @@ -263,6 +268,18 @@ static int acpi_load_old(QEMUFile *f, void *opaque, int version_id)
> >      return ret;
> >  }
> >  
> > +static bool vmstate_test_use_acpi_pci_hotplug(void *opaque, int version_id)
> > +{
> > +    PIIX4PMState *s = opaque;
> > +    return s->use_acpi_pci_hotplug;
> > +}
> > +
> > +static bool vmstate_test_no_use_acpi_pci_hotplug(void *opaque, int version_id)
> > +{
> > +    PIIX4PMState *s = opaque;
> > +    return !s->use_acpi_pci_hotplug;
> > +}
> > +
> >  /* qemu-kvm 1.2 uses version 3 but advertised as 2
> >   * To support incoming qemu-kvm 1.2 migration, change version_id
> >   * and minimum_version_id to 2 below (which breaks migration from
> > @@ -285,8 +302,12 @@ static const VMStateDescription vmstate_acpi = {
> >          VMSTATE_TIMER(ar.tmr.timer, PIIX4PMState),
> >          VMSTATE_INT64(ar.tmr.overflow_time, PIIX4PMState),
> >          VMSTATE_STRUCT(ar.gpe, PIIX4PMState, 2, vmstate_gpe, ACPIGPE),
> > -        VMSTATE_STRUCT(pci0_status, PIIX4PMState, 2, vmstate_pci_status,
> > -                       struct pci_status),
> > +        VMSTATE_STRUCT_TEST(pci0_status, PIIX4PMState,
> > +                            vmstate_test_no_use_acpi_pci_hotplug,
> > +                            2, vmstate_pci_status,
> > +                            struct pci_status),
> > +        VMSTATE_PCI_HOTPLUG(acpi_pci_hotplug, PIIX4PMState,
> > +                            vmstate_test_use_acpi_pci_hotplug),
> >          VMSTATE_END_OF_LIST()
> >      }
> >  };
> > @@ -364,7 +385,11 @@ static void piix4_reset(void *opaque)
> >          pci_conf[0x5B] = 0x02;
> >      }
> >      pm_io_space_update(s);
> > -    piix4_update_hotplug(s);
> > +    if (s->use_acpi_pci_hotplug) {
> > +        acpi_pcihp_reset(&s->acpi_pci_hotplug);
> > +    } else {
> > +        piix4_update_hotplug(s);
> > +    }
> >  }
> >  
> >  static void piix4_pm_powerdown_req(Notifier *n, void *opaque)
> > @@ -375,6 +400,26 @@ static void piix4_pm_powerdown_req(Notifier *n, void *opaque)
> >      acpi_pm1_evt_power_down(&s->ar);
> >  }
> >  
> > +static int piix4_acpi_pci_hotplug(DeviceState *qdev, PCIDevice *dev,
> > +                                  PCIHotplugState state)
> > +{
> > +    PIIX4PMState *s = PIIX4_PM(qdev);
> > +    int ret = acpi_pcihp_device_hotplug(&s->acpi_pci_hotplug, dev, state);
> > +    if (ret < 0) {
> > +        return ret;
> > +    }
> > +    s->ar.gpe.sts[0] |= PIIX4_PCI_HOTPLUG_STATUS;
> > +
> > +    acpi_update_sci(&s->ar, s->irq);
> > +    return 0;
> > +}
> > +
> > +static void piix4_update_bus_hotplug(PCIBus *bus, void *opaque)
> > +{
> > +    PIIX4PMState *s = opaque;
> > +    pci_bus_hotplug(bus, piix4_acpi_pci_hotplug, DEVICE(s));
> > +}
> > +
> >  static void piix4_pm_machine_ready(Notifier *n, void *opaque)
> >  {
> >      PIIX4PMState *s = container_of(n, PIIX4PMState, machine_ready);
> > @@ -388,6 +433,10 @@ static void piix4_pm_machine_ready(Notifier *n, void *opaque)
> >      pci_conf[0x63] = 0x60;
> >      pci_conf[0x67] = (memory_region_present(io_as, 0x3f8) ? 0x08 : 0) |
> >          (memory_region_present(io_as, 0x2f8) ? 0x90 : 0);
> > +
> > +    if (s->use_acpi_pci_hotplug) {
> > +        pci_for_each_bus(d->bus, piix4_update_bus_hotplug, s);
> > +    }
> >  }
> >  
> >  static void piix4_pm_add_propeties(PIIX4PMState *s)
> > @@ -509,6 +558,8 @@ static Property piix4_pm_properties[] = {
> >      DEFINE_PROP_UINT8(ACPI_PM_PROP_S3_DISABLED, PIIX4PMState, disable_s3, 0),
> >      DEFINE_PROP_UINT8(ACPI_PM_PROP_S4_DISABLED, PIIX4PMState, disable_s4, 0),
> >      DEFINE_PROP_UINT8(ACPI_PM_PROP_S4_VAL, PIIX4PMState, s4_val, 2),
> > +    DEFINE_PROP_BOOL("acpi-pci-hotplug-with-bridge-support", PIIX4PMState,
> > +                     use_acpi_pci_hotplug, true),
> >      DEFINE_PROP_END_OF_LIST(),
> >  };
> >  
> > @@ -701,11 +752,15 @@ static void piix4_acpi_system_hot_add_init(MemoryRegion *parent,
> >                            "acpi-gpe0", GPE_LEN);
> >      memory_region_add_subregion(parent, GPE_BASE, &s->io_gpe);
> >  
> > -    memory_region_init_io(&s->io_pci, OBJECT(s), &piix4_pci_ops, s,
> > -                          "acpi-pci-hotplug", PCI_HOTPLUG_SIZE);
> > -    memory_region_add_subregion(parent, PCI_HOTPLUG_ADDR,
> > -                                &s->io_pci);
> > -    pci_bus_hotplug(bus, piix4_device_hotplug, DEVICE(s));
> > +    if (s->use_acpi_pci_hotplug) {
> > +        acpi_pcihp_init(&s->acpi_pci_hotplug, bus, parent);
> > +    } else {
> > +        memory_region_init_io(&s->io_pci, OBJECT(s), &piix4_pci_ops, s,
> > +                              "acpi-pci-hotplug", PCI_HOTPLUG_SIZE);
> > +        memory_region_add_subregion(parent, PCI_HOTPLUG_ADDR,
> > +                                    &s->io_pci);
> > +        pci_bus_hotplug(bus, piix4_device_hotplug, DEVICE(s));
> > +    }
> >  
> >      CPU_FOREACH(cpu) {
> >          CPUClass *cc = CPU_GET_CLASS(cpu);
> > -- 
> > MST
> >
diff mbox

Patch

diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
index eb3da96..71653e8 100644
--- a/include/hw/i386/pc.h
+++ b/include/hw/i386/pc.h
@@ -261,6 +261,11 @@  int e820_add_entry(uint64_t, uint64_t, uint32_t);
 
 #define PC_COMPAT_1_6 \
         {\
+            .driver   = "PIIX4_PM",\
+            .property = "acpi-pci-hotplug-with-bridge-support",\
+            .value    = "off",\
+        }, \
+        {\
             .driver   = "e1000",\
             .property = "mitigation",\
             .value    = "off",\
diff --git a/hw/acpi/piix4.c b/hw/acpi/piix4.c
index 20353b9..1aa35bc 100644
--- a/hw/acpi/piix4.c
+++ b/hw/acpi/piix4.c
@@ -30,6 +30,7 @@ 
 #include "hw/nvram/fw_cfg.h"
 #include "exec/address-spaces.h"
 #include "hw/acpi/piix4.h"
+#include "hw/acpi/pcihp.h"
 
 //#define DEBUG
 
@@ -73,7 +74,6 @@  typedef struct PIIX4PMState {
     uint32_t io_base;
 
     MemoryRegion io_gpe;
-    MemoryRegion io_pci;
     MemoryRegion io_cpu;
     ACPIREGS ar;
 
@@ -88,11 +88,16 @@  typedef struct PIIX4PMState {
     Notifier machine_ready;
     Notifier powerdown_notifier;
 
-    /* for pci hotplug */
+    /* for legacy pci hotplug (compatible with qemu 1.6 and older) */
+    MemoryRegion io_pci;
     struct pci_status pci0_status;
     uint32_t pci0_hotplug_enable;
     uint32_t pci0_slot_device_present;
 
+    /* for new pci hotplug (with PCI2PCI bridge support) */
+    AcpiPciHpState acpi_pci_hotplug;
+    bool use_acpi_pci_hotplug;
+
     uint8_t disable_s3;
     uint8_t disable_s4;
     uint8_t s4_val;
@@ -263,6 +268,18 @@  static int acpi_load_old(QEMUFile *f, void *opaque, int version_id)
     return ret;
 }
 
+static bool vmstate_test_use_acpi_pci_hotplug(void *opaque, int version_id)
+{
+    PIIX4PMState *s = opaque;
+    return s->use_acpi_pci_hotplug;
+}
+
+static bool vmstate_test_no_use_acpi_pci_hotplug(void *opaque, int version_id)
+{
+    PIIX4PMState *s = opaque;
+    return !s->use_acpi_pci_hotplug;
+}
+
 /* qemu-kvm 1.2 uses version 3 but advertised as 2
  * To support incoming qemu-kvm 1.2 migration, change version_id
  * and minimum_version_id to 2 below (which breaks migration from
@@ -285,8 +302,12 @@  static const VMStateDescription vmstate_acpi = {
         VMSTATE_TIMER(ar.tmr.timer, PIIX4PMState),
         VMSTATE_INT64(ar.tmr.overflow_time, PIIX4PMState),
         VMSTATE_STRUCT(ar.gpe, PIIX4PMState, 2, vmstate_gpe, ACPIGPE),
-        VMSTATE_STRUCT(pci0_status, PIIX4PMState, 2, vmstate_pci_status,
-                       struct pci_status),
+        VMSTATE_STRUCT_TEST(pci0_status, PIIX4PMState,
+                            vmstate_test_no_use_acpi_pci_hotplug,
+                            2, vmstate_pci_status,
+                            struct pci_status),
+        VMSTATE_PCI_HOTPLUG(acpi_pci_hotplug, PIIX4PMState,
+                            vmstate_test_use_acpi_pci_hotplug),
         VMSTATE_END_OF_LIST()
     }
 };
@@ -364,7 +385,11 @@  static void piix4_reset(void *opaque)
         pci_conf[0x5B] = 0x02;
     }
     pm_io_space_update(s);
-    piix4_update_hotplug(s);
+    if (s->use_acpi_pci_hotplug) {
+        acpi_pcihp_reset(&s->acpi_pci_hotplug);
+    } else {
+        piix4_update_hotplug(s);
+    }
 }
 
 static void piix4_pm_powerdown_req(Notifier *n, void *opaque)
@@ -375,6 +400,26 @@  static void piix4_pm_powerdown_req(Notifier *n, void *opaque)
     acpi_pm1_evt_power_down(&s->ar);
 }
 
+static int piix4_acpi_pci_hotplug(DeviceState *qdev, PCIDevice *dev,
+                                  PCIHotplugState state)
+{
+    PIIX4PMState *s = PIIX4_PM(qdev);
+    int ret = acpi_pcihp_device_hotplug(&s->acpi_pci_hotplug, dev, state);
+    if (ret < 0) {
+        return ret;
+    }
+    s->ar.gpe.sts[0] |= PIIX4_PCI_HOTPLUG_STATUS;
+
+    acpi_update_sci(&s->ar, s->irq);
+    return 0;
+}
+
+static void piix4_update_bus_hotplug(PCIBus *bus, void *opaque)
+{
+    PIIX4PMState *s = opaque;
+    pci_bus_hotplug(bus, piix4_acpi_pci_hotplug, DEVICE(s));
+}
+
 static void piix4_pm_machine_ready(Notifier *n, void *opaque)
 {
     PIIX4PMState *s = container_of(n, PIIX4PMState, machine_ready);
@@ -388,6 +433,10 @@  static void piix4_pm_machine_ready(Notifier *n, void *opaque)
     pci_conf[0x63] = 0x60;
     pci_conf[0x67] = (memory_region_present(io_as, 0x3f8) ? 0x08 : 0) |
         (memory_region_present(io_as, 0x2f8) ? 0x90 : 0);
+
+    if (s->use_acpi_pci_hotplug) {
+        pci_for_each_bus(d->bus, piix4_update_bus_hotplug, s);
+    }
 }
 
 static void piix4_pm_add_propeties(PIIX4PMState *s)
@@ -509,6 +558,8 @@  static Property piix4_pm_properties[] = {
     DEFINE_PROP_UINT8(ACPI_PM_PROP_S3_DISABLED, PIIX4PMState, disable_s3, 0),
     DEFINE_PROP_UINT8(ACPI_PM_PROP_S4_DISABLED, PIIX4PMState, disable_s4, 0),
     DEFINE_PROP_UINT8(ACPI_PM_PROP_S4_VAL, PIIX4PMState, s4_val, 2),
+    DEFINE_PROP_BOOL("acpi-pci-hotplug-with-bridge-support", PIIX4PMState,
+                     use_acpi_pci_hotplug, true),
     DEFINE_PROP_END_OF_LIST(),
 };
 
@@ -701,11 +752,15 @@  static void piix4_acpi_system_hot_add_init(MemoryRegion *parent,
                           "acpi-gpe0", GPE_LEN);
     memory_region_add_subregion(parent, GPE_BASE, &s->io_gpe);
 
-    memory_region_init_io(&s->io_pci, OBJECT(s), &piix4_pci_ops, s,
-                          "acpi-pci-hotplug", PCI_HOTPLUG_SIZE);
-    memory_region_add_subregion(parent, PCI_HOTPLUG_ADDR,
-                                &s->io_pci);
-    pci_bus_hotplug(bus, piix4_device_hotplug, DEVICE(s));
+    if (s->use_acpi_pci_hotplug) {
+        acpi_pcihp_init(&s->acpi_pci_hotplug, bus, parent);
+    } else {
+        memory_region_init_io(&s->io_pci, OBJECT(s), &piix4_pci_ops, s,
+                              "acpi-pci-hotplug", PCI_HOTPLUG_SIZE);
+        memory_region_add_subregion(parent, PCI_HOTPLUG_ADDR,
+                                    &s->io_pci);
+        pci_bus_hotplug(bus, piix4_device_hotplug, DEVICE(s));
+    }
 
     CPU_FOREACH(cpu) {
         CPUClass *cc = CPU_GET_CLASS(cpu);