Merge back earlier material related to system sleep
This commit is contained in:
@@ -5000,6 +5000,18 @@
|
||||
that number, otherwise (e.g., 'pmu_override=on'), MMCR1
|
||||
remains 0.
|
||||
|
||||
pm_async= [PM]
|
||||
Format: off
|
||||
This parameter sets the initial value of the
|
||||
/sys/power/pm_async sysfs knob at boot time.
|
||||
If set to "off", disables asynchronous suspend and
|
||||
resume of devices during system-wide power transitions.
|
||||
This can be useful on platforms where device
|
||||
dependencies are not well-defined, or for debugging
|
||||
power management issues. Asynchronous operations are
|
||||
enabled by default.
|
||||
|
||||
|
||||
pm_debug_messages [SUSPEND,KNL]
|
||||
Enable suspend/resume debug messages during boot up.
|
||||
|
||||
|
||||
@@ -9787,7 +9787,7 @@ F: fs/freevxfs/
|
||||
|
||||
FREEZER
|
||||
M: "Rafael J. Wysocki" <rafael@kernel.org>
|
||||
M: Pavel Machek <pavel@kernel.org>
|
||||
R: Pavel Machek <pavel@kernel.org>
|
||||
L: linux-pm@vger.kernel.org
|
||||
S: Supported
|
||||
F: Documentation/power/freezing-of-tasks.rst
|
||||
@@ -10663,7 +10663,7 @@ F: drivers/video/fbdev/hgafb.c
|
||||
|
||||
HIBERNATION (aka Software Suspend, aka swsusp)
|
||||
M: "Rafael J. Wysocki" <rafael@kernel.org>
|
||||
M: Pavel Machek <pavel@kernel.org>
|
||||
R: Pavel Machek <pavel@kernel.org>
|
||||
L: linux-pm@vger.kernel.org
|
||||
S: Supported
|
||||
B: https://bugzilla.kernel.org
|
||||
@@ -23938,8 +23938,8 @@ F: drivers/sh/
|
||||
|
||||
SUSPEND TO RAM
|
||||
M: "Rafael J. Wysocki" <rafael@kernel.org>
|
||||
M: Len Brown <len.brown@intel.com>
|
||||
M: Pavel Machek <pavel@kernel.org>
|
||||
R: Len Brown <lenb@kernel.org>
|
||||
R: Pavel Machek <pavel@kernel.org>
|
||||
L: linux-pm@vger.kernel.org
|
||||
S: Supported
|
||||
B: https://bugzilla.kernel.org
|
||||
|
||||
@@ -1119,6 +1119,8 @@ int acpi_subsys_prepare(struct device *dev)
|
||||
{
|
||||
struct acpi_device *adev = ACPI_COMPANION(dev);
|
||||
|
||||
dev_pm_set_strict_midlayer(dev, true);
|
||||
|
||||
if (dev->driver && dev->driver->pm && dev->driver->pm->prepare) {
|
||||
int ret = dev->driver->pm->prepare(dev);
|
||||
|
||||
@@ -1147,6 +1149,8 @@ void acpi_subsys_complete(struct device *dev)
|
||||
*/
|
||||
if (pm_runtime_suspended(dev) && pm_resume_via_firmware())
|
||||
pm_request_resume(dev);
|
||||
|
||||
dev_pm_set_strict_midlayer(dev, false);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(acpi_subsys_complete);
|
||||
|
||||
|
||||
@@ -647,14 +647,27 @@ static void dpm_async_resume_children(struct device *dev, async_func_t func)
|
||||
/*
|
||||
* Start processing "async" children of the device unless it's been
|
||||
* started already for them.
|
||||
*
|
||||
* This could have been done for the device's "async" consumers too, but
|
||||
* they either need to wait for their parents or the processing has
|
||||
* already started for them after their parents were processed.
|
||||
*/
|
||||
device_for_each_child(dev, func, dpm_async_with_cleanup);
|
||||
}
|
||||
|
||||
static void dpm_async_resume_subordinate(struct device *dev, async_func_t func)
|
||||
{
|
||||
struct device_link *link;
|
||||
int idx;
|
||||
|
||||
dpm_async_resume_children(dev, func);
|
||||
|
||||
idx = device_links_read_lock();
|
||||
|
||||
/* Start processing the device's "async" consumers. */
|
||||
list_for_each_entry_rcu(link, &dev->links.consumers, s_node)
|
||||
if (READ_ONCE(link->status) != DL_STATE_DORMANT)
|
||||
dpm_async_with_cleanup(link->consumer, func);
|
||||
|
||||
device_links_read_unlock(idx);
|
||||
}
|
||||
|
||||
static void dpm_clear_async_state(struct device *dev)
|
||||
{
|
||||
reinit_completion(&dev->power.completion);
|
||||
@@ -663,7 +676,14 @@ static void dpm_clear_async_state(struct device *dev)
|
||||
|
||||
static bool dpm_root_device(struct device *dev)
|
||||
{
|
||||
return !dev->parent;
|
||||
lockdep_assert_held(&dpm_list_mtx);
|
||||
|
||||
/*
|
||||
* Since this function is required to run under dpm_list_mtx, the
|
||||
* list_empty() below will only return true if the device's list of
|
||||
* consumers is actually empty before calling it.
|
||||
*/
|
||||
return !dev->parent && list_empty(&dev->links.suppliers);
|
||||
}
|
||||
|
||||
static void async_resume_noirq(void *data, async_cookie_t cookie);
|
||||
@@ -752,7 +772,7 @@ Out:
|
||||
pm_dev_err(dev, state, async ? " async noirq" : " noirq", error);
|
||||
}
|
||||
|
||||
dpm_async_resume_children(dev, async_resume_noirq);
|
||||
dpm_async_resume_subordinate(dev, async_resume_noirq);
|
||||
}
|
||||
|
||||
static void async_resume_noirq(void *data, async_cookie_t cookie)
|
||||
@@ -895,7 +915,7 @@ Out:
|
||||
pm_dev_err(dev, state, async ? " async early" : " early", error);
|
||||
}
|
||||
|
||||
dpm_async_resume_children(dev, async_resume_early);
|
||||
dpm_async_resume_subordinate(dev, async_resume_early);
|
||||
}
|
||||
|
||||
static void async_resume_early(void *data, async_cookie_t cookie)
|
||||
@@ -1071,7 +1091,7 @@ static void device_resume(struct device *dev, pm_message_t state, bool async)
|
||||
pm_dev_err(dev, state, async ? " async" : "", error);
|
||||
}
|
||||
|
||||
dpm_async_resume_children(dev, async_resume);
|
||||
dpm_async_resume_subordinate(dev, async_resume);
|
||||
}
|
||||
|
||||
static void async_resume(void *data, async_cookie_t cookie)
|
||||
@@ -1095,7 +1115,6 @@ void dpm_resume(pm_message_t state)
|
||||
ktime_t starttime = ktime_get();
|
||||
|
||||
trace_suspend_resume(TPS("dpm_resume"), state.event, true);
|
||||
might_sleep();
|
||||
|
||||
pm_transition = state;
|
||||
async_error = 0;
|
||||
@@ -1198,7 +1217,6 @@ void dpm_complete(pm_message_t state)
|
||||
struct list_head list;
|
||||
|
||||
trace_suspend_resume(TPS("dpm_complete"), state.event, true);
|
||||
might_sleep();
|
||||
|
||||
INIT_LIST_HEAD(&list);
|
||||
mutex_lock(&dpm_list_mtx);
|
||||
@@ -1258,10 +1276,15 @@ static bool dpm_leaf_device(struct device *dev)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
/*
|
||||
* Since this function is required to run under dpm_list_mtx, the
|
||||
* list_empty() below will only return true if the device's list of
|
||||
* consumers is actually empty before calling it.
|
||||
*/
|
||||
return list_empty(&dev->links.consumers);
|
||||
}
|
||||
|
||||
static void dpm_async_suspend_parent(struct device *dev, async_func_t func)
|
||||
static bool dpm_async_suspend_parent(struct device *dev, async_func_t func)
|
||||
{
|
||||
guard(mutex)(&dpm_list_mtx);
|
||||
|
||||
@@ -1273,11 +1296,31 @@ static void dpm_async_suspend_parent(struct device *dev, async_func_t func)
|
||||
* deleted before it.
|
||||
*/
|
||||
if (!device_pm_initialized(dev))
|
||||
return;
|
||||
return false;
|
||||
|
||||
/* Start processing the device's parent if it is "async". */
|
||||
if (dev->parent)
|
||||
dpm_async_with_cleanup(dev->parent, func);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void dpm_async_suspend_superior(struct device *dev, async_func_t func)
|
||||
{
|
||||
struct device_link *link;
|
||||
int idx;
|
||||
|
||||
if (!dpm_async_suspend_parent(dev, func))
|
||||
return;
|
||||
|
||||
idx = device_links_read_lock();
|
||||
|
||||
/* Start processing the device's "async" suppliers. */
|
||||
list_for_each_entry_rcu(link, &dev->links.suppliers, c_node)
|
||||
if (READ_ONCE(link->status) != DL_STATE_DORMANT)
|
||||
dpm_async_with_cleanup(link->supplier, func);
|
||||
|
||||
device_links_read_unlock(idx);
|
||||
}
|
||||
|
||||
static void dpm_async_suspend_complete_all(struct list_head *device_list)
|
||||
@@ -1417,7 +1460,7 @@ Complete:
|
||||
if (error || async_error)
|
||||
return error;
|
||||
|
||||
dpm_async_suspend_parent(dev, async_suspend_noirq);
|
||||
dpm_async_suspend_superior(dev, async_suspend_noirq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1614,7 +1657,7 @@ Complete:
|
||||
if (error || async_error)
|
||||
return error;
|
||||
|
||||
dpm_async_suspend_parent(dev, async_suspend_late);
|
||||
dpm_async_suspend_superior(dev, async_suspend_late);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1906,7 +1949,7 @@ static int device_suspend(struct device *dev, pm_message_t state, bool async)
|
||||
if (error || async_error)
|
||||
return error;
|
||||
|
||||
dpm_async_suspend_parent(dev, async_suspend);
|
||||
dpm_async_suspend_superior(dev, async_suspend);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -2129,7 +2172,6 @@ int dpm_prepare(pm_message_t state)
|
||||
int error = 0;
|
||||
|
||||
trace_suspend_resume(TPS("dpm_prepare"), state.event, true);
|
||||
might_sleep();
|
||||
|
||||
/*
|
||||
* Give a chance for the known devices to complete their probes, before
|
||||
|
||||
@@ -19,10 +19,24 @@
|
||||
|
||||
typedef int (*pm_callback_t)(struct device *);
|
||||
|
||||
static inline pm_callback_t get_callback_ptr(const void *start, size_t offset)
|
||||
{
|
||||
return *(pm_callback_t *)(start + offset);
|
||||
}
|
||||
|
||||
static pm_callback_t __rpm_get_driver_callback(struct device *dev,
|
||||
size_t cb_offset)
|
||||
{
|
||||
if (dev->driver && dev->driver->pm)
|
||||
return get_callback_ptr(dev->driver->pm, cb_offset);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static pm_callback_t __rpm_get_callback(struct device *dev, size_t cb_offset)
|
||||
{
|
||||
pm_callback_t cb;
|
||||
const struct dev_pm_ops *ops;
|
||||
pm_callback_t cb = NULL;
|
||||
|
||||
if (dev->pm_domain)
|
||||
ops = &dev->pm_domain->ops;
|
||||
@@ -36,12 +50,10 @@ static pm_callback_t __rpm_get_callback(struct device *dev, size_t cb_offset)
|
||||
ops = NULL;
|
||||
|
||||
if (ops)
|
||||
cb = *(pm_callback_t *)((void *)ops + cb_offset);
|
||||
else
|
||||
cb = NULL;
|
||||
cb = get_callback_ptr(ops, cb_offset);
|
||||
|
||||
if (!cb && dev->driver && dev->driver->pm)
|
||||
cb = *(pm_callback_t *)((void *)dev->driver->pm + cb_offset);
|
||||
if (!cb)
|
||||
cb = __rpm_get_driver_callback(dev, cb_offset);
|
||||
|
||||
return cb;
|
||||
}
|
||||
@@ -1827,7 +1839,7 @@ void pm_runtime_init(struct device *dev)
|
||||
dev->power.request_pending = false;
|
||||
dev->power.request = RPM_REQ_NONE;
|
||||
dev->power.deferred_resume = false;
|
||||
dev->power.needs_force_resume = 0;
|
||||
dev->power.needs_force_resume = false;
|
||||
INIT_WORK(&dev->power.work, pm_runtime_work);
|
||||
|
||||
dev->power.timer_expires = 0;
|
||||
@@ -1854,6 +1866,11 @@ void pm_runtime_reinit(struct device *dev)
|
||||
pm_runtime_put(dev->parent);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Clear power.needs_force_resume in case it has been set by
|
||||
* pm_runtime_force_suspend() invoked from a driver remove callback.
|
||||
*/
|
||||
dev->power.needs_force_resume = false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1941,13 +1958,23 @@ void pm_runtime_drop_link(struct device_link *link)
|
||||
pm_request_idle(link->supplier);
|
||||
}
|
||||
|
||||
bool pm_runtime_need_not_resume(struct device *dev)
|
||||
static pm_callback_t get_callback(struct device *dev, size_t cb_offset)
|
||||
{
|
||||
return atomic_read(&dev->power.usage_count) <= 1 &&
|
||||
(atomic_read(&dev->power.child_count) == 0 ||
|
||||
dev->power.ignore_children);
|
||||
/*
|
||||
* Setting power.strict_midlayer means that the middle layer
|
||||
* code does not want its runtime PM callbacks to be invoked via
|
||||
* pm_runtime_force_suspend() and pm_runtime_force_resume(), so
|
||||
* return a direct pointer to the driver callback in that case.
|
||||
*/
|
||||
if (dev_pm_strict_midlayer_is_set(dev))
|
||||
return __rpm_get_driver_callback(dev, cb_offset);
|
||||
|
||||
return __rpm_get_callback(dev, cb_offset);
|
||||
}
|
||||
|
||||
#define GET_CALLBACK(dev, callback) \
|
||||
get_callback(dev, offsetof(struct dev_pm_ops, callback))
|
||||
|
||||
/**
|
||||
* pm_runtime_force_suspend - Force a device into suspend state if needed.
|
||||
* @dev: Device to suspend.
|
||||
@@ -1964,10 +1991,6 @@ bool pm_runtime_need_not_resume(struct device *dev)
|
||||
* sure the device is put into low power state and it should only be used during
|
||||
* system-wide PM transitions to sleep states. It assumes that the analogous
|
||||
* pm_runtime_force_resume() will be used to resume the device.
|
||||
*
|
||||
* Do not use with DPM_FLAG_SMART_SUSPEND as this can lead to an inconsistent
|
||||
* state where this function has called the ->runtime_suspend callback but the
|
||||
* PM core marks the driver as runtime active.
|
||||
*/
|
||||
int pm_runtime_force_suspend(struct device *dev)
|
||||
{
|
||||
@@ -1975,10 +1998,10 @@ int pm_runtime_force_suspend(struct device *dev)
|
||||
int ret;
|
||||
|
||||
pm_runtime_disable(dev);
|
||||
if (pm_runtime_status_suspended(dev))
|
||||
if (pm_runtime_status_suspended(dev) || dev->power.needs_force_resume)
|
||||
return 0;
|
||||
|
||||
callback = RPM_GET_CALLBACK(dev, runtime_suspend);
|
||||
callback = GET_CALLBACK(dev, runtime_suspend);
|
||||
|
||||
dev_pm_enable_wake_irq_check(dev, true);
|
||||
ret = callback ? callback(dev) : 0;
|
||||
@@ -1990,15 +2013,16 @@ int pm_runtime_force_suspend(struct device *dev)
|
||||
/*
|
||||
* If the device can stay in suspend after the system-wide transition
|
||||
* to the working state that will follow, drop the children counter of
|
||||
* its parent, but set its status to RPM_SUSPENDED anyway in case this
|
||||
* function will be called again for it in the meantime.
|
||||
* its parent and the usage counters of its suppliers. Otherwise, set
|
||||
* power.needs_force_resume to let pm_runtime_force_resume() know that
|
||||
* the device needs to be taken care of and to prevent this function
|
||||
* from handling the device again in case the device is passed to it
|
||||
* once more subsequently.
|
||||
*/
|
||||
if (pm_runtime_need_not_resume(dev)) {
|
||||
if (pm_runtime_need_not_resume(dev))
|
||||
pm_runtime_set_suspended(dev);
|
||||
} else {
|
||||
__update_runtime_status(dev, RPM_SUSPENDED);
|
||||
dev->power.needs_force_resume = 1;
|
||||
}
|
||||
else
|
||||
dev->power.needs_force_resume = true;
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -2009,33 +2033,37 @@ err:
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pm_runtime_force_suspend);
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
|
||||
/**
|
||||
* pm_runtime_force_resume - Force a device into resume state if needed.
|
||||
* @dev: Device to resume.
|
||||
*
|
||||
* Prior invoking this function we expect the user to have brought the device
|
||||
* into low power state by a call to pm_runtime_force_suspend(). Here we reverse
|
||||
* those actions and bring the device into full power, if it is expected to be
|
||||
* used on system resume. In the other case, we defer the resume to be managed
|
||||
* via runtime PM.
|
||||
* This function expects that either pm_runtime_force_suspend() has put the
|
||||
* device into a low-power state prior to calling it, or the device had been
|
||||
* runtime-suspended before the preceding system-wide suspend transition and it
|
||||
* was left in suspend during that transition.
|
||||
*
|
||||
* Typically this function may be invoked from a system resume callback.
|
||||
* The actions carried out by pm_runtime_force_suspend(), or by a runtime
|
||||
* suspend in general, are reversed and the device is brought back into full
|
||||
* power if it is expected to be used on system resume, which is the case when
|
||||
* its needs_force_resume flag is set or when its smart_suspend flag is set and
|
||||
* its runtime PM status is "active".
|
||||
*
|
||||
* In other cases, the resume is deferred to be managed via runtime PM.
|
||||
*
|
||||
* Typically, this function may be invoked from a system resume callback.
|
||||
*/
|
||||
int pm_runtime_force_resume(struct device *dev)
|
||||
{
|
||||
int (*callback)(struct device *);
|
||||
int ret = 0;
|
||||
|
||||
if (!dev->power.needs_force_resume)
|
||||
if (!dev->power.needs_force_resume && (!dev_pm_smart_suspend(dev) ||
|
||||
pm_runtime_status_suspended(dev)))
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* The value of the parent's children counter is correct already, so
|
||||
* just update the status of the device.
|
||||
*/
|
||||
__update_runtime_status(dev, RPM_ACTIVE);
|
||||
|
||||
callback = RPM_GET_CALLBACK(dev, runtime_resume);
|
||||
callback = GET_CALLBACK(dev, runtime_resume);
|
||||
|
||||
dev_pm_disable_wake_irq_check(dev, false);
|
||||
ret = callback ? callback(dev) : 0;
|
||||
@@ -2046,9 +2074,30 @@ int pm_runtime_force_resume(struct device *dev)
|
||||
}
|
||||
|
||||
pm_runtime_mark_last_busy(dev);
|
||||
|
||||
out:
|
||||
dev->power.needs_force_resume = 0;
|
||||
/*
|
||||
* The smart_suspend flag can be cleared here because it is not going
|
||||
* to be necessary until the next system-wide suspend transition that
|
||||
* will update it again.
|
||||
*/
|
||||
dev->power.smart_suspend = false;
|
||||
/*
|
||||
* Also clear needs_force_resume to make this function skip devices that
|
||||
* have been seen by it once.
|
||||
*/
|
||||
dev->power.needs_force_resume = false;
|
||||
|
||||
pm_runtime_enable(dev);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pm_runtime_force_resume);
|
||||
|
||||
bool pm_runtime_need_not_resume(struct device *dev)
|
||||
{
|
||||
return atomic_read(&dev->power.usage_count) <= 1 &&
|
||||
(atomic_read(&dev->power.child_count) == 0 ||
|
||||
dev->power.ignore_children);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_PM_SLEEP */
|
||||
|
||||
@@ -708,6 +708,8 @@ static int pci_pm_prepare(struct device *dev)
|
||||
struct pci_dev *pci_dev = to_pci_dev(dev);
|
||||
const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
|
||||
|
||||
dev_pm_set_strict_midlayer(dev, true);
|
||||
|
||||
if (pm && pm->prepare) {
|
||||
int error = pm->prepare(dev);
|
||||
if (error < 0)
|
||||
@@ -749,6 +751,8 @@ static void pci_pm_complete(struct device *dev)
|
||||
if (pci_dev->current_state < pre_sleep_state)
|
||||
pm_request_resume(dev);
|
||||
}
|
||||
|
||||
dev_pm_set_strict_midlayer(dev, false);
|
||||
}
|
||||
|
||||
#else /* !CONFIG_PM_SLEEP */
|
||||
|
||||
@@ -879,6 +879,33 @@ static inline bool dev_pm_smart_suspend(struct device *dev)
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* dev_pm_set_strict_midlayer - Update the device's power.strict_midlayer flag
|
||||
* @dev: Target device.
|
||||
* @val: New flag value.
|
||||
*
|
||||
* When set, power.strict_midlayer means that the middle layer power management
|
||||
* code (typically, a bus type or a PM domain) does not expect its runtime PM
|
||||
* suspend callback to be invoked at all during system-wide PM transitions and
|
||||
* it does not expect its runtime PM resume callback to be invoked at any point
|
||||
* when runtime PM is disabled for the device during system-wide PM transitions.
|
||||
*/
|
||||
static inline void dev_pm_set_strict_midlayer(struct device *dev, bool val)
|
||||
{
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
dev->power.strict_midlayer = val;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline bool dev_pm_strict_midlayer_is_set(struct device *dev)
|
||||
{
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
return dev->power.strict_midlayer;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void device_lock(struct device *dev)
|
||||
{
|
||||
mutex_lock(&dev->mutex);
|
||||
|
||||
@@ -683,6 +683,7 @@ struct dev_pm_info {
|
||||
bool smart_suspend:1; /* Owned by the PM core */
|
||||
bool must_resume:1; /* Owned by the PM core */
|
||||
bool may_skip_resume:1; /* Set by subsystems */
|
||||
bool strict_midlayer:1;
|
||||
#else
|
||||
bool should_wakeup:1;
|
||||
#endif
|
||||
|
||||
@@ -66,9 +66,7 @@ static inline bool queue_pm_work(struct work_struct *work)
|
||||
|
||||
extern int pm_generic_runtime_suspend(struct device *dev);
|
||||
extern int pm_generic_runtime_resume(struct device *dev);
|
||||
extern bool pm_runtime_need_not_resume(struct device *dev);
|
||||
extern int pm_runtime_force_suspend(struct device *dev);
|
||||
extern int pm_runtime_force_resume(struct device *dev);
|
||||
|
||||
extern int __pm_runtime_idle(struct device *dev, int rpmflags);
|
||||
extern int __pm_runtime_suspend(struct device *dev, int rpmflags);
|
||||
@@ -257,9 +255,7 @@ static inline bool queue_pm_work(struct work_struct *work) { return false; }
|
||||
|
||||
static inline int pm_generic_runtime_suspend(struct device *dev) { return 0; }
|
||||
static inline int pm_generic_runtime_resume(struct device *dev) { return 0; }
|
||||
static inline bool pm_runtime_need_not_resume(struct device *dev) {return true; }
|
||||
static inline int pm_runtime_force_suspend(struct device *dev) { return 0; }
|
||||
static inline int pm_runtime_force_resume(struct device *dev) { return 0; }
|
||||
|
||||
static inline int __pm_runtime_idle(struct device *dev, int rpmflags)
|
||||
{
|
||||
@@ -330,6 +326,18 @@ static inline void pm_runtime_release_supplier(struct device_link *link) {}
|
||||
|
||||
#endif /* !CONFIG_PM */
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
|
||||
bool pm_runtime_need_not_resume(struct device *dev);
|
||||
int pm_runtime_force_resume(struct device *dev);
|
||||
|
||||
#else /* !CONFIG_PM_SLEEP */
|
||||
|
||||
static inline bool pm_runtime_need_not_resume(struct device *dev) {return true; }
|
||||
static inline int pm_runtime_force_resume(struct device *dev) { return -ENXIO; }
|
||||
|
||||
#endif /* CONFIG_PM_SLEEP */
|
||||
|
||||
/**
|
||||
* pm_runtime_idle - Conditionally set up autosuspend of a device or suspend it.
|
||||
* @dev: Target device.
|
||||
|
||||
@@ -1080,7 +1080,7 @@ int kernel_kexec(void)
|
||||
console_suspend_all();
|
||||
error = dpm_suspend_start(PMSG_FREEZE);
|
||||
if (error)
|
||||
goto Resume_console;
|
||||
goto Resume_devices;
|
||||
/*
|
||||
* dpm_suspend_end() must be called after dpm_suspend_start()
|
||||
* to complete the transition, like in the hibernation flows
|
||||
@@ -1135,8 +1135,6 @@ int kernel_kexec(void)
|
||||
dpm_resume_start(PMSG_RESTORE);
|
||||
Resume_devices:
|
||||
dpm_resume_end(PMSG_RESTORE);
|
||||
Resume_console:
|
||||
pm_restore_gfp_mask();
|
||||
console_resume_all();
|
||||
thaw_processes();
|
||||
Restore_console:
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#define SUSPEND_CONSOLE (MAX_NR_CONSOLES-1)
|
||||
|
||||
static int orig_fgconsole, orig_kmsg;
|
||||
static bool vt_switch_done;
|
||||
|
||||
static DEFINE_MUTEX(vt_switch_mutex);
|
||||
|
||||
@@ -136,17 +137,21 @@ void pm_prepare_console(void)
|
||||
if (orig_fgconsole < 0)
|
||||
return;
|
||||
|
||||
vt_switch_done = true;
|
||||
|
||||
orig_kmsg = vt_kmsg_redirect(SUSPEND_CONSOLE);
|
||||
return;
|
||||
}
|
||||
|
||||
void pm_restore_console(void)
|
||||
{
|
||||
if (!pm_vt_switch())
|
||||
if (!pm_vt_switch() && !vt_switch_done)
|
||||
return;
|
||||
|
||||
if (orig_fgconsole >= 0) {
|
||||
vt_move_to_console(orig_fgconsole, 0);
|
||||
vt_kmsg_redirect(orig_kmsg);
|
||||
}
|
||||
|
||||
vt_switch_done = false;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kobject.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/pm-trace.h>
|
||||
@@ -112,6 +113,14 @@ int pm_notifier_call_chain(unsigned long val)
|
||||
/* If set, devices may be suspended and resumed asynchronously. */
|
||||
int pm_async_enabled = 1;
|
||||
|
||||
static int __init pm_async_setup(char *str)
|
||||
{
|
||||
if (!strcmp(str, "off"))
|
||||
pm_async_enabled = 0;
|
||||
return 1;
|
||||
}
|
||||
__setup("pm_async=", pm_async_setup);
|
||||
|
||||
static ssize_t pm_async_show(struct kobject *kobj, struct kobj_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user