From: Rafael J. Wysocki <rafael.j.wysocki@xxxxxxxxx> If the resume_from_noirq flag is set in dev_desc, the ->suspend_late callback provided by the device driver will be invoked at the "noirq" stage of system suspend, via acpi_lpss_do_suspend_late(), which is incorrect. To fix that, drop acpi_lpss_do_suspend_late() and rearrange acpi_lpss_suspend_late() to call pm_generic_suspend_late() directly, before calling acpi_lpss_suspend(), in analogy with acpi_subsys_suspend_late(). Also notice that acpi_subsys_suspend_late() is not used outside of the file where it is defined, so make it static and drop its header for the header file containing it. Fixes: 48402cee6889 (ACPI / LPSS: Resume BYT/CHT I2C controllers from resume_noirq) Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@xxxxxxxxx> --- drivers/acpi/acpi_lpss.c | 23 ++++++++++------------- drivers/acpi/device_pm.c | 3 +-- include/linux/acpi.h | 2 -- 3 files changed, 11 insertions(+), 17 deletions(-) Index: linux-pm/drivers/acpi/acpi_lpss.c =================================================================== --- linux-pm.orig/drivers/acpi/acpi_lpss.c +++ linux-pm/drivers/acpi/acpi_lpss.c @@ -1034,34 +1034,31 @@ static int acpi_lpss_resume(struct devic } #ifdef CONFIG_PM_SLEEP -static int acpi_lpss_do_suspend_late(struct device *dev) +static int acpi_lpss_suspend_late(struct device *dev) { + struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev)); int ret; if (dev_pm_smart_suspend_and_suspended(dev)) return 0; ret = pm_generic_suspend_late(dev); - return ret ? ret : acpi_lpss_suspend(dev, device_may_wakeup(dev)); -} + if (ret) + return ret; -static int acpi_lpss_suspend_late(struct device *dev) -{ - struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev)); - - if (pdata->dev_desc->resume_from_noirq) - return 0; + if (!pdata->dev_desc->resume_from_noirq) + return acpi_lpss_suspend(dev, device_may_wakeup(dev)); - return acpi_lpss_do_suspend_late(dev); + return 0; } static int acpi_lpss_suspend_noirq(struct device *dev) { struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev)); - int ret; - if (pdata->dev_desc->resume_from_noirq) { - ret = acpi_lpss_do_suspend_late(dev); + if (!dev_pm_smart_suspend_and_suspended(dev) && + pdata->dev_desc->resume_from_noirq) { + int ret = acpi_lpss_suspend(dev, device_may_wakeup(dev)); if (ret) return ret; } Index: linux-pm/drivers/acpi/device_pm.c =================================================================== --- linux-pm.orig/drivers/acpi/device_pm.c +++ linux-pm/drivers/acpi/device_pm.c @@ -1069,7 +1069,7 @@ EXPORT_SYMBOL_GPL(acpi_subsys_suspend); * Carry out the generic late suspend procedure for @dev and use ACPI to put * it into a low-power state during system transition into a sleep state. */ -int acpi_subsys_suspend_late(struct device *dev) +static int acpi_subsys_suspend_late(struct device *dev) { int ret; @@ -1079,7 +1079,6 @@ int acpi_subsys_suspend_late(struct devi ret = pm_generic_suspend_late(dev); return ret ? ret : acpi_dev_suspend(dev, device_may_wakeup(dev)); } -EXPORT_SYMBOL_GPL(acpi_subsys_suspend_late); /** * acpi_subsys_suspend_noirq - Run the device driver's "noirq" suspend callback. Index: linux-pm/include/linux/acpi.h =================================================================== --- linux-pm.orig/include/linux/acpi.h +++ linux-pm/include/linux/acpi.h @@ -916,7 +916,6 @@ static inline int acpi_dev_pm_attach(str int acpi_dev_suspend_late(struct device *dev); int acpi_subsys_prepare(struct device *dev); void acpi_subsys_complete(struct device *dev); -int acpi_subsys_suspend_late(struct device *dev); int acpi_subsys_suspend_noirq(struct device *dev); int acpi_subsys_suspend(struct device *dev); int acpi_subsys_freeze(struct device *dev); @@ -924,7 +923,6 @@ int acpi_subsys_freeze(struct device *de static inline int acpi_dev_resume_early(struct device *dev) { return 0; } static inline int acpi_subsys_prepare(struct device *dev) { return 0; } static inline void acpi_subsys_complete(struct device *dev) {} -static inline int acpi_subsys_suspend_late(struct device *dev) { return 0; } static inline int acpi_subsys_suspend_noirq(struct device *dev) { return 0; } static inline int acpi_subsys_suspend(struct device *dev) { return 0; } static inline int acpi_subsys_freeze(struct device *dev) { return 0; }