PCI: ACPI: PM: Power up devices in D3cold before scanning them
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>
Mon, 4 Apr 2022 15:25:04 +0000 (17:25 +0200)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Wed, 13 Apr 2022 15:26:22 +0000 (17:26 +0200)
The initial configuration of ACPI power resources on some systems
implies that some PCI devices on them are initially in D3cold.

In some cases, especially for PCIe Root Ports, this is a "logical"
D3cold, meaning that the configuration space of the device is
accessible, but some of its functionality may be missing, but it
very well may be real D3cold, in which case the device will not
be accessible at all.  However, the PCI bus type driver will need
to access its configuration space in order to enumerate it.

To prevent possible device enumeration failures that may ensue as
a result of ACPI power resources being initially in the "off"
state, power up all children of the host bridge ACPI device object
that hold valid _ADR objects (which indicates that they will be
enumerated by the PCI bus type driver) and do that to all children
of the ACPI device objects corresponding to PCI bridges (including
PCIe ports).

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Acked-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Mika Westerberg <mika.westerberg@linux.intel.com>
drivers/acpi/pci_root.c
drivers/pci/pci-acpi.c

index 6f9e75d148084b48ba2db9de38dd3209dd274f42..b3b507f20e87edf061ca9099fac1070de1be3255 100644 (file)
@@ -927,6 +927,8 @@ struct pci_bus *acpi_pci_root_create(struct acpi_pci_root *root,
                host_bridge->preserve_config = 1;
        ACPI_FREE(obj);
 
+       acpi_dev_power_up_children_with_adr(device);
+
        pci_scan_child_bus(bus);
        pci_set_host_bridge_release(host_bridge, acpi_pci_root_release_info,
                                    info);
index 1f15ab7eabf81dca8365f26144afbd5ff3ffa40c..3787876ecb245c69d13c20abdf613504c3c9c2e4 100644 (file)
@@ -1374,6 +1374,9 @@ void pci_acpi_setup(struct device *dev, struct acpi_device *adev)
 
        acpi_pci_wakeup(pci_dev, false);
        acpi_device_power_add_dependent(adev, dev);
+
+       if (pci_is_bridge(pci_dev))
+               acpi_dev_power_up_children_with_adr(adev);
 }
 
 void pci_acpi_cleanup(struct device *dev, struct acpi_device *adev)