diff options
author | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2021-11-02 19:11:49 +0100 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2021-11-02 19:11:49 +0100 |
commit | b62b306469b36fae7030c0ad4ffa11de0c9b9957 (patch) | |
tree | 390ebc29f062281d5d86716451d1c9143678b36e /drivers/base | |
parent | Merge branch 'pm-pci' (diff) | |
parent | usb: mtu3: enable wake-up interrupt after runtime_suspend called (diff) | |
download | linux-b62b306469b36fae7030c0ad4ffa11de0c9b9957.tar.xz linux-b62b306469b36fae7030c0ad4ffa11de0c9b9957.zip |
Merge branch 'pm-sleep'
Merge updates related to system sleep for 5.16-rc1:
- Clean up hib_wait_io() (Falla Coulibaly).
- Fix sparse warnings in hibernation-related code (Anders Roxell).
- Use vzalloc() and kzalloc() instead of their open-coded
equivalents in hibernation-related code (Cai Huoqing).
- Prevent user space from crashing the kernel by attempting to
restore the system state from a swap partition in use (Ye Bin).
- Do not let "syscore" devices runtime-suspend during system PM
transitions (Rafael Wysocki).
- Do not pause cpuidle in the suspend-to-idle path (Rafael Wysocki).
- Pause cpuidle later and resume it earlier during system PM
transitions (Rafael Wysocki).
- Make system suspend code use valid_state() consistently (Rafael
Wysocki).
- Add support for enabling wakeup IRQs after invoking the
->runtime_suspend() callback and make two drivers use it (Chunfeng
Yun).
* pm-sleep:
usb: mtu3: enable wake-up interrupt after runtime_suspend called
usb: xhci-mtk: enable wake-up interrupt after runtime_suspend called
PM / wakeirq: support enabling wake-up irq after runtime_suspend called
PM: suspend: Use valid_state() consistently
PM: sleep: Pause cpuidle later and resume it earlier during system transitions
PM: suspend: Do not pause cpuidle in the suspend-to-idle path
PM: sleep: Do not let "syscore" devices runtime-suspend during system transitions
PM: hibernate: Get block device exclusively in swsusp_check()
PM: hibernate: swap: Use vzalloc() and kzalloc()
PM: hibernate: fix sparse warnings
Revert "PM: sleep: Do not assume that "mem" is always present"
PM: hibernate: Remove blk_status_to_errno in hib_wait_io
PM: sleep: Do not assume that "mem" is always present
Diffstat (limited to 'drivers/base')
-rw-r--r-- | drivers/base/power/main.c | 14 | ||||
-rw-r--r-- | drivers/base/power/power.h | 7 | ||||
-rw-r--r-- | drivers/base/power/runtime.c | 6 | ||||
-rw-r--r-- | drivers/base/power/wakeirq.c | 101 |
4 files changed, 94 insertions, 34 deletions
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index cbea78e79f3d..ac4dde8fdb8b 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -32,7 +32,6 @@ #include <linux/suspend.h> #include <trace/events/power.h> #include <linux/cpufreq.h> -#include <linux/cpuidle.h> #include <linux/devfreq.h> #include <linux/timer.h> @@ -747,8 +746,6 @@ void dpm_resume_noirq(pm_message_t state) resume_device_irqs(); device_wakeup_disarm_wake_irqs(); - - cpuidle_resume(); } /** @@ -1051,7 +1048,7 @@ static void device_complete(struct device *dev, pm_message_t state) const char *info = NULL; if (dev->power.syscore) - return; + goto out; device_lock(dev); @@ -1081,6 +1078,7 @@ static void device_complete(struct device *dev, pm_message_t state) device_unlock(dev); +out: pm_runtime_put(dev); } @@ -1336,8 +1334,6 @@ int dpm_suspend_noirq(pm_message_t state) { int ret; - cpuidle_pause(); - device_wakeup_arm_wake_irqs(); suspend_device_irqs(); @@ -1794,9 +1790,6 @@ static int device_prepare(struct device *dev, pm_message_t state) int (*callback)(struct device *) = NULL; int ret = 0; - if (dev->power.syscore) - return 0; - /* * If a device's parent goes into runtime suspend at the wrong time, * it won't be possible to resume the device. To prevent this we @@ -1805,6 +1798,9 @@ static int device_prepare(struct device *dev, pm_message_t state) */ pm_runtime_get_noresume(dev); + if (dev->power.syscore) + return 0; + device_lock(dev); dev->power.wakeup_path = false; diff --git a/drivers/base/power/power.h b/drivers/base/power/power.h index 54292cdd7808..0eb7f02b3ad5 100644 --- a/drivers/base/power/power.h +++ b/drivers/base/power/power.h @@ -25,8 +25,10 @@ extern u64 pm_runtime_active_time(struct device *dev); #define WAKE_IRQ_DEDICATED_ALLOCATED BIT(0) #define WAKE_IRQ_DEDICATED_MANAGED BIT(1) +#define WAKE_IRQ_DEDICATED_REVERSE BIT(2) #define WAKE_IRQ_DEDICATED_MASK (WAKE_IRQ_DEDICATED_ALLOCATED | \ - WAKE_IRQ_DEDICATED_MANAGED) + WAKE_IRQ_DEDICATED_MANAGED | \ + WAKE_IRQ_DEDICATED_REVERSE) struct wake_irq { struct device *dev; @@ -39,7 +41,8 @@ extern void dev_pm_arm_wake_irq(struct wake_irq *wirq); extern void dev_pm_disarm_wake_irq(struct wake_irq *wirq); extern void dev_pm_enable_wake_irq_check(struct device *dev, bool can_change_status); -extern void dev_pm_disable_wake_irq_check(struct device *dev); +extern void dev_pm_disable_wake_irq_check(struct device *dev, bool cond_disable); +extern void dev_pm_enable_wake_irq_complete(struct device *dev); #ifdef CONFIG_PM_SLEEP diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index ec94049442b9..d504cd4ab3cb 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c @@ -645,6 +645,8 @@ static int rpm_suspend(struct device *dev, int rpmflags) if (retval) goto fail; + dev_pm_enable_wake_irq_complete(dev); + no_callback: __update_runtime_status(dev, RPM_SUSPENDED); pm_runtime_deactivate_timer(dev); @@ -690,7 +692,7 @@ static int rpm_suspend(struct device *dev, int rpmflags) return retval; fail: - dev_pm_disable_wake_irq_check(dev); + dev_pm_disable_wake_irq_check(dev, true); __update_runtime_status(dev, RPM_ACTIVE); dev->power.deferred_resume = false; wake_up_all(&dev->power.wait_queue); @@ -873,7 +875,7 @@ static int rpm_resume(struct device *dev, int rpmflags) callback = RPM_GET_CALLBACK(dev, runtime_resume); - dev_pm_disable_wake_irq_check(dev); + dev_pm_disable_wake_irq_check(dev, false); retval = rpm_callback(callback, dev); if (retval) { __update_runtime_status(dev, RPM_SUSPENDED); diff --git a/drivers/base/power/wakeirq.c b/drivers/base/power/wakeirq.c index b91a3a9bf9f6..0004db4a9d3b 100644 --- a/drivers/base/power/wakeirq.c +++ b/drivers/base/power/wakeirq.c @@ -142,24 +142,7 @@ static irqreturn_t handle_threaded_wake_irq(int irq, void *_wirq) return IRQ_HANDLED; } -/** - * dev_pm_set_dedicated_wake_irq - Request a dedicated wake-up interrupt - * @dev: Device entry - * @irq: Device wake-up interrupt - * - * Unless your hardware has separate wake-up interrupts in addition - * to the device IO interrupts, you don't need this. - * - * Sets up a threaded interrupt handler for a device that has - * a dedicated wake-up interrupt in addition to the device IO - * interrupt. - * - * The interrupt starts disabled, and needs to be managed for - * the device by the bus code or the device driver using - * dev_pm_enable_wake_irq() and dev_pm_disable_wake_irq() - * functions. - */ -int dev_pm_set_dedicated_wake_irq(struct device *dev, int irq) +static int __dev_pm_set_dedicated_wake_irq(struct device *dev, int irq, unsigned int flag) { struct wake_irq *wirq; int err; @@ -197,7 +180,7 @@ int dev_pm_set_dedicated_wake_irq(struct device *dev, int irq) if (err) goto err_free_irq; - wirq->status = WAKE_IRQ_DEDICATED_ALLOCATED; + wirq->status = WAKE_IRQ_DEDICATED_ALLOCATED | flag; return err; @@ -210,9 +193,58 @@ err_free: return err; } + + +/** + * dev_pm_set_dedicated_wake_irq - Request a dedicated wake-up interrupt + * @dev: Device entry + * @irq: Device wake-up interrupt + * + * Unless your hardware has separate wake-up interrupts in addition + * to the device IO interrupts, you don't need this. + * + * Sets up a threaded interrupt handler for a device that has + * a dedicated wake-up interrupt in addition to the device IO + * interrupt. + * + * The interrupt starts disabled, and needs to be managed for + * the device by the bus code or the device driver using + * dev_pm_enable_wake_irq*() and dev_pm_disable_wake_irq*() + * functions. + */ +int dev_pm_set_dedicated_wake_irq(struct device *dev, int irq) +{ + return __dev_pm_set_dedicated_wake_irq(dev, irq, 0); +} EXPORT_SYMBOL_GPL(dev_pm_set_dedicated_wake_irq); /** + * dev_pm_set_dedicated_wake_irq_reverse - Request a dedicated wake-up interrupt + * with reverse enable ordering + * @dev: Device entry + * @irq: Device wake-up interrupt + * + * Unless your hardware has separate wake-up interrupts in addition + * to the device IO interrupts, you don't need this. + * + * Sets up a threaded interrupt handler for a device that has a dedicated + * wake-up interrupt in addition to the device IO interrupt. It sets + * the status of WAKE_IRQ_DEDICATED_REVERSE to tell rpm_suspend() + * to enable dedicated wake-up interrupt after running the runtime suspend + * callback for @dev. + * + * The interrupt starts disabled, and needs to be managed for + * the device by the bus code or the device driver using + * dev_pm_enable_wake_irq*() and dev_pm_disable_wake_irq*() + * functions. + */ +int dev_pm_set_dedicated_wake_irq_reverse(struct device *dev, int irq) +{ + return __dev_pm_set_dedicated_wake_irq(dev, irq, WAKE_IRQ_DEDICATED_REVERSE); +} +EXPORT_SYMBOL_GPL(dev_pm_set_dedicated_wake_irq_reverse); + +/** * dev_pm_enable_wake_irq - Enable device wake-up interrupt * @dev: Device * @@ -282,28 +314,55 @@ void dev_pm_enable_wake_irq_check(struct device *dev, return; enable: - enable_irq(wirq->irq); + if (!can_change_status || !(wirq->status & WAKE_IRQ_DEDICATED_REVERSE)) + enable_irq(wirq->irq); } /** * dev_pm_disable_wake_irq_check - Checks and disables wake-up interrupt * @dev: Device + * @cond_disable: if set, also check WAKE_IRQ_DEDICATED_REVERSE * * Disables wake-up interrupt conditionally based on status. * Should be only called from rpm_suspend() and rpm_resume() path. */ -void dev_pm_disable_wake_irq_check(struct device *dev) +void dev_pm_disable_wake_irq_check(struct device *dev, bool cond_disable) { struct wake_irq *wirq = dev->power.wakeirq; if (!wirq || !(wirq->status & WAKE_IRQ_DEDICATED_MASK)) return; + if (cond_disable && (wirq->status & WAKE_IRQ_DEDICATED_REVERSE)) + return; + if (wirq->status & WAKE_IRQ_DEDICATED_MANAGED) disable_irq_nosync(wirq->irq); } /** + * dev_pm_enable_wake_irq_complete - enable wake IRQ not enabled before + * @dev: Device using the wake IRQ + * + * Enable wake IRQ conditionally based on status, mainly used if want to + * enable wake IRQ after running ->runtime_suspend() which depends on + * WAKE_IRQ_DEDICATED_REVERSE. + * + * Should be only called from rpm_suspend() path. + */ +void dev_pm_enable_wake_irq_complete(struct device *dev) +{ + struct wake_irq *wirq = dev->power.wakeirq; + + if (!wirq || !(wirq->status & WAKE_IRQ_DEDICATED_MASK)) + return; + + if (wirq->status & WAKE_IRQ_DEDICATED_MANAGED && + wirq->status & WAKE_IRQ_DEDICATED_REVERSE) + enable_irq(wirq->irq); +} + +/** * dev_pm_arm_wake_irq - Arm device wake-up * @wirq: Device wake-up interrupt * |