diff --git a/drivers/pci/hotplug/pnv_php.c b/drivers/pci/hotplug/pnv_php.c index f4c2e6e01be0..881d420637bf 100644 --- a/drivers/pci/hotplug/pnv_php.c +++ b/drivers/pci/hotplug/pnv_php.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include diff --git a/drivers/pci/hotplug/rpadlpar_core.c b/drivers/pci/hotplug/rpadlpar_core.c index e6991ff67526..980bb3afd092 100644 --- a/drivers/pci/hotplug/rpadlpar_core.c +++ b/drivers/pci/hotplug/rpadlpar_core.c @@ -15,6 +15,7 @@ #include #include +#include #include #include #include diff --git a/drivers/pci/hotplug/rpaphp_core.c b/drivers/pci/hotplug/rpaphp_core.c index 9887c9de08c3..491986197c47 100644 --- a/drivers/pci/hotplug/rpaphp_core.c +++ b/drivers/pci/hotplug/rpaphp_core.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -20,6 +21,7 @@ #include /* for eeh_add_device() */ #include /* rtas_call */ #include /* for pci_controller */ +#include #include "../pci.h" /* for pci_add_new_bus */ /* and pci_do_scan_bus */ #include "rpaphp.h" diff --git a/drivers/pci/hotplug/rpaphp_pci.c b/drivers/pci/hotplug/rpaphp_pci.c index c380bdacd146..630f77057c23 100644 --- a/drivers/pci/hotplug/rpaphp_pci.c +++ b/drivers/pci/hotplug/rpaphp_pci.c @@ -8,6 +8,7 @@ * Send feedback to * */ +#include #include #include diff --git a/drivers/pci/hotplug/rpaphp_slot.c b/drivers/pci/hotplug/rpaphp_slot.c index 93b4a945c55d..779eab12e981 100644 --- a/drivers/pci/hotplug/rpaphp_slot.c +++ b/drivers/pci/hotplug/rpaphp_slot.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index 1f15ab7eabf8..3ae435beaf0a 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -974,9 +974,11 @@ bool acpi_pci_power_manageable(struct pci_dev *dev) bool acpi_pci_bridge_d3(struct pci_dev *dev) { - const union acpi_object *obj; - struct acpi_device *adev; struct pci_dev *rpdev; + struct acpi_device *adev; + acpi_status status; + unsigned long long state; + const union acpi_object *obj; if (acpi_pci_disabled || !dev->is_hotplug_bridge) return false; @@ -985,12 +987,6 @@ bool acpi_pci_bridge_d3(struct pci_dev *dev) if (acpi_pci_power_manageable(dev)) return true; - /* - * The ACPI firmware will provide the device-specific properties through - * _DSD configuration object. Look for the 'HotPlugSupportInD3' property - * for the root port and if it is set we know the hierarchy behind it - * supports D3 just fine. - */ rpdev = pcie_find_root_port(dev); if (!rpdev) return false; @@ -999,11 +995,34 @@ bool acpi_pci_bridge_d3(struct pci_dev *dev) if (!adev) return false; - if (acpi_dev_get_property(adev, "HotPlugSupportInD3", - ACPI_TYPE_INTEGER, &obj) < 0) + /* + * If the Root Port cannot signal wakeup signals at all, i.e., it + * doesn't supply a wakeup GPE via _PRW, it cannot signal hotplug + * events from low-power states including D3hot and D3cold. + */ + if (!adev->wakeup.flags.valid) return false; - return obj->integer.value == 1; + /* + * If the Root Port cannot wake itself from D3hot or D3cold, we + * can't use D3. + */ + status = acpi_evaluate_integer(adev->handle, "_S0W", NULL, &state); + if (ACPI_SUCCESS(status) && state < ACPI_STATE_D3_HOT) + return false; + + /* + * The "HotPlugSupportInD3" property in a Root Port _DSD indicates + * the Port can signal hotplug events while in D3. We assume any + * bridges *below* that Root Port can also signal hotplug events + * while in D3. + */ + if (!acpi_dev_get_property(adev, "HotPlugSupportInD3", + ACPI_TYPE_INTEGER, &obj) && + obj->integer.value == 1) + return true; + + return false; } int acpi_pci_set_power_state(struct pci_dev *dev, pci_power_t state)