| From 8527beb12087238d4387607597b4020bc393c4b4 Mon Sep 17 00:00:00 2001 |
| From: Johan Hovold <johan+linaro@kernel.org> |
| Date: Thu, 13 Jul 2023 16:57:39 +0200 |
| Subject: PM: sleep: wakeirq: fix wake irq arming |
| |
| From: Johan Hovold <johan+linaro@kernel.org> |
| |
| commit 8527beb12087238d4387607597b4020bc393c4b4 upstream. |
| |
| The decision whether to enable a wake irq during suspend can not be done |
| based on the runtime PM state directly as a driver may use wake irqs |
| without implementing runtime PM. Such drivers specifically leave the |
| state set to the default 'suspended' and the wake irq is thus never |
| enabled at suspend. |
| |
| Add a new wake irq flag to track whether a dedicated wake irq has been |
| enabled at runtime suspend and therefore must not be enabled at system |
| suspend. |
| |
| Note that pm_runtime_enabled() can not be used as runtime PM is always |
| disabled during late suspend. |
| |
| Fixes: 69728051f5bf ("PM / wakeirq: Fix unbalanced IRQ enable for wakeirq") |
| Cc: 4.16+ <stable@vger.kernel.org> # 4.16+ |
| Signed-off-by: Johan Hovold <johan+linaro@kernel.org> |
| Reviewed-by: Tony Lindgren <tony@atomide.com> |
| Tested-by: Tony Lindgren <tony@atomide.com> |
| Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| drivers/base/power/power.h | 1 + |
| drivers/base/power/wakeirq.c | 12 ++++++++---- |
| 2 files changed, 9 insertions(+), 4 deletions(-) |
| |
| --- a/drivers/base/power/power.h |
| +++ b/drivers/base/power/power.h |
| @@ -29,6 +29,7 @@ extern u64 pm_runtime_active_time(struct |
| #define WAKE_IRQ_DEDICATED_MASK (WAKE_IRQ_DEDICATED_ALLOCATED | \ |
| WAKE_IRQ_DEDICATED_MANAGED | \ |
| WAKE_IRQ_DEDICATED_REVERSE) |
| +#define WAKE_IRQ_DEDICATED_ENABLED BIT(3) |
| |
| struct wake_irq { |
| struct device *dev; |
| --- a/drivers/base/power/wakeirq.c |
| +++ b/drivers/base/power/wakeirq.c |
| @@ -314,8 +314,10 @@ void dev_pm_enable_wake_irq_check(struct |
| return; |
| |
| enable: |
| - if (!can_change_status || !(wirq->status & WAKE_IRQ_DEDICATED_REVERSE)) |
| + if (!can_change_status || !(wirq->status & WAKE_IRQ_DEDICATED_REVERSE)) { |
| enable_irq(wirq->irq); |
| + wirq->status |= WAKE_IRQ_DEDICATED_ENABLED; |
| + } |
| } |
| |
| /** |
| @@ -336,8 +338,10 @@ void dev_pm_disable_wake_irq_check(struc |
| if (cond_disable && (wirq->status & WAKE_IRQ_DEDICATED_REVERSE)) |
| return; |
| |
| - if (wirq->status & WAKE_IRQ_DEDICATED_MANAGED) |
| + if (wirq->status & WAKE_IRQ_DEDICATED_MANAGED) { |
| + wirq->status &= ~WAKE_IRQ_DEDICATED_ENABLED; |
| disable_irq_nosync(wirq->irq); |
| + } |
| } |
| |
| /** |
| @@ -376,7 +380,7 @@ void dev_pm_arm_wake_irq(struct wake_irq |
| |
| if (device_may_wakeup(wirq->dev)) { |
| if (wirq->status & WAKE_IRQ_DEDICATED_ALLOCATED && |
| - !pm_runtime_status_suspended(wirq->dev)) |
| + !(wirq->status & WAKE_IRQ_DEDICATED_ENABLED)) |
| enable_irq(wirq->irq); |
| |
| enable_irq_wake(wirq->irq); |
| @@ -399,7 +403,7 @@ void dev_pm_disarm_wake_irq(struct wake_ |
| disable_irq_wake(wirq->irq); |
| |
| if (wirq->status & WAKE_IRQ_DEDICATED_ALLOCATED && |
| - !pm_runtime_status_suspended(wirq->dev)) |
| + !(wirq->status & WAKE_IRQ_DEDICATED_ENABLED)) |
| disable_irq_nosync(wirq->irq); |
| } |
| } |