Merge tag 'hyperv-next-signed-20220528' of git://git.kernel.org/pub/scm/linux/kernel...
[linux-2.6-microblaze.git] / drivers / pci / pci-acpi.c
index 3787876..3760d85 100644 (file)
@@ -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)