2019-05-27 14:55:05 +08:00
|
|
|
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
2008-03-20 05:39:13 +08:00
|
|
|
/*
|
|
|
|
* pm_wakeup.h - Power management wakeup interface
|
|
|
|
*
|
|
|
|
* Copyright (C) 2008 Alan Stern
|
2010-09-23 04:09:10 +08:00
|
|
|
* Copyright (C) 2010 Rafael J. Wysocki, Novell Inc.
|
2008-03-20 05:39:13 +08:00
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef _LINUX_PM_WAKEUP_H
|
|
|
|
#define _LINUX_PM_WAKEUP_H
|
|
|
|
|
|
|
|
#ifndef _DEVICE_H_
|
|
|
|
# error "please don't include this file directly"
|
|
|
|
#endif
|
|
|
|
|
2010-03-16 04:44:41 +08:00
|
|
|
#include <linux/types.h>
|
|
|
|
|
PM / Wakeirq: Add automated device wake IRQ handling
Turns out we can automate the handling for the device_may_wakeup()
quite a bit by using the kernel wakeup source list as suggested
by Rafael J. Wysocki <rjw@rjwysocki.net>.
And as some hardware has separate dedicated wake-up interrupt
in addition to the IO interrupt, we can automate the handling by
adding a generic threaded interrupt handler that just calls the
device PM runtime to wake up the device.
This allows dropping code from device drivers as we currently
are doing it in multiple ways, and often wrong.
For most drivers, we should be able to drop the following
boilerplate code from runtime_suspend and runtime_resume
functions:
...
device_init_wakeup(dev, true);
...
if (device_may_wakeup(dev))
enable_irq_wake(irq);
...
if (device_may_wakeup(dev))
disable_irq_wake(irq);
...
device_init_wakeup(dev, false);
...
We can replace it with just the following init and exit
time code:
...
device_init_wakeup(dev, true);
dev_pm_set_wake_irq(dev, irq);
...
dev_pm_clear_wake_irq(dev);
device_init_wakeup(dev, false);
...
And for hardware with dedicated wake-up interrupts:
...
device_init_wakeup(dev, true);
dev_pm_set_dedicated_wake_irq(dev, irq);
...
dev_pm_clear_wake_irq(dev);
device_init_wakeup(dev, false);
...
Signed-off-by: Tony Lindgren <tony@atomide.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2015-05-19 06:40:29 +08:00
|
|
|
struct wake_irq;
|
|
|
|
|
2010-09-23 04:09:10 +08:00
|
|
|
/**
|
|
|
|
* struct wakeup_source - Representation of wakeup sources
|
2010-06-13 06:36:52 +08:00
|
|
|
*
|
PM / Wakeirq: Add automated device wake IRQ handling
Turns out we can automate the handling for the device_may_wakeup()
quite a bit by using the kernel wakeup source list as suggested
by Rafael J. Wysocki <rjw@rjwysocki.net>.
And as some hardware has separate dedicated wake-up interrupt
in addition to the IO interrupt, we can automate the handling by
adding a generic threaded interrupt handler that just calls the
device PM runtime to wake up the device.
This allows dropping code from device drivers as we currently
are doing it in multiple ways, and often wrong.
For most drivers, we should be able to drop the following
boilerplate code from runtime_suspend and runtime_resume
functions:
...
device_init_wakeup(dev, true);
...
if (device_may_wakeup(dev))
enable_irq_wake(irq);
...
if (device_may_wakeup(dev))
disable_irq_wake(irq);
...
device_init_wakeup(dev, false);
...
We can replace it with just the following init and exit
time code:
...
device_init_wakeup(dev, true);
dev_pm_set_wake_irq(dev, irq);
...
dev_pm_clear_wake_irq(dev);
device_init_wakeup(dev, false);
...
And for hardware with dedicated wake-up interrupts:
...
device_init_wakeup(dev, true);
dev_pm_set_dedicated_wake_irq(dev, irq);
...
dev_pm_clear_wake_irq(dev);
device_init_wakeup(dev, false);
...
Signed-off-by: Tony Lindgren <tony@atomide.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2015-05-19 06:40:29 +08:00
|
|
|
* @name: Name of the wakeup source
|
2019-08-07 09:48:46 +08:00
|
|
|
* @id: Wakeup source id
|
PM / Wakeirq: Add automated device wake IRQ handling
Turns out we can automate the handling for the device_may_wakeup()
quite a bit by using the kernel wakeup source list as suggested
by Rafael J. Wysocki <rjw@rjwysocki.net>.
And as some hardware has separate dedicated wake-up interrupt
in addition to the IO interrupt, we can automate the handling by
adding a generic threaded interrupt handler that just calls the
device PM runtime to wake up the device.
This allows dropping code from device drivers as we currently
are doing it in multiple ways, and often wrong.
For most drivers, we should be able to drop the following
boilerplate code from runtime_suspend and runtime_resume
functions:
...
device_init_wakeup(dev, true);
...
if (device_may_wakeup(dev))
enable_irq_wake(irq);
...
if (device_may_wakeup(dev))
disable_irq_wake(irq);
...
device_init_wakeup(dev, false);
...
We can replace it with just the following init and exit
time code:
...
device_init_wakeup(dev, true);
dev_pm_set_wake_irq(dev, irq);
...
dev_pm_clear_wake_irq(dev);
device_init_wakeup(dev, false);
...
And for hardware with dedicated wake-up interrupts:
...
device_init_wakeup(dev, true);
dev_pm_set_dedicated_wake_irq(dev, irq);
...
dev_pm_clear_wake_irq(dev);
device_init_wakeup(dev, false);
...
Signed-off-by: Tony Lindgren <tony@atomide.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2015-05-19 06:40:29 +08:00
|
|
|
* @entry: Wakeup source list entry
|
|
|
|
* @lock: Wakeup source lock
|
|
|
|
* @wakeirq: Optional device specific wakeirq
|
|
|
|
* @timer: Wakeup timer list
|
|
|
|
* @timer_expires: Wakeup timer expiration
|
2010-09-23 04:09:10 +08:00
|
|
|
* @total_time: Total time this wakeup source has been active.
|
|
|
|
* @max_time: Maximum time this wakeup source has been continuously active.
|
2012-04-30 04:52:52 +08:00
|
|
|
* @last_time: Monotonic clock when the wakeup source's was touched last time.
|
2012-04-30 04:53:32 +08:00
|
|
|
* @prevent_sleep_time: Total time this source has been preventing autosleep.
|
2010-09-23 04:09:10 +08:00
|
|
|
* @event_count: Number of signaled wakeup events.
|
2013-07-11 12:55:58 +08:00
|
|
|
* @active_count: Number of times the wakeup source was activated.
|
|
|
|
* @relax_count: Number of times the wakeup source was deactivated.
|
2012-04-30 04:52:52 +08:00
|
|
|
* @expire_count: Number of times the wakeup source's timeout has expired.
|
|
|
|
* @wakeup_count: Number of times the wakeup source might abort suspend.
|
2019-08-07 09:48:46 +08:00
|
|
|
* @dev: Struct device for sysfs statistics about the wakeup source.
|
2010-09-23 04:09:10 +08:00
|
|
|
* @active: Status of the wakeup source.
|
2019-06-19 06:48:15 +08:00
|
|
|
* @autosleep_enabled: Autosleep is active, so update @prevent_sleep_time.
|
2008-03-20 05:39:13 +08:00
|
|
|
*/
|
2010-09-23 04:09:10 +08:00
|
|
|
struct wakeup_source {
|
2012-02-22 06:47:56 +08:00
|
|
|
const char *name;
|
2019-08-07 09:48:46 +08:00
|
|
|
int id;
|
2010-09-23 04:09:10 +08:00
|
|
|
struct list_head entry;
|
|
|
|
spinlock_t lock;
|
PM / Wakeirq: Add automated device wake IRQ handling
Turns out we can automate the handling for the device_may_wakeup()
quite a bit by using the kernel wakeup source list as suggested
by Rafael J. Wysocki <rjw@rjwysocki.net>.
And as some hardware has separate dedicated wake-up interrupt
in addition to the IO interrupt, we can automate the handling by
adding a generic threaded interrupt handler that just calls the
device PM runtime to wake up the device.
This allows dropping code from device drivers as we currently
are doing it in multiple ways, and often wrong.
For most drivers, we should be able to drop the following
boilerplate code from runtime_suspend and runtime_resume
functions:
...
device_init_wakeup(dev, true);
...
if (device_may_wakeup(dev))
enable_irq_wake(irq);
...
if (device_may_wakeup(dev))
disable_irq_wake(irq);
...
device_init_wakeup(dev, false);
...
We can replace it with just the following init and exit
time code:
...
device_init_wakeup(dev, true);
dev_pm_set_wake_irq(dev, irq);
...
dev_pm_clear_wake_irq(dev);
device_init_wakeup(dev, false);
...
And for hardware with dedicated wake-up interrupts:
...
device_init_wakeup(dev, true);
dev_pm_set_dedicated_wake_irq(dev, irq);
...
dev_pm_clear_wake_irq(dev);
device_init_wakeup(dev, false);
...
Signed-off-by: Tony Lindgren <tony@atomide.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2015-05-19 06:40:29 +08:00
|
|
|
struct wake_irq *wakeirq;
|
2010-09-23 04:09:10 +08:00
|
|
|
struct timer_list timer;
|
|
|
|
unsigned long timer_expires;
|
|
|
|
ktime_t total_time;
|
|
|
|
ktime_t max_time;
|
|
|
|
ktime_t last_time;
|
2012-04-30 04:53:32 +08:00
|
|
|
ktime_t start_prevent_time;
|
|
|
|
ktime_t prevent_sleep_time;
|
2010-09-23 04:09:10 +08:00
|
|
|
unsigned long event_count;
|
|
|
|
unsigned long active_count;
|
|
|
|
unsigned long relax_count;
|
2012-04-30 04:52:52 +08:00
|
|
|
unsigned long expire_count;
|
|
|
|
unsigned long wakeup_count;
|
2019-08-07 09:48:46 +08:00
|
|
|
struct device *dev;
|
2012-04-30 04:52:52 +08:00
|
|
|
bool active:1;
|
2012-04-30 04:53:32 +08:00
|
|
|
bool autosleep_enabled:1;
|
2010-09-23 04:09:10 +08:00
|
|
|
};
|
|
|
|
|
2019-10-24 17:26:42 +08:00
|
|
|
#define for_each_wakeup_source(ws) \
|
|
|
|
for ((ws) = wakeup_sources_walk_start(); \
|
|
|
|
(ws); \
|
|
|
|
(ws) = wakeup_sources_walk_next((ws)))
|
|
|
|
|
2010-09-23 04:09:10 +08:00
|
|
|
#ifdef CONFIG_PM_SLEEP
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Changes to device_may_wakeup take effect on the next pm state change.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static inline bool device_can_wakeup(struct device *dev)
|
|
|
|
{
|
|
|
|
return dev->power.can_wakeup;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool device_may_wakeup(struct device *dev)
|
2008-03-20 05:39:13 +08:00
|
|
|
{
|
2010-09-23 04:09:10 +08:00
|
|
|
return dev->power.can_wakeup && !!dev->power.wakeup;
|
2008-03-20 05:39:13 +08:00
|
|
|
}
|
|
|
|
|
2020-11-19 15:25:39 +08:00
|
|
|
static inline bool device_wakeup_path(struct device *dev)
|
|
|
|
{
|
|
|
|
return dev->power.wakeup_path;
|
|
|
|
}
|
|
|
|
|
PM / wakeup: Add device_set_wakeup_path() helper to control wakeup path
During system suspend, a driver may find that the wakeup setting is
enabled for its device and therefore configures it to deliver system
wakeup signals.
Additionally, sometimes the driver and its device, relies on some
further consumed resource, like an irqchip or a phy for example, to
stay powered on, as to be able to deliver system wakeup signals.
In general the driver deals with this, via raising an "enable count"
of the consumed resource or via a subsystem specific API, like
irq_set_irq_wake() or enable|disable_irq_wake() for an irqchip.
However, this may not be sufficient in cases when the resource's
device may be attached to a PM domain (genpd for example) or is
handled by a non-trivial middle layer (PCI for example).
To address cases like these, the existing ->dev.power.wakeup_path
status flag is there to help. As a matter of fact, genpd already
monitors the flag during system suspend and acts accordingly.
However, so far it has not been clear, if anybody else but the PM
core is allowed to set the ->dev.power.wakeup_path status flag,
which is required to make this work. For this reason, introduce
a new helper function, device_set_wakeup_path() for that.
Typically, a driver that manages a resource needed in the wakeup path
should call device_set_wakeup_path() from its ->suspend() or
->suspend_late() callback.
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2018-01-03 00:08:52 +08:00
|
|
|
static inline void device_set_wakeup_path(struct device *dev)
|
|
|
|
{
|
|
|
|
dev->power.wakeup_path = true;
|
|
|
|
}
|
|
|
|
|
2010-09-23 04:09:10 +08:00
|
|
|
/* drivers/base/power/wakeup.c */
|
|
|
|
extern struct wakeup_source *wakeup_source_create(const char *name);
|
|
|
|
extern void wakeup_source_destroy(struct wakeup_source *ws);
|
|
|
|
extern void wakeup_source_add(struct wakeup_source *ws);
|
|
|
|
extern void wakeup_source_remove(struct wakeup_source *ws);
|
2019-08-07 09:48:46 +08:00
|
|
|
extern struct wakeup_source *wakeup_source_register(struct device *dev,
|
|
|
|
const char *name);
|
2010-09-23 04:09:10 +08:00
|
|
|
extern void wakeup_source_unregister(struct wakeup_source *ws);
|
2019-10-24 17:26:42 +08:00
|
|
|
extern int wakeup_sources_read_lock(void);
|
|
|
|
extern void wakeup_sources_read_unlock(int idx);
|
|
|
|
extern struct wakeup_source *wakeup_sources_walk_start(void);
|
|
|
|
extern struct wakeup_source *wakeup_sources_walk_next(struct wakeup_source *ws);
|
2010-09-23 04:09:10 +08:00
|
|
|
extern int device_wakeup_enable(struct device *dev);
|
|
|
|
extern int device_wakeup_disable(struct device *dev);
|
2011-02-09 06:26:02 +08:00
|
|
|
extern void device_set_wakeup_capable(struct device *dev, bool capable);
|
2010-09-23 04:09:10 +08:00
|
|
|
extern int device_init_wakeup(struct device *dev, bool val);
|
|
|
|
extern int device_set_wakeup_enable(struct device *dev, bool enable);
|
|
|
|
extern void __pm_stay_awake(struct wakeup_source *ws);
|
|
|
|
extern void pm_stay_awake(struct device *dev);
|
|
|
|
extern void __pm_relax(struct wakeup_source *ws);
|
|
|
|
extern void pm_relax(struct device *dev);
|
PM / wakeup: Integrate mechanism to abort transitions in progress
The system wakeup framework is not very consistent with respect to
the way it handles suspend-to-idle and generally wakeup events
occurring during transitions to system low-power states.
First off, system transitions in progress are aborted by the event
reporting helpers like pm_wakeup_event() only if the wakeup_count
sysfs attribute is in use (as documented), but there are cases in
which system-wide transitions should be aborted even if that is
not the case. For example, a wakeup signal from a designated
wakeup device during system-wide PM transition, it should cause
the transition to be aborted right away.
Moreover, there is a freeze_wake() call in wakeup_source_activate(),
but that really is only effective after suspend_freeze_state has
been set to FREEZE_STATE_ENTER by freeze_enter(). However, it
is very unlikely that wakeup_source_activate() will ever be called
at that time, as it could only be triggered by a IRQF_NO_SUSPEND
interrupt handler, so wakeups from suspend-to-idle don't really
occur in wakeup_source_activate().
At the same time there is a way to abort a system suspend in
progress (or wake up the system from suspend-to-idle), which is by
calling pm_system_wakeup(), but in turn that doesn't cause any
wakeup source objects to be activated, so it will not be covered
by wakeup source statistics and will not prevent the system from
suspending again immediately (in case autosleep is used, for
example). Consequently, if anyone wants to abort system transitions
in progress and allow the wakeup_count mechanism to work, they need
to use both pm_system_wakeup() and pm_wakeup_event(), say, at the
same time which is awkward.
For the above reasons, make it possible to trigger
pm_system_wakeup() from within wakeup_source_activate() and
provide a new pm_wakeup_hard_event() helper to do so within the
wakeup framework.
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2017-04-27 05:22:09 +08:00
|
|
|
extern void pm_wakeup_ws_event(struct wakeup_source *ws, unsigned int msec, bool hard);
|
|
|
|
extern void pm_wakeup_dev_event(struct device *dev, unsigned int msec, bool hard);
|
2010-09-23 04:09:10 +08:00
|
|
|
|
|
|
|
#else /* !CONFIG_PM_SLEEP */
|
|
|
|
|
2010-03-16 04:44:41 +08:00
|
|
|
static inline void device_set_wakeup_capable(struct device *dev, bool capable)
|
2008-07-07 09:34:48 +08:00
|
|
|
{
|
2010-03-16 04:44:41 +08:00
|
|
|
dev->power.can_wakeup = capable;
|
2008-07-07 09:34:48 +08:00
|
|
|
}
|
|
|
|
|
2010-03-16 04:44:41 +08:00
|
|
|
static inline bool device_can_wakeup(struct device *dev)
|
2008-03-20 05:39:13 +08:00
|
|
|
{
|
|
|
|
return dev->power.can_wakeup;
|
|
|
|
}
|
|
|
|
|
2010-09-23 04:09:10 +08:00
|
|
|
static inline struct wakeup_source *wakeup_source_create(const char *name)
|
2008-03-20 05:39:13 +08:00
|
|
|
{
|
2010-09-23 04:09:10 +08:00
|
|
|
return NULL;
|
2008-03-20 05:39:13 +08:00
|
|
|
}
|
|
|
|
|
2010-09-23 04:09:10 +08:00
|
|
|
static inline void wakeup_source_destroy(struct wakeup_source *ws) {}
|
|
|
|
|
|
|
|
static inline void wakeup_source_add(struct wakeup_source *ws) {}
|
2008-03-20 05:39:13 +08:00
|
|
|
|
2010-09-23 04:09:10 +08:00
|
|
|
static inline void wakeup_source_remove(struct wakeup_source *ws) {}
|
|
|
|
|
2019-08-07 09:48:46 +08:00
|
|
|
static inline struct wakeup_source *wakeup_source_register(struct device *dev,
|
|
|
|
const char *name)
|
2008-03-20 05:39:13 +08:00
|
|
|
{
|
2010-09-23 04:09:10 +08:00
|
|
|
return NULL;
|
2008-03-20 05:39:13 +08:00
|
|
|
}
|
|
|
|
|
2010-09-23 04:09:10 +08:00
|
|
|
static inline void wakeup_source_unregister(struct wakeup_source *ws) {}
|
|
|
|
|
|
|
|
static inline int device_wakeup_enable(struct device *dev)
|
2010-03-16 04:44:41 +08:00
|
|
|
{
|
2011-02-24 18:10:01 +08:00
|
|
|
dev->power.should_wakeup = true;
|
|
|
|
return 0;
|
2010-03-16 04:44:41 +08:00
|
|
|
}
|
2008-07-10 08:16:44 +08:00
|
|
|
|
2010-09-23 04:09:10 +08:00
|
|
|
static inline int device_wakeup_disable(struct device *dev)
|
2008-03-20 05:39:13 +08:00
|
|
|
{
|
2011-02-24 18:10:01 +08:00
|
|
|
dev->power.should_wakeup = false;
|
2010-09-23 04:09:10 +08:00
|
|
|
return 0;
|
2008-03-20 05:39:13 +08:00
|
|
|
}
|
|
|
|
|
2011-02-24 18:10:01 +08:00
|
|
|
static inline int device_set_wakeup_enable(struct device *dev, bool enable)
|
2010-03-16 04:44:41 +08:00
|
|
|
{
|
2011-02-24 18:10:01 +08:00
|
|
|
dev->power.should_wakeup = enable;
|
|
|
|
return 0;
|
2010-03-16 04:44:41 +08:00
|
|
|
}
|
|
|
|
|
2011-02-24 18:10:01 +08:00
|
|
|
static inline int device_init_wakeup(struct device *dev, bool val)
|
|
|
|
{
|
|
|
|
device_set_wakeup_capable(dev, val);
|
|
|
|
device_set_wakeup_enable(dev, val);
|
|
|
|
return 0;
|
|
|
|
}
|
2010-09-23 04:09:10 +08:00
|
|
|
|
2011-02-24 18:10:01 +08:00
|
|
|
static inline bool device_may_wakeup(struct device *dev)
|
2010-03-16 04:44:41 +08:00
|
|
|
{
|
2011-02-24 18:10:01 +08:00
|
|
|
return dev->power.can_wakeup && dev->power.should_wakeup;
|
2010-03-16 04:44:41 +08:00
|
|
|
}
|
2008-03-20 05:39:13 +08:00
|
|
|
|
2020-11-19 15:25:39 +08:00
|
|
|
static inline bool device_wakeup_path(struct device *dev)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
PM / wakeup: Add device_set_wakeup_path() helper to control wakeup path
During system suspend, a driver may find that the wakeup setting is
enabled for its device and therefore configures it to deliver system
wakeup signals.
Additionally, sometimes the driver and its device, relies on some
further consumed resource, like an irqchip or a phy for example, to
stay powered on, as to be able to deliver system wakeup signals.
In general the driver deals with this, via raising an "enable count"
of the consumed resource or via a subsystem specific API, like
irq_set_irq_wake() or enable|disable_irq_wake() for an irqchip.
However, this may not be sufficient in cases when the resource's
device may be attached to a PM domain (genpd for example) or is
handled by a non-trivial middle layer (PCI for example).
To address cases like these, the existing ->dev.power.wakeup_path
status flag is there to help. As a matter of fact, genpd already
monitors the flag during system suspend and acts accordingly.
However, so far it has not been clear, if anybody else but the PM
core is allowed to set the ->dev.power.wakeup_path status flag,
which is required to make this work. For this reason, introduce
a new helper function, device_set_wakeup_path() for that.
Typically, a driver that manages a resource needed in the wakeup path
should call device_set_wakeup_path() from its ->suspend() or
->suspend_late() callback.
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2018-01-03 00:08:52 +08:00
|
|
|
static inline void device_set_wakeup_path(struct device *dev) {}
|
|
|
|
|
2010-09-23 04:09:10 +08:00
|
|
|
static inline void __pm_stay_awake(struct wakeup_source *ws) {}
|
|
|
|
|
|
|
|
static inline void pm_stay_awake(struct device *dev) {}
|
|
|
|
|
|
|
|
static inline void __pm_relax(struct wakeup_source *ws) {}
|
|
|
|
|
|
|
|
static inline void pm_relax(struct device *dev) {}
|
|
|
|
|
PM / wakeup: Integrate mechanism to abort transitions in progress
The system wakeup framework is not very consistent with respect to
the way it handles suspend-to-idle and generally wakeup events
occurring during transitions to system low-power states.
First off, system transitions in progress are aborted by the event
reporting helpers like pm_wakeup_event() only if the wakeup_count
sysfs attribute is in use (as documented), but there are cases in
which system-wide transitions should be aborted even if that is
not the case. For example, a wakeup signal from a designated
wakeup device during system-wide PM transition, it should cause
the transition to be aborted right away.
Moreover, there is a freeze_wake() call in wakeup_source_activate(),
but that really is only effective after suspend_freeze_state has
been set to FREEZE_STATE_ENTER by freeze_enter(). However, it
is very unlikely that wakeup_source_activate() will ever be called
at that time, as it could only be triggered by a IRQF_NO_SUSPEND
interrupt handler, so wakeups from suspend-to-idle don't really
occur in wakeup_source_activate().
At the same time there is a way to abort a system suspend in
progress (or wake up the system from suspend-to-idle), which is by
calling pm_system_wakeup(), but in turn that doesn't cause any
wakeup source objects to be activated, so it will not be covered
by wakeup source statistics and will not prevent the system from
suspending again immediately (in case autosleep is used, for
example). Consequently, if anyone wants to abort system transitions
in progress and allow the wakeup_count mechanism to work, they need
to use both pm_system_wakeup() and pm_wakeup_event(), say, at the
same time which is awkward.
For the above reasons, make it possible to trigger
pm_system_wakeup() from within wakeup_source_activate() and
provide a new pm_wakeup_hard_event() helper to do so within the
wakeup framework.
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2017-04-27 05:22:09 +08:00
|
|
|
static inline void pm_wakeup_ws_event(struct wakeup_source *ws,
|
|
|
|
unsigned int msec, bool hard) {}
|
2010-09-23 04:09:10 +08:00
|
|
|
|
PM / wakeup: Integrate mechanism to abort transitions in progress
The system wakeup framework is not very consistent with respect to
the way it handles suspend-to-idle and generally wakeup events
occurring during transitions to system low-power states.
First off, system transitions in progress are aborted by the event
reporting helpers like pm_wakeup_event() only if the wakeup_count
sysfs attribute is in use (as documented), but there are cases in
which system-wide transitions should be aborted even if that is
not the case. For example, a wakeup signal from a designated
wakeup device during system-wide PM transition, it should cause
the transition to be aborted right away.
Moreover, there is a freeze_wake() call in wakeup_source_activate(),
but that really is only effective after suspend_freeze_state has
been set to FREEZE_STATE_ENTER by freeze_enter(). However, it
is very unlikely that wakeup_source_activate() will ever be called
at that time, as it could only be triggered by a IRQF_NO_SUSPEND
interrupt handler, so wakeups from suspend-to-idle don't really
occur in wakeup_source_activate().
At the same time there is a way to abort a system suspend in
progress (or wake up the system from suspend-to-idle), which is by
calling pm_system_wakeup(), but in turn that doesn't cause any
wakeup source objects to be activated, so it will not be covered
by wakeup source statistics and will not prevent the system from
suspending again immediately (in case autosleep is used, for
example). Consequently, if anyone wants to abort system transitions
in progress and allow the wakeup_count mechanism to work, they need
to use both pm_system_wakeup() and pm_wakeup_event(), say, at the
same time which is awkward.
For the above reasons, make it possible to trigger
pm_system_wakeup() from within wakeup_source_activate() and
provide a new pm_wakeup_hard_event() helper to do so within the
wakeup framework.
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2017-04-27 05:22:09 +08:00
|
|
|
static inline void pm_wakeup_dev_event(struct device *dev, unsigned int msec,
|
|
|
|
bool hard) {}
|
2010-09-23 04:09:10 +08:00
|
|
|
|
|
|
|
#endif /* !CONFIG_PM_SLEEP */
|
2008-03-20 05:39:13 +08:00
|
|
|
|
PM / wakeup: Integrate mechanism to abort transitions in progress
The system wakeup framework is not very consistent with respect to
the way it handles suspend-to-idle and generally wakeup events
occurring during transitions to system low-power states.
First off, system transitions in progress are aborted by the event
reporting helpers like pm_wakeup_event() only if the wakeup_count
sysfs attribute is in use (as documented), but there are cases in
which system-wide transitions should be aborted even if that is
not the case. For example, a wakeup signal from a designated
wakeup device during system-wide PM transition, it should cause
the transition to be aborted right away.
Moreover, there is a freeze_wake() call in wakeup_source_activate(),
but that really is only effective after suspend_freeze_state has
been set to FREEZE_STATE_ENTER by freeze_enter(). However, it
is very unlikely that wakeup_source_activate() will ever be called
at that time, as it could only be triggered by a IRQF_NO_SUSPEND
interrupt handler, so wakeups from suspend-to-idle don't really
occur in wakeup_source_activate().
At the same time there is a way to abort a system suspend in
progress (or wake up the system from suspend-to-idle), which is by
calling pm_system_wakeup(), but in turn that doesn't cause any
wakeup source objects to be activated, so it will not be covered
by wakeup source statistics and will not prevent the system from
suspending again immediately (in case autosleep is used, for
example). Consequently, if anyone wants to abort system transitions
in progress and allow the wakeup_count mechanism to work, they need
to use both pm_system_wakeup() and pm_wakeup_event(), say, at the
same time which is awkward.
For the above reasons, make it possible to trigger
pm_system_wakeup() from within wakeup_source_activate() and
provide a new pm_wakeup_hard_event() helper to do so within the
wakeup framework.
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2017-04-27 05:22:09 +08:00
|
|
|
static inline void __pm_wakeup_event(struct wakeup_source *ws, unsigned int msec)
|
|
|
|
{
|
|
|
|
return pm_wakeup_ws_event(ws, msec, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void pm_wakeup_event(struct device *dev, unsigned int msec)
|
|
|
|
{
|
|
|
|
return pm_wakeup_dev_event(dev, msec, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void pm_wakeup_hard_event(struct device *dev)
|
|
|
|
{
|
|
|
|
return pm_wakeup_dev_event(dev, 0, true);
|
|
|
|
}
|
|
|
|
|
2008-03-20 05:39:13 +08:00
|
|
|
#endif /* _LINUX_PM_WAKEUP_H */
|