From: Igor Mammedov <imamm...@redhat.com>

When QEMU is started with hotplugged bridges (think migration):

  QEMU  -S -monitor stdio \
        -device pci-bridge,chassis_nr=1 \
        -device pci-bridge,bus=pci.1,addr=1.0,chassis_nr=2

  (qemu) device_add pci-bridge,id=hpbr,bus=pci.1,addr=2.0,chassis_nr=3
  (qemu) cont

it will generate AML calls to hpbr's PCNT, which doesn't exists
since it's hotplugged bridge. As result DSDT becomes malformed,
with consequences that hotplug might stop working at best or
crash guest OS at worst, when it attempts to call non existing
PCNT method or during OS guest reboot when parsing DSDT again.

IASL de-compiles malformed AML of above config DSDT as:

   +    External (_SB_.PCI0.S18_.S10_.PCNT, MethodObj)    // Warning: Unknown 
method, guessing 1 arguments
   +    External (_SB_.PCI0.S18_.S19_.PCNT, MethodObj)    // Warning: Unknown 
method, guessing 2 arguments
   ...
                        BNUM = One
                        DVNT (PCIU, One)
                        DVNT (PCID, 0x03)
   -                    ^S08.PCNT ()
   +                    ^S19.PCNT (^S10.PCNT (^S08.PCNT ()))
                    }
                }

With BSEL assignment limited only to coldplugged bridges [1],
it should be possible to add PCNT call to a child bridge only
if the child has BSEL property, otherwise ignore it since it's
hotplugged. Which should fix the issue.

1) ("pci: acpihp: assign BSEL only to coldplugged bridges")

Signed-off-by: Igor Mammedov <imamm...@redhat.com>
Message-Id: <20230112140312.3096331-13-imamm...@redhat.com>
Reviewed-by: Michael S. Tsirkin <m...@redhat.com>
Signed-off-by: Michael S. Tsirkin <m...@redhat.com>
---
 hw/i386/acpi-build.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index 8ba34d8fde..1c51ab01fc 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -515,7 +515,8 @@ static void build_append_pci_bus_devices(Aml *parent_scope, 
PCIBus *bus,
         /* Notify about child bus events in any case */
         if (pcihp_bridge_en) {
             QLIST_FOREACH(sec, &bus->child, sibling) {
-                if (pci_bus_is_root(sec)) {
+                if (pci_bus_is_root(sec) ||
+                    !object_property_find(OBJECT(sec), ACPI_PCIHP_PROP_BSEL)) {
                     continue;
                 }
 
-- 
MST


Reply via email to