2019-10-09 18:31:19

by Tony Lindgren

[permalink] [raw]
Subject: [PATCH] PM / runtime: Add support for wake-up reason for wakeirqs

With generic wakeirqs we can wake a device, but do not know if the
device woke to a wakeirq. Let's add pm_runtime_wakeup_is_wakeirq() so
a device can check the wake-up reason.

This can used for cases where a device wakes up on its own to a
wake-up interrupt, and the device PM runtime resume function can
then skip some or all of the device wake-up sequence based on
pm_runtime_wakeup_is_wakeirq().

Let's only add RPM_WAKEUP_NONE and RPM_WAKEUP_WAKEIRQ for now, other
events can be added later on if really needed.

Signed-off-by: Tony Lindgren <[email protected]>
---
drivers/base/power/wakeirq.c | 14 ++++++++++++--
include/linux/pm.h | 14 ++++++++++++++
include/linux/pm_runtime.h | 6 ++++++
3 files changed, 32 insertions(+), 2 deletions(-)

diff --git a/drivers/base/power/wakeirq.c b/drivers/base/power/wakeirq.c
--- a/drivers/base/power/wakeirq.c
+++ b/drivers/base/power/wakeirq.c
@@ -127,13 +127,18 @@ EXPORT_SYMBOL_GPL(dev_pm_clear_wake_irq);
static irqreturn_t handle_threaded_wake_irq(int irq, void *_wirq)
{
struct wake_irq *wirq = _wirq;
+ struct device *dev = wirq->dev;
+ unsigned long flags;
int res;

+ spin_lock_irqsave(&dev->power.lock, flags);
+ dev->power.wakeup_reason = RPM_WAKEUP_WAKEIRQ;
+ spin_unlock_irqrestore(&dev->power.lock, flags);
+
/* Maybe abort suspend? */
if (irqd_is_wakeup_set(irq_get_irq_data(irq))) {
pm_wakeup_event(wirq->dev, 0);
-
- return IRQ_HANDLED;
+ goto out_handled;
}

/* We don't want RPM_ASYNC or RPM_NOWAIT here */
@@ -142,6 +147,11 @@ static irqreturn_t handle_threaded_wake_irq(int irq, void *_wirq)
dev_warn(wirq->dev,
"wake IRQ with no resume: %i\n", res);

+out_handled:
+ spin_lock_irqsave(&dev->power.lock, flags);
+ dev->power.wakeup_reason = RPM_WAKEUP_NONE;
+ spin_unlock_irqrestore(&dev->power.lock, flags);
+
return IRQ_HANDLED;
}

diff --git a/include/linux/pm.h b/include/linux/pm.h
--- a/include/linux/pm.h
+++ b/include/linux/pm.h
@@ -523,6 +523,19 @@ enum rpm_request {
RPM_REQ_RESUME,
};

+/*
+ * Device run-time wake-up reason types.
+ *
+ * RPM_WAKEUP_NONE No wake-up reason
+ *
+ * RPM_WAKEUP_WAKEIRQ Wake-up to a dedicated wakeirq
+ */
+
+enum rpm_wakeup_reason {
+ RPM_WAKEUP_NONE = 0,
+ RPM_WAKEUP_WAKEIRQ,
+};
+
struct wakeup_source;
struct wake_irq;
struct pm_domain_data;
@@ -615,6 +628,7 @@ struct dev_pm_info {
unsigned int use_autosuspend:1;
unsigned int timer_autosuspends:1;
unsigned int memalloc_noio:1;
+ unsigned int wakeup_reason:1;
unsigned int links_count;
enum rpm_request request;
enum rpm_status runtime_status;
diff --git a/include/linux/pm_runtime.h b/include/linux/pm_runtime.h
--- a/include/linux/pm_runtime.h
+++ b/include/linux/pm_runtime.h
@@ -117,6 +117,11 @@ static inline bool pm_runtime_is_irq_safe(struct device *dev)
return dev->power.irq_safe;
}

+static inline bool pm_runtime_wakeup_is_wakeirq(struct device *dev)
+{
+ return dev->power.wakeup_reason == RPM_WAKEUP_WAKEIRQ;
+}
+
extern u64 pm_runtime_suspended_time(struct device *dev);

#else /* !CONFIG_PM */
@@ -183,6 +188,7 @@ static inline void pm_runtime_get_suppliers(struct device *dev) {}
static inline void pm_runtime_put_suppliers(struct device *dev) {}
static inline void pm_runtime_new_link(struct device *dev) {}
static inline void pm_runtime_drop_link(struct device *dev) {}
+static inline bool pm_runtime_wakeup_is_wakeirq(struct device *dev) { return false; }

#endif /* !CONFIG_PM */

--
2.23.0


2019-10-09 18:54:09

by Alan Stern

[permalink] [raw]
Subject: Re: [PATCH] PM / runtime: Add support for wake-up reason for wakeirqs

On Wed, 9 Oct 2019, Tony Lindgren wrote:

> With generic wakeirqs we can wake a device, but do not know if the
> device woke to a wakeirq. Let's add pm_runtime_wakeup_is_wakeirq() so
> a device can check the wake-up reason.

People have tried many times over the years to do something like this.
It's never right.

The problem is simple: It's impossible to know for certain why the
system woke up from suspend. In fact, there may be many wakeup sources
all active at the same time, and any of them could be the one
responsible for actually waking the system.

All you can do is check to see whether a particular wakeup source is
active at the present moment. You can't tell whether it was active in
the past (while the system was suspended) or whether it caused the
system to resume.

Alan Stern

2019-10-09 19:58:04

by Tony Lindgren

[permalink] [raw]
Subject: Re: [PATCH] PM / runtime: Add support for wake-up reason for wakeirqs

* Alan Stern <[email protected]> [191009 18:51]:
> On Wed, 9 Oct 2019, Tony Lindgren wrote:
>
> > With generic wakeirqs we can wake a device, but do not know if the
> > device woke to a wakeirq. Let's add pm_runtime_wakeup_is_wakeirq() so
> > a device can check the wake-up reason.
>
> People have tried many times over the years to do something like this.
> It's never right.
>
> The problem is simple: It's impossible to know for certain why the
> system woke up from suspend. In fact, there may be many wakeup sources
> all active at the same time, and any of them could be the one
> responsible for actually waking the system.

Hmm yeah good point. Even with dedicated wakeirq it could race
against a timer for the wake-up event.

> All you can do is check to see whether a particular wakeup source is
> active at the present moment. You can't tell whether it was active in
> the past (while the system was suspended) or whether it caused the
> system to resume.

We can actually do more than that now though :)

With handle_threaded_wake_irq() we could optionally call a handler
before we call pm_runtime_resume() and let the consumer device
driver figure out what the state is.

Regards,

Tony