Skip to contentSkip to conversation

Patch "PM / wakeirq: Fix dedicated wakeirq for drivers not using autosuspend" has been added to the 4.9-stable tree

PATCH [email protected] 1 participant 1 message Jan 9, 2017

Subsystems (5)
lore
Share & tools
lore

[email protected]

author maintainer Applied
#0 lore raw

This is a note to let you know that I've just added the patch titled

PM / wakeirq: Fix dedicated wakeirq for drivers not using autosuspend

to the 4.9-stable tree which can be found at:
http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
pm-wakeirq-fix-dedicated-wakeirq-for-drivers-not-using-autosuspend.patch
and it can be found in the queue-4.9 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree, please let <[email protected]> know about it.

Quoted 1 line

From bed570307ed78f21b77cb04a1df781dee4a8f05a Mon Sep 17 00:00:00 2001

From: Tony Lindgren <[email protected]>
Date: Mon, 5 Dec 2016 16:38:16 -0800
Subject: PM / wakeirq: Fix dedicated wakeirq for drivers not using autosuspend

From: Tony Lindgren <[email protected]>

commit bed570307ed78f21b77cb04a1df781dee4a8f05a upstream.

I noticed some wakeirq flakeyness with consumer drivers not using autosuspend. For drivers not using autosuspend, the wakeirq may never get unmasked in rpm_suspend() because of irq desc->depth.

We are configuring dedicated wakeirqs to start with IRQ_NOAUTOEN as we naturally don't want them running until rpm_suspend() is called.

However, when a consumer driver initially calls pm_runtime_get(), we now wrongly start with disable_irq_nosync() call on the dedicated wakeirq that is disabled to start with.

This causes desc->depth to toggle between 1 and 2 instead of the usual 0 and 1. This can prevent enable_irq() from unmasking the wakeirq as that only happens at desc->depth 1.

This does not necessarily show up with drivers using autosuspend as there is time for disable_irq_nosync() before rpm_suspend() gets called after the autosuspend timeout.

Let's fix the issue by adding wirq->status that lazily gets set on the first rpm_suspend(). We also need PM runtime core private functions for dev_pm_enable_wake_irq_check() and dev_pm_disable_wake_irq_check() so we can enable the dedicated wakeirq on the first rpm_suspend().

While at it, let's also fix the comments for dev_pm_enable_wake_irq() and dev_pm_disable_wake_irq(). Those can still be used by the consumer drivers as needed because the IRQ core manages the interrupt usecount for us.

Fixes 4990d4fe327b (PM / Wakeirq: Add automated device wake IRQ handling)
---
 drivers/base/power/power.h   |   19 ++++++++++
 drivers/base/power/runtime.c |    8 ++--
 drivers/base/power/wakeirq.c |   76 +++++++++++++++++++++++++++++++++++++------
 3 files changed, 88 insertions(+), 15 deletions(-)
drivers/base/power/power.h +18 -1
@@ -21,14 +21,22 @@ extern void pm_runtime_init(struct devic
 extern void pm_runtime_reinit(struct device *dev);
 extern void pm_runtime_remove(struct device *dev);
 
+#define WAKE_IRQ_DEDICATED_ALLOCATED	BIT(0)
+#define WAKE_IRQ_DEDICATED_MANAGED	BIT(1)
+#define WAKE_IRQ_DEDICATED_MASK		(WAKE_IRQ_DEDICATED_ALLOCATED | \
+					 WAKE_IRQ_DEDICATED_MANAGED)
+
 struct wake_irq {
 	struct device *dev;
+	unsigned int status;
 	int irq;
-	bool dedicated_irq:1;
 };
 
 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);
 
 #ifdef CONFIG_PM_SLEEP
 
@@ -104,6 +112,15 @@ static inline void dev_pm_disarm_wake_ir
 {
 }
 
+static inline void dev_pm_enable_wake_irq_check(struct device *dev,
+						bool can_change_status)
+{
+}
+
+static inline void dev_pm_disable_wake_irq_check(struct device *dev)
+{
+}
+
 #endif
 
 #ifdef CONFIG_PM_SLEEP
drivers/base/power/runtime.c +4 -4
@@ -515,7 +515,7 @@ static int rpm_suspend(struct device *de
 
 	callback = RPM_GET_CALLBACK(dev, runtime_suspend);
 
-	dev_pm_enable_wake_irq(dev);
+	dev_pm_enable_wake_irq_check(dev, true);
 	retval = rpm_callback(callback, dev);
 	if (retval)
 		goto fail;
@@ -554,7 +554,7 @@ static int rpm_suspend(struct device *de
 	return retval;
 
  fail:
-	dev_pm_disable_wake_irq(dev);
+	dev_pm_disable_wake_irq_check(dev);
 	__update_runtime_status(dev, RPM_ACTIVE);
 	dev->power.deferred_resume = false;
 	wake_up_all(&dev->power.wait_queue);
@@ -737,12 +737,12 @@ static int rpm_resume(struct device *dev
 
 	callback = RPM_GET_CALLBACK(dev, runtime_resume);
 
-	dev_pm_disable_wake_irq(dev);
+	dev_pm_disable_wake_irq_check(dev);
 	retval = rpm_callback(callback, dev);
 	if (retval) {
 		__update_runtime_status(dev, RPM_SUSPENDED);
 		pm_runtime_cancel_pending(dev);
-		dev_pm_enable_wake_irq(dev);
+		dev_pm_enable_wake_irq_check(dev, false);
 	} else {
  no_callback:
 		__update_runtime_status(dev, RPM_ACTIVE);
drivers/base/power/wakeirq.c +66 -10

123 lines not on this page · raw message

Patches currently in stable-queue which might be from [email protected] are

queue-4.9/pm-wakeirq-fix-dedicated-wakeirq-for-drivers-not-using-autosuspend.patch queue-4.9/usb-musb-fix-trying-to-free-already-free-irq-4.patch