Merge tag 'for-linus-5.14-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rw...
[linux-2.6-microblaze.git] / drivers / acpi / device_pm.c
index d260bc1..0028b6b 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/pm_runtime.h>
 #include <linux/suspend.h>
 
+#include "fan.h"
 #include "internal.h"
 
 /**
@@ -1133,19 +1134,48 @@ static int acpi_subsys_resume_noirq(struct device *dev)
  *
  * Use ACPI to put the given device into the full-power state and carry out the
  * generic early resume procedure for it during system transition into the
- * working state.
+ * working state, but only do that if device either defines early resume
+ * handler, or does not define power operations at all. Otherwise powering up
+ * of the device is postponed to the normal resume phase.
  */
 static int acpi_subsys_resume_early(struct device *dev)
 {
+       const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
        int ret;
 
        if (dev_pm_skip_resume(dev))
                return 0;
 
+       if (pm && !pm->resume_early) {
+               dev_dbg(dev, "postponing D0 transition to normal resume stage\n");
+               return 0;
+       }
+
        ret = acpi_dev_resume(dev);
        return ret ? ret : pm_generic_resume_early(dev);
 }
 
+/**
+ * acpi_subsys_resume - Resume device using ACPI.
+ * @dev: Device to Resume.
+ *
+ * Use ACPI to put the given device into the full-power state if it has not been
+ * powered up during early resume phase, and carry out the generic resume
+ * procedure for it during system transition into the working state.
+ */
+static int acpi_subsys_resume(struct device *dev)
+{
+       const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
+       int ret = 0;
+
+       if (!dev_pm_skip_resume(dev) && pm && !pm->resume_early) {
+               dev_dbg(dev, "executing postponed D0 transition\n");
+               ret = acpi_dev_resume(dev);
+       }
+
+       return ret ? ret : pm_generic_resume(dev);
+}
+
 /**
  * acpi_subsys_freeze - Run the device driver's freeze callback.
  * @dev: Device to handle.
@@ -1239,6 +1269,7 @@ static struct dev_pm_domain acpi_general_pm_domain = {
                .prepare = acpi_subsys_prepare,
                .complete = acpi_subsys_complete,
                .suspend = acpi_subsys_suspend,
+               .resume = acpi_subsys_resume,
                .suspend_late = acpi_subsys_suspend_late,
                .suspend_noirq = acpi_subsys_suspend_noirq,
                .resume_noirq = acpi_subsys_resume_noirq,
@@ -1310,10 +1341,7 @@ int acpi_dev_pm_attach(struct device *dev, bool power_on)
         * with the generic ACPI PM domain.
         */
        static const struct acpi_device_id special_pm_ids[] = {
-               {"PNP0C0B", }, /* Generic ACPI fan */
-               {"INT3404", }, /* Fan */
-               {"INTC1044", }, /* Fan for Tiger Lake generation */
-               {"INTC1048", }, /* Fan for Alder Lake generation */
+               ACPI_FAN_DEVICE_IDS,
                {}
        };
        struct acpi_device *adev = ACPI_COMPANION(dev);
@@ -1340,4 +1368,36 @@ int acpi_dev_pm_attach(struct device *dev, bool power_on)
        return 1;
 }
 EXPORT_SYMBOL_GPL(acpi_dev_pm_attach);
+
+/**
+ * acpi_storage_d3 - Check if D3 should be used in the suspend path
+ * @dev: Device to check
+ *
+ * Return %true if the platform firmware wants @dev to be programmed
+ * into D3hot or D3cold (if supported) in the suspend path, or %false
+ * when there is no specific preference. On some platforms, if this
+ * hint is ignored, @dev may remain unresponsive after suspending the
+ * platform as a whole.
+ *
+ * Although the property has storage in the name it actually is
+ * applied to the PCIe slot and plugging in a non-storage device the
+ * same platform restrictions will likely apply.
+ */
+bool acpi_storage_d3(struct device *dev)
+{
+       struct acpi_device *adev = ACPI_COMPANION(dev);
+       u8 val;
+
+       if (force_storage_d3())
+               return true;
+
+       if (!adev)
+               return false;
+       if (fwnode_property_read_u8(acpi_fwnode_handle(adev), "StorageD3Enable",
+                       &val))
+               return false;
+       return val == 1;
+}
+EXPORT_SYMBOL_GPL(acpi_storage_d3);
+
 #endif /* CONFIG_PM */