Merge tag 'pm-5.8-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
Pull power management updates from Rafael Wysocki: "These rework the system-wide PM driver flags, make runtime switching of cpuidle governors easier, improve the user space hibernation interface code, add intel-speed-select interface documentation, add more debug messages to the ACPI code handling suspend to idle, update the cpufreq core and drivers, fix a minor issue in the cpuidle core and update two cpuidle drivers, improve the PM-runtime framework, update the Intel RAPL power capping driver, update devfreq core and drivers, and clean up the cpupower utility. Specifics: - Rework the system-wide PM driver flags to make them easier to understand and use and update their documentation (Rafael Wysocki, Alan Stern). - Allow cpuidle governors to be switched at run time regardless of the kernel configuration and update the related documentation accordingly (Hanjun Guo). - Improve the resume device handling in the user space hibernarion interface code (Domenico Andreoli). - Document the intel-speed-select sysfs interface (Srinivas Pandruvada). - Make the ACPI code handing suspend to idle print more debug messages to help diagnose issues with it (Rafael Wysocki). - Fix a helper routine in the cpufreq core and correct a typo in the struct cpufreq_driver kerneldoc comment (Rafael Wysocki, Wang Wenhu). - Update cpufreq drivers: - Make the intel_pstate driver start in the passive mode by default on systems without HWP (Rafael Wysocki). - Add i.MX7ULP support to the imx-cpufreq-dt driver and add i.MX7ULP to the cpufreq-dt-platdev blacklist (Peng Fan). - Convert the qoriq cpufreq driver to a platform one, make the platform code create a suitable device object for it and add platform dependencies to it (Mian Yousaf Kaukab, Geert Uytterhoeven). - Fix wrong compatible binding in the qcom driver (Ansuel Smith). - Build the omap driver by default for ARCH_OMAP2PLUS (Anders Roxell). - Add r8a7742 SoC support to the dt cpufreq driver (Lad Prabhakar). - Update cpuidle core and drivers: - Fix three reference count leaks in error code paths in the cpuidle core (Qiushi Wu). - Convert Qualcomm SPM to a generic cpuidle driver (Stephan Gerhold). - Fix up the execution order when entering a domain idle state in the PSCI driver (Ulf Hansson). - Fix a reference counting issue related to clock management and clean up two oddities in the PM-runtime framework (Rafael Wysocki, Andy Shevchenko). - Add ElkhartLake support to the Intel RAPL power capping driver and remove an unused local MSR definition from it (Jacob Pan, Sumeet Pawnikar). - Update devfreq core and drivers: - Replace strncpy() with strscpy() in the devfreq core and use lockdep asserts instead of manual checks for a locked mutex in it (Dmitry Osipenko, Krzysztof Kozlowski). - Add a generic imx bus scaling driver and make it register an interconnect device (Leonard Crestez, Gustavo A. R. Silva). - Make the cpufreq notifier in the tegra30 driver take boosting into account and delete an unuseful error message from that driver (Dmitry Osipenko, Markus Elfring). - Remove unneeded semicolon from the cpupower code (Zou Wei)" * tag 'pm-5.8-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: (51 commits) cpuidle: Fix three reference count leaks PM: runtime: Replace pm_runtime_callbacks_present() PM / devfreq: Use lockdep asserts instead of manual checks for locked mutex PM / devfreq: imx-bus: Fix inconsistent IS_ERR and PTR_ERR PM / devfreq: Replace strncpy with strscpy PM / devfreq: imx: Register interconnect device PM / devfreq: Add generic imx bus scaling driver PM / devfreq: tegra30: Delete an error message in tegra_devfreq_probe() PM / devfreq: tegra30: Make CPUFreq notifier to take into account boosting PM: hibernate: Restrict writes to the resume device PM: runtime: clk: Fix clk_pm_runtime_get() error path cpuidle: Convert Qualcomm SPM driver to a generic CPUidle driver ACPI: EC: PM: s2idle: Extend GPE dispatching debug message ACPI: PM: s2idle: Print type of wakeup debug messages powercap: RAPL: remove unused local MSR define PM: runtime: Make clear what we do when conditions are wrong in rpm_suspend() Documentation: admin-guide: pm: Document intel-speed-select PM: hibernate: Split off snapshot dev option PM: hibernate: Incorporate concurrency handling Documentation: ABI: make current_governer_ro as a candidate for removal ...
This commit is contained in:
@@ -562,72 +562,26 @@ static void dpm_watchdog_clear(struct dpm_watchdog *wd)
|
||||
/*------------------------- Resume routines -------------------------*/
|
||||
|
||||
/**
|
||||
* suspend_event - Return a "suspend" message for given "resume" one.
|
||||
* @resume_msg: PM message representing a system-wide resume transition.
|
||||
*/
|
||||
static pm_message_t suspend_event(pm_message_t resume_msg)
|
||||
{
|
||||
switch (resume_msg.event) {
|
||||
case PM_EVENT_RESUME:
|
||||
return PMSG_SUSPEND;
|
||||
case PM_EVENT_THAW:
|
||||
case PM_EVENT_RESTORE:
|
||||
return PMSG_FREEZE;
|
||||
case PM_EVENT_RECOVER:
|
||||
return PMSG_HIBERNATE;
|
||||
}
|
||||
return PMSG_ON;
|
||||
}
|
||||
|
||||
/**
|
||||
* dev_pm_may_skip_resume - System-wide device resume optimization check.
|
||||
* dev_pm_skip_resume - System-wide device resume optimization check.
|
||||
* @dev: Target device.
|
||||
*
|
||||
* Checks whether or not the device may be left in suspend after a system-wide
|
||||
* transition to the working state.
|
||||
* Return:
|
||||
* - %false if the transition under way is RESTORE.
|
||||
* - Return value of dev_pm_skip_suspend() if the transition under way is THAW.
|
||||
* - The logical negation of %power.must_resume otherwise (that is, when the
|
||||
* transition under way is RESUME).
|
||||
*/
|
||||
bool dev_pm_may_skip_resume(struct device *dev)
|
||||
bool dev_pm_skip_resume(struct device *dev)
|
||||
{
|
||||
return !dev->power.must_resume && pm_transition.event != PM_EVENT_RESTORE;
|
||||
if (pm_transition.event == PM_EVENT_RESTORE)
|
||||
return false;
|
||||
|
||||
if (pm_transition.event == PM_EVENT_THAW)
|
||||
return dev_pm_skip_suspend(dev);
|
||||
|
||||
return !dev->power.must_resume;
|
||||
}
|
||||
|
||||
static pm_callback_t dpm_subsys_resume_noirq_cb(struct device *dev,
|
||||
pm_message_t state,
|
||||
const char **info_p)
|
||||
{
|
||||
pm_callback_t callback;
|
||||
const char *info;
|
||||
|
||||
if (dev->pm_domain) {
|
||||
info = "noirq power domain ";
|
||||
callback = pm_noirq_op(&dev->pm_domain->ops, state);
|
||||
} else if (dev->type && dev->type->pm) {
|
||||
info = "noirq type ";
|
||||
callback = pm_noirq_op(dev->type->pm, state);
|
||||
} else if (dev->class && dev->class->pm) {
|
||||
info = "noirq class ";
|
||||
callback = pm_noirq_op(dev->class->pm, state);
|
||||
} else if (dev->bus && dev->bus->pm) {
|
||||
info = "noirq bus ";
|
||||
callback = pm_noirq_op(dev->bus->pm, state);
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (info_p)
|
||||
*info_p = info;
|
||||
|
||||
return callback;
|
||||
}
|
||||
|
||||
static pm_callback_t dpm_subsys_suspend_noirq_cb(struct device *dev,
|
||||
pm_message_t state,
|
||||
const char **info_p);
|
||||
|
||||
static pm_callback_t dpm_subsys_suspend_late_cb(struct device *dev,
|
||||
pm_message_t state,
|
||||
const char **info_p);
|
||||
|
||||
/**
|
||||
* device_resume_noirq - Execute a "noirq resume" callback for given device.
|
||||
* @dev: Device to handle.
|
||||
@@ -639,8 +593,8 @@ static pm_callback_t dpm_subsys_suspend_late_cb(struct device *dev,
|
||||
*/
|
||||
static int device_resume_noirq(struct device *dev, pm_message_t state, bool async)
|
||||
{
|
||||
pm_callback_t callback;
|
||||
const char *info;
|
||||
pm_callback_t callback = NULL;
|
||||
const char *info = NULL;
|
||||
bool skip_resume;
|
||||
int error = 0;
|
||||
|
||||
@@ -656,37 +610,41 @@ static int device_resume_noirq(struct device *dev, pm_message_t state, bool asyn
|
||||
if (!dpm_wait_for_superior(dev, async))
|
||||
goto Out;
|
||||
|
||||
skip_resume = dev_pm_may_skip_resume(dev);
|
||||
skip_resume = dev_pm_skip_resume(dev);
|
||||
/*
|
||||
* If the driver callback is skipped below or by the middle layer
|
||||
* callback and device_resume_early() also skips the driver callback for
|
||||
* this device later, it needs to appear as "suspended" to PM-runtime,
|
||||
* so change its status accordingly.
|
||||
*
|
||||
* Otherwise, the device is going to be resumed, so set its PM-runtime
|
||||
* status to "active", but do that only if DPM_FLAG_SMART_SUSPEND is set
|
||||
* to avoid confusing drivers that don't use it.
|
||||
*/
|
||||
if (skip_resume)
|
||||
pm_runtime_set_suspended(dev);
|
||||
else if (dev_pm_skip_suspend(dev))
|
||||
pm_runtime_set_active(dev);
|
||||
|
||||
callback = dpm_subsys_resume_noirq_cb(dev, state, &info);
|
||||
if (dev->pm_domain) {
|
||||
info = "noirq power domain ";
|
||||
callback = pm_noirq_op(&dev->pm_domain->ops, state);
|
||||
} else if (dev->type && dev->type->pm) {
|
||||
info = "noirq type ";
|
||||
callback = pm_noirq_op(dev->type->pm, state);
|
||||
} else if (dev->class && dev->class->pm) {
|
||||
info = "noirq class ";
|
||||
callback = pm_noirq_op(dev->class->pm, state);
|
||||
} else if (dev->bus && dev->bus->pm) {
|
||||
info = "noirq bus ";
|
||||
callback = pm_noirq_op(dev->bus->pm, state);
|
||||
}
|
||||
if (callback)
|
||||
goto Run;
|
||||
|
||||
if (skip_resume)
|
||||
goto Skip;
|
||||
|
||||
if (dev_pm_smart_suspend_and_suspended(dev)) {
|
||||
pm_message_t suspend_msg = suspend_event(state);
|
||||
|
||||
/*
|
||||
* If "freeze" callbacks have been skipped during a transition
|
||||
* related to hibernation, the subsequent "thaw" callbacks must
|
||||
* be skipped too or bad things may happen. Otherwise, resume
|
||||
* callbacks are going to be run for the device, so its runtime
|
||||
* PM status must be changed to reflect the new state after the
|
||||
* transition under way.
|
||||
*/
|
||||
if (!dpm_subsys_suspend_late_cb(dev, suspend_msg, NULL) &&
|
||||
!dpm_subsys_suspend_noirq_cb(dev, suspend_msg, NULL)) {
|
||||
if (state.event == PM_EVENT_THAW) {
|
||||
skip_resume = true;
|
||||
goto Skip;
|
||||
} else {
|
||||
pm_runtime_set_active(dev);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (dev->driver && dev->driver->pm) {
|
||||
info = "noirq driver ";
|
||||
callback = pm_noirq_op(dev->driver->pm, state);
|
||||
@@ -698,20 +656,6 @@ Run:
|
||||
Skip:
|
||||
dev->power.is_noirq_suspended = false;
|
||||
|
||||
if (skip_resume) {
|
||||
/* Make the next phases of resume skip the device. */
|
||||
dev->power.is_late_suspended = false;
|
||||
dev->power.is_suspended = false;
|
||||
/*
|
||||
* The device is going to be left in suspend, but it might not
|
||||
* have been in runtime suspend before the system suspended, so
|
||||
* its runtime PM status needs to be updated to avoid confusing
|
||||
* the runtime PM framework when runtime PM is enabled for the
|
||||
* device again.
|
||||
*/
|
||||
pm_runtime_set_suspended(dev);
|
||||
}
|
||||
|
||||
Out:
|
||||
complete_all(&dev->power.completion);
|
||||
TRACE_RESUME(error);
|
||||
@@ -810,35 +754,6 @@ void dpm_resume_noirq(pm_message_t state)
|
||||
cpuidle_resume();
|
||||
}
|
||||
|
||||
static pm_callback_t dpm_subsys_resume_early_cb(struct device *dev,
|
||||
pm_message_t state,
|
||||
const char **info_p)
|
||||
{
|
||||
pm_callback_t callback;
|
||||
const char *info;
|
||||
|
||||
if (dev->pm_domain) {
|
||||
info = "early power domain ";
|
||||
callback = pm_late_early_op(&dev->pm_domain->ops, state);
|
||||
} else if (dev->type && dev->type->pm) {
|
||||
info = "early type ";
|
||||
callback = pm_late_early_op(dev->type->pm, state);
|
||||
} else if (dev->class && dev->class->pm) {
|
||||
info = "early class ";
|
||||
callback = pm_late_early_op(dev->class->pm, state);
|
||||
} else if (dev->bus && dev->bus->pm) {
|
||||
info = "early bus ";
|
||||
callback = pm_late_early_op(dev->bus->pm, state);
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (info_p)
|
||||
*info_p = info;
|
||||
|
||||
return callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* device_resume_early - Execute an "early resume" callback for given device.
|
||||
* @dev: Device to handle.
|
||||
@@ -849,8 +764,8 @@ static pm_callback_t dpm_subsys_resume_early_cb(struct device *dev,
|
||||
*/
|
||||
static int device_resume_early(struct device *dev, pm_message_t state, bool async)
|
||||
{
|
||||
pm_callback_t callback;
|
||||
const char *info;
|
||||
pm_callback_t callback = NULL;
|
||||
const char *info = NULL;
|
||||
int error = 0;
|
||||
|
||||
TRACE_DEVICE(dev);
|
||||
@@ -865,17 +780,37 @@ static int device_resume_early(struct device *dev, pm_message_t state, bool asyn
|
||||
if (!dpm_wait_for_superior(dev, async))
|
||||
goto Out;
|
||||
|
||||
callback = dpm_subsys_resume_early_cb(dev, state, &info);
|
||||
if (dev->pm_domain) {
|
||||
info = "early power domain ";
|
||||
callback = pm_late_early_op(&dev->pm_domain->ops, state);
|
||||
} else if (dev->type && dev->type->pm) {
|
||||
info = "early type ";
|
||||
callback = pm_late_early_op(dev->type->pm, state);
|
||||
} else if (dev->class && dev->class->pm) {
|
||||
info = "early class ";
|
||||
callback = pm_late_early_op(dev->class->pm, state);
|
||||
} else if (dev->bus && dev->bus->pm) {
|
||||
info = "early bus ";
|
||||
callback = pm_late_early_op(dev->bus->pm, state);
|
||||
}
|
||||
if (callback)
|
||||
goto Run;
|
||||
|
||||
if (!callback && dev->driver && dev->driver->pm) {
|
||||
if (dev_pm_skip_resume(dev))
|
||||
goto Skip;
|
||||
|
||||
if (dev->driver && dev->driver->pm) {
|
||||
info = "early driver ";
|
||||
callback = pm_late_early_op(dev->driver->pm, state);
|
||||
}
|
||||
|
||||
Run:
|
||||
error = dpm_run_callback(callback, dev, state, info);
|
||||
|
||||
Skip:
|
||||
dev->power.is_late_suspended = false;
|
||||
|
||||
Out:
|
||||
Out:
|
||||
TRACE_RESUME(error);
|
||||
|
||||
pm_runtime_enable(dev);
|
||||
@@ -1245,61 +1180,6 @@ static void dpm_superior_set_must_resume(struct device *dev)
|
||||
device_links_read_unlock(idx);
|
||||
}
|
||||
|
||||
static pm_callback_t dpm_subsys_suspend_noirq_cb(struct device *dev,
|
||||
pm_message_t state,
|
||||
const char **info_p)
|
||||
{
|
||||
pm_callback_t callback;
|
||||
const char *info;
|
||||
|
||||
if (dev->pm_domain) {
|
||||
info = "noirq power domain ";
|
||||
callback = pm_noirq_op(&dev->pm_domain->ops, state);
|
||||
} else if (dev->type && dev->type->pm) {
|
||||
info = "noirq type ";
|
||||
callback = pm_noirq_op(dev->type->pm, state);
|
||||
} else if (dev->class && dev->class->pm) {
|
||||
info = "noirq class ";
|
||||
callback = pm_noirq_op(dev->class->pm, state);
|
||||
} else if (dev->bus && dev->bus->pm) {
|
||||
info = "noirq bus ";
|
||||
callback = pm_noirq_op(dev->bus->pm, state);
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (info_p)
|
||||
*info_p = info;
|
||||
|
||||
return callback;
|
||||
}
|
||||
|
||||
static bool device_must_resume(struct device *dev, pm_message_t state,
|
||||
bool no_subsys_suspend_noirq)
|
||||
{
|
||||
pm_message_t resume_msg = resume_event(state);
|
||||
|
||||
/*
|
||||
* If all of the device driver's "noirq", "late" and "early" callbacks
|
||||
* are invoked directly by the core, the decision to allow the device to
|
||||
* stay in suspend can be based on its current runtime PM status and its
|
||||
* wakeup settings.
|
||||
*/
|
||||
if (no_subsys_suspend_noirq &&
|
||||
!dpm_subsys_suspend_late_cb(dev, state, NULL) &&
|
||||
!dpm_subsys_resume_early_cb(dev, resume_msg, NULL) &&
|
||||
!dpm_subsys_resume_noirq_cb(dev, resume_msg, NULL))
|
||||
return !pm_runtime_status_suspended(dev) &&
|
||||
(resume_msg.event != PM_EVENT_RESUME ||
|
||||
(device_can_wakeup(dev) && !device_may_wakeup(dev)));
|
||||
|
||||
/*
|
||||
* The only safe strategy here is to require that if the device may not
|
||||
* be left in suspend, resume callbacks must be invoked for it.
|
||||
*/
|
||||
return !dev->power.may_skip_resume;
|
||||
}
|
||||
|
||||
/**
|
||||
* __device_suspend_noirq - Execute a "noirq suspend" callback for given device.
|
||||
* @dev: Device to handle.
|
||||
@@ -1311,9 +1191,8 @@ static bool device_must_resume(struct device *dev, pm_message_t state,
|
||||
*/
|
||||
static int __device_suspend_noirq(struct device *dev, pm_message_t state, bool async)
|
||||
{
|
||||
pm_callback_t callback;
|
||||
const char *info;
|
||||
bool no_subsys_cb = false;
|
||||
pm_callback_t callback = NULL;
|
||||
const char *info = NULL;
|
||||
int error = 0;
|
||||
|
||||
TRACE_DEVICE(dev);
|
||||
@@ -1327,13 +1206,23 @@ static int __device_suspend_noirq(struct device *dev, pm_message_t state, bool a
|
||||
if (dev->power.syscore || dev->power.direct_complete)
|
||||
goto Complete;
|
||||
|
||||
callback = dpm_subsys_suspend_noirq_cb(dev, state, &info);
|
||||
if (dev->pm_domain) {
|
||||
info = "noirq power domain ";
|
||||
callback = pm_noirq_op(&dev->pm_domain->ops, state);
|
||||
} else if (dev->type && dev->type->pm) {
|
||||
info = "noirq type ";
|
||||
callback = pm_noirq_op(dev->type->pm, state);
|
||||
} else if (dev->class && dev->class->pm) {
|
||||
info = "noirq class ";
|
||||
callback = pm_noirq_op(dev->class->pm, state);
|
||||
} else if (dev->bus && dev->bus->pm) {
|
||||
info = "noirq bus ";
|
||||
callback = pm_noirq_op(dev->bus->pm, state);
|
||||
}
|
||||
if (callback)
|
||||
goto Run;
|
||||
|
||||
no_subsys_cb = !dpm_subsys_suspend_late_cb(dev, state, NULL);
|
||||
|
||||
if (dev_pm_smart_suspend_and_suspended(dev) && no_subsys_cb)
|
||||
if (dev_pm_skip_suspend(dev))
|
||||
goto Skip;
|
||||
|
||||
if (dev->driver && dev->driver->pm) {
|
||||
@@ -1351,13 +1240,16 @@ Run:
|
||||
Skip:
|
||||
dev->power.is_noirq_suspended = true;
|
||||
|
||||
if (dev_pm_test_driver_flags(dev, DPM_FLAG_LEAVE_SUSPENDED)) {
|
||||
dev->power.must_resume = dev->power.must_resume ||
|
||||
atomic_read(&dev->power.usage_count) > 1 ||
|
||||
device_must_resume(dev, state, no_subsys_cb);
|
||||
} else {
|
||||
/*
|
||||
* Skipping the resume of devices that were in use right before the
|
||||
* system suspend (as indicated by their PM-runtime usage counters)
|
||||
* would be suboptimal. Also resume them if doing that is not allowed
|
||||
* to be skipped.
|
||||
*/
|
||||
if (atomic_read(&dev->power.usage_count) > 1 ||
|
||||
!(dev_pm_test_driver_flags(dev, DPM_FLAG_MAY_SKIP_RESUME) &&
|
||||
dev->power.may_skip_resume))
|
||||
dev->power.must_resume = true;
|
||||
}
|
||||
|
||||
if (dev->power.must_resume)
|
||||
dpm_superior_set_must_resume(dev);
|
||||
@@ -1474,35 +1366,6 @@ static void dpm_propagate_wakeup_to_parent(struct device *dev)
|
||||
spin_unlock_irq(&parent->power.lock);
|
||||
}
|
||||
|
||||
static pm_callback_t dpm_subsys_suspend_late_cb(struct device *dev,
|
||||
pm_message_t state,
|
||||
const char **info_p)
|
||||
{
|
||||
pm_callback_t callback;
|
||||
const char *info;
|
||||
|
||||
if (dev->pm_domain) {
|
||||
info = "late power domain ";
|
||||
callback = pm_late_early_op(&dev->pm_domain->ops, state);
|
||||
} else if (dev->type && dev->type->pm) {
|
||||
info = "late type ";
|
||||
callback = pm_late_early_op(dev->type->pm, state);
|
||||
} else if (dev->class && dev->class->pm) {
|
||||
info = "late class ";
|
||||
callback = pm_late_early_op(dev->class->pm, state);
|
||||
} else if (dev->bus && dev->bus->pm) {
|
||||
info = "late bus ";
|
||||
callback = pm_late_early_op(dev->bus->pm, state);
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (info_p)
|
||||
*info_p = info;
|
||||
|
||||
return callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* __device_suspend_late - Execute a "late suspend" callback for given device.
|
||||
* @dev: Device to handle.
|
||||
@@ -1513,8 +1376,8 @@ static pm_callback_t dpm_subsys_suspend_late_cb(struct device *dev,
|
||||
*/
|
||||
static int __device_suspend_late(struct device *dev, pm_message_t state, bool async)
|
||||
{
|
||||
pm_callback_t callback;
|
||||
const char *info;
|
||||
pm_callback_t callback = NULL;
|
||||
const char *info = NULL;
|
||||
int error = 0;
|
||||
|
||||
TRACE_DEVICE(dev);
|
||||
@@ -1535,12 +1398,23 @@ static int __device_suspend_late(struct device *dev, pm_message_t state, bool as
|
||||
if (dev->power.syscore || dev->power.direct_complete)
|
||||
goto Complete;
|
||||
|
||||
callback = dpm_subsys_suspend_late_cb(dev, state, &info);
|
||||
if (dev->pm_domain) {
|
||||
info = "late power domain ";
|
||||
callback = pm_late_early_op(&dev->pm_domain->ops, state);
|
||||
} else if (dev->type && dev->type->pm) {
|
||||
info = "late type ";
|
||||
callback = pm_late_early_op(dev->type->pm, state);
|
||||
} else if (dev->class && dev->class->pm) {
|
||||
info = "late class ";
|
||||
callback = pm_late_early_op(dev->class->pm, state);
|
||||
} else if (dev->bus && dev->bus->pm) {
|
||||
info = "late bus ";
|
||||
callback = pm_late_early_op(dev->bus->pm, state);
|
||||
}
|
||||
if (callback)
|
||||
goto Run;
|
||||
|
||||
if (dev_pm_smart_suspend_and_suspended(dev) &&
|
||||
!dpm_subsys_suspend_noirq_cb(dev, state, NULL))
|
||||
if (dev_pm_skip_suspend(dev))
|
||||
goto Skip;
|
||||
|
||||
if (dev->driver && dev->driver->pm) {
|
||||
@@ -1766,7 +1640,7 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
|
||||
dev->power.direct_complete = false;
|
||||
}
|
||||
|
||||
dev->power.may_skip_resume = false;
|
||||
dev->power.may_skip_resume = true;
|
||||
dev->power.must_resume = false;
|
||||
|
||||
dpm_watchdog_set(&wd, dev);
|
||||
@@ -1970,7 +1844,7 @@ unlock:
|
||||
spin_lock_irq(&dev->power.lock);
|
||||
dev->power.direct_complete = state.event == PM_EVENT_SUSPEND &&
|
||||
(ret > 0 || dev->power.no_pm_callbacks) &&
|
||||
!dev_pm_test_driver_flags(dev, DPM_FLAG_NEVER_SKIP);
|
||||
!dev_pm_test_driver_flags(dev, DPM_FLAG_NO_DIRECT_COMPLETE);
|
||||
spin_unlock_irq(&dev->power.lock);
|
||||
return 0;
|
||||
}
|
||||
@@ -2128,7 +2002,7 @@ void device_pm_check_callbacks(struct device *dev)
|
||||
spin_unlock_irq(&dev->power.lock);
|
||||
}
|
||||
|
||||
bool dev_pm_smart_suspend_and_suspended(struct device *dev)
|
||||
bool dev_pm_skip_suspend(struct device *dev)
|
||||
{
|
||||
return dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_SUSPEND) &&
|
||||
pm_runtime_status_suspended(dev);
|
||||
|
@@ -523,13 +523,11 @@ static int rpm_suspend(struct device *dev, int rpmflags)
|
||||
|
||||
repeat:
|
||||
retval = rpm_check_suspend_allowed(dev);
|
||||
|
||||
if (retval < 0)
|
||||
; /* Conditions are wrong. */
|
||||
goto out; /* Conditions are wrong. */
|
||||
|
||||
/* Synchronous suspends are not allowed in the RPM_RESUMING state. */
|
||||
else if (dev->power.runtime_status == RPM_RESUMING &&
|
||||
!(rpmflags & RPM_ASYNC))
|
||||
if (dev->power.runtime_status == RPM_RESUMING && !(rpmflags & RPM_ASYNC))
|
||||
retval = -EAGAIN;
|
||||
if (retval)
|
||||
goto out;
|
||||
|
@@ -666,7 +666,7 @@ int dpm_sysfs_add(struct device *dev)
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (pm_runtime_callbacks_present(dev)) {
|
||||
if (!pm_runtime_has_no_callbacks(dev)) {
|
||||
rc = sysfs_merge_group(&dev->kobj, &pm_runtime_attr_group);
|
||||
if (rc)
|
||||
goto err_out;
|
||||
@@ -709,7 +709,7 @@ int dpm_sysfs_change_owner(struct device *dev, kuid_t kuid, kgid_t kgid)
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (pm_runtime_callbacks_present(dev)) {
|
||||
if (!pm_runtime_has_no_callbacks(dev)) {
|
||||
rc = sysfs_group_change_owner(
|
||||
&dev->kobj, &pm_runtime_attr_group, kuid, kgid);
|
||||
if (rc)
|
||||
|
Reference in New Issue
Block a user