--- /dev/null
+From cc22522fd55e257c86d340ae9aedc122e705a435 Mon Sep 17 00:00:00 2001
+From: Igor Mammedov <imammedo@redhat.com>
+Date: Wed, 26 Jul 2023 14:35:18 +0200
+Subject: PCI: acpiphp: Use pci_assign_unassigned_bridge_resources() only for non-root bus
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Igor Mammedov <imammedo@redhat.com>
+
+commit cc22522fd55e257c86d340ae9aedc122e705a435 upstream.
+
+40613da52b13 ("PCI: acpiphp: Reassign resources on bridge if necessary")
+changed acpiphp hotplug to use pci_assign_unassigned_bridge_resources()
+which depends on bridge being available, however enable_slot() can be
+called without bridge associated:
+
+ 1. Legitimate case of hotplug on root bus (widely used in virt world)
+
+ 2. A (misbehaving) firmware, that sends ACPI Bus Check notifications to
+ non existing root ports (Dell Inspiron 7352/0W6WV0), which end up at
+ enable_slot(..., bridge = 0) where bus has no bridge assigned to it.
+ acpihp doesn't know that it's a bridge, and bus specific 'PCI
+ subsystem' can't augment ACPI context with bridge information since
+ the PCI device to get this data from is/was not available.
+
+Issue is easy to reproduce with QEMU's 'pc' machine, which supports PCI
+hotplug on hostbridge slots. To reproduce, boot kernel at commit
+40613da52b13 in VM started with following CLI (assuming guest root fs is
+installed on sda1 partition):
+
+ # qemu-system-x86_64 -M pc -m 1G -enable-kvm -cpu host \
+ -monitor stdio -serial file:serial.log \
+ -kernel arch/x86/boot/bzImage \
+ -append "root=/dev/sda1 console=ttyS0" \
+ guest_disk.img
+
+Once guest OS is fully booted at qemu prompt:
+
+ (qemu) device_add e1000
+
+(check serial.log) it will cause NULL pointer dereference at:
+
+ void pci_assign_unassigned_bridge_resources(struct pci_dev *bridge)
+ {
+ struct pci_bus *parent = bridge->subordinate;
+
+ BUG: kernel NULL pointer dereference, address: 0000000000000018
+
+ ? pci_assign_unassigned_bridge_resources+0x1f/0x260
+ enable_slot+0x21f/0x3e0
+ acpiphp_hotplug_notify+0x13d/0x260
+ acpi_device_hotplug+0xbc/0x540
+ acpi_hotplug_work_fn+0x15/0x20
+ process_one_work+0x1f7/0x370
+ worker_thread+0x45/0x3b0
+
+The issue was discovered on Dell Inspiron 7352/0W6WV0 laptop with following
+sequence:
+
+ 1. Suspend to RAM
+ 2. Wake up with the same backtrace being observed:
+ 3. 2nd suspend to RAM attempt makes laptop freeze
+
+Fix it by using __pci_bus_assign_resources() instead of
+pci_assign_unassigned_bridge_resources() as we used to do, but only in case
+when bus doesn't have a bridge associated (to cover for the case of ACPI
+event on hostbridge or non existing root port).
+
+That lets us keep hotplug on root bus working like it used to and at the
+same time keeps resource reassignment usable on root ports (and other 1st
+level bridges) that was fixed by 40613da52b13.
+
+Fixes: 40613da52b13 ("PCI: acpiphp: Reassign resources on bridge if necessary")
+Link: https://lore.kernel.org/r/20230726123518.2361181-2-imammedo@redhat.com
+Reported-by: Woody Suwalski <terraluna977@gmail.com>
+Tested-by: Woody Suwalski <terraluna977@gmail.com>
+Tested-by: Michal Koutný <mkoutny@suse.com>
+Link: https://lore.kernel.org/r/11fc981c-af49-ce64-6b43-3e282728bd1a@gmail.com
+Signed-off-by: Igor Mammedov <imammedo@redhat.com>
+Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
+Acked-by: Rafael J. Wysocki <rafael@kernel.org>
+Acked-by: Michael S. Tsirkin <mst@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/pci/hotplug/acpiphp_glue.c | 8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+--- a/drivers/pci/hotplug/acpiphp_glue.c
++++ b/drivers/pci/hotplug/acpiphp_glue.c
+@@ -489,6 +489,7 @@ static void enable_slot(struct acpiphp_s
+ acpiphp_native_scan_bridge(dev);
+ }
+ } else {
++ LIST_HEAD(add_list);
+ int max, pass;
+
+ acpiphp_rescan_slot(slot);
+@@ -502,10 +503,15 @@ static void enable_slot(struct acpiphp_s
+ if (pass && dev->subordinate) {
+ check_hotplug_bridge(slot, dev);
+ pcibios_resource_survey_bus(dev->subordinate);
++ if (pci_is_root_bus(bus))
++ __pci_bus_size_bridges(dev->subordinate, &add_list);
+ }
+ }
+ }
+- pci_assign_unassigned_bridge_resources(bus->self);
++ if (pci_is_root_bus(bus))
++ __pci_bus_assign_resources(bus, &add_list, NULL);
++ else
++ pci_assign_unassigned_bridge_resources(bus->self);
+ }
+
+ acpiphp_sanitize_bus(bus);