Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/suspend-2.6
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/suspend-2.6: (21 commits) PM / Hibernate: Reduce autotuned default image size PM / Core: Introduce struct syscore_ops for core subsystems PM PM QoS: Make pm_qos settings readable PM / OPP: opp_find_freq_exact() documentation fix PM: Documentation/power/states.txt: fix repetition PM: Make system-wide PM and runtime PM treat subsystems consistently PM: Simplify kernel/power/Kconfig PM: Add support for device power domains PM: Drop pm_flags that is not necessary PM: Allow pm_runtime_suspend() to succeed during system suspend PM: Clean up PM_TRACE dependencies and drop unnecessary Kconfig option PM: Remove CONFIG_PM_OPS PM: Reorder power management Kconfig options PM: Make CONFIG_PM depend on (CONFIG_PM_SLEEP || CONFIG_PM_RUNTIME) PM / ACPI: Remove references to pm_flags from bus.c PM: Do not create wakeup sysfs files for devices that cannot wake up USB / Hub: Do not call device_set_wakeup_capable() under spinlock PM: Use appropriate printk() priority level in trace.c PM / Wakeup: Don't update events_check_enabled in pm_get_wakeup_count() PM / Wakeup: Make pm_save_wakeup_count() work as documented ...
This commit is contained in:
commit
fc82e1d59a
40 changed files with 698 additions and 428 deletions
|
@ -29,9 +29,8 @@ Description:
|
|||
"disabled" to it.
|
||||
|
||||
For the devices that are not capable of generating system wakeup
|
||||
events this file contains "\n". In that cases the user space
|
||||
cannot modify the contents of this file and the device cannot be
|
||||
enabled to wake up the system.
|
||||
events this file is not present. In that case the device cannot
|
||||
be enabled to wake up the system from sleep states.
|
||||
|
||||
What: /sys/devices/.../power/control
|
||||
Date: January 2009
|
||||
|
@ -85,7 +84,7 @@ Description:
|
|||
The /sys/devices/.../wakeup_count attribute contains the number
|
||||
of signaled wakeup events associated with the device. This
|
||||
attribute is read-only. If the device is not enabled to wake up
|
||||
the system from sleep states, this attribute is empty.
|
||||
the system from sleep states, this attribute is not present.
|
||||
|
||||
What: /sys/devices/.../power/wakeup_active_count
|
||||
Date: September 2010
|
||||
|
@ -95,7 +94,7 @@ Description:
|
|||
number of times the processing of wakeup events associated with
|
||||
the device was completed (at the kernel level). This attribute
|
||||
is read-only. If the device is not enabled to wake up the
|
||||
system from sleep states, this attribute is empty.
|
||||
system from sleep states, this attribute is not present.
|
||||
|
||||
What: /sys/devices/.../power/wakeup_hit_count
|
||||
Date: September 2010
|
||||
|
@ -105,7 +104,8 @@ Description:
|
|||
number of times the processing of a wakeup event associated with
|
||||
the device might prevent the system from entering a sleep state.
|
||||
This attribute is read-only. If the device is not enabled to
|
||||
wake up the system from sleep states, this attribute is empty.
|
||||
wake up the system from sleep states, this attribute is not
|
||||
present.
|
||||
|
||||
What: /sys/devices/.../power/wakeup_active
|
||||
Date: September 2010
|
||||
|
@ -115,7 +115,7 @@ Description:
|
|||
or 0, depending on whether or not a wakeup event associated with
|
||||
the device is being processed (1). This attribute is read-only.
|
||||
If the device is not enabled to wake up the system from sleep
|
||||
states, this attribute is empty.
|
||||
states, this attribute is not present.
|
||||
|
||||
What: /sys/devices/.../power/wakeup_total_time_ms
|
||||
Date: September 2010
|
||||
|
@ -125,7 +125,7 @@ Description:
|
|||
the total time of processing wakeup events associated with the
|
||||
device, in milliseconds. This attribute is read-only. If the
|
||||
device is not enabled to wake up the system from sleep states,
|
||||
this attribute is empty.
|
||||
this attribute is not present.
|
||||
|
||||
What: /sys/devices/.../power/wakeup_max_time_ms
|
||||
Date: September 2010
|
||||
|
@ -135,7 +135,7 @@ Description:
|
|||
the maximum time of processing a single wakeup event associated
|
||||
with the device, in milliseconds. This attribute is read-only.
|
||||
If the device is not enabled to wake up the system from sleep
|
||||
states, this attribute is empty.
|
||||
states, this attribute is not present.
|
||||
|
||||
What: /sys/devices/.../power/wakeup_last_time_ms
|
||||
Date: September 2010
|
||||
|
@ -146,7 +146,7 @@ Description:
|
|||
signaling the last wakeup event associated with the device, in
|
||||
milliseconds. This attribute is read-only. If the device is
|
||||
not enabled to wake up the system from sleep states, this
|
||||
attribute is empty.
|
||||
attribute is not present.
|
||||
|
||||
What: /sys/devices/.../power/autosuspend_delay_ms
|
||||
Date: September 2010
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
Device Power Management
|
||||
|
||||
Copyright (c) 2010 Rafael J. Wysocki <rjw@sisk.pl>, Novell Inc.
|
||||
Copyright (c) 2010-2011 Rafael J. Wysocki <rjw@sisk.pl>, Novell Inc.
|
||||
Copyright (c) 2010 Alan Stern <stern@rowland.harvard.edu>
|
||||
|
||||
|
||||
|
@ -159,18 +159,18 @@ matter, and the kernel is responsible for keeping track of it. By contrast,
|
|||
whether or not a wakeup-capable device should issue wakeup events is a policy
|
||||
decision, and it is managed by user space through a sysfs attribute: the
|
||||
power/wakeup file. User space can write the strings "enabled" or "disabled" to
|
||||
set or clear the should_wakeup flag, respectively. Reads from the file will
|
||||
return the corresponding string if can_wakeup is true, but if can_wakeup is
|
||||
false then reads will return an empty string, to indicate that the device
|
||||
doesn't support wakeup events. (But even though the file appears empty, writes
|
||||
will still affect the should_wakeup flag.)
|
||||
set or clear the "should_wakeup" flag, respectively. This file is only present
|
||||
for wakeup-capable devices (i.e. devices whose "can_wakeup" flags are set)
|
||||
and is created (or removed) by device_set_wakeup_capable(). Reads from the
|
||||
file will return the corresponding string.
|
||||
|
||||
The device_may_wakeup() routine returns true only if both flags are set.
|
||||
Drivers should check this routine when putting devices in a low-power state
|
||||
during a system sleep transition, to see whether or not to enable the devices'
|
||||
wakeup mechanisms. However for runtime power management, wakeup events should
|
||||
be enabled whenever the device and driver both support them, regardless of the
|
||||
should_wakeup flag.
|
||||
This information is used by subsystems, like the PCI bus type code, to see
|
||||
whether or not to enable the devices' wakeup mechanisms. If device wakeup
|
||||
mechanisms are enabled or disabled directly by drivers, they also should use
|
||||
device_may_wakeup() to decide what to do during a system sleep transition.
|
||||
However for runtime power management, wakeup events should be enabled whenever
|
||||
the device and driver both support them, regardless of the should_wakeup flag.
|
||||
|
||||
|
||||
/sys/devices/.../power/control files
|
||||
|
@ -249,23 +249,18 @@ various phases always run after tasks have been frozen and before they are
|
|||
unfrozen. Furthermore, the *_noirq phases run at a time when IRQ handlers have
|
||||
been disabled (except for those marked with the IRQ_WAKEUP flag).
|
||||
|
||||
Most phases use bus, type, and class callbacks (that is, methods defined in
|
||||
dev->bus->pm, dev->type->pm, and dev->class->pm). The prepare and complete
|
||||
phases are exceptions; they use only bus callbacks. When multiple callbacks
|
||||
are used in a phase, they are invoked in the order: <class, type, bus> during
|
||||
power-down transitions and in the opposite order during power-up transitions.
|
||||
For example, during the suspend phase the PM core invokes
|
||||
|
||||
dev->class->pm.suspend(dev);
|
||||
dev->type->pm.suspend(dev);
|
||||
dev->bus->pm.suspend(dev);
|
||||
|
||||
before moving on to the next device, whereas during the resume phase the core
|
||||
invokes
|
||||
|
||||
dev->bus->pm.resume(dev);
|
||||
dev->type->pm.resume(dev);
|
||||
dev->class->pm.resume(dev);
|
||||
All phases use bus, type, or class callbacks (that is, methods defined in
|
||||
dev->bus->pm, dev->type->pm, or dev->class->pm). These callbacks are mutually
|
||||
exclusive, so if the device type provides a struct dev_pm_ops object pointed to
|
||||
by its pm field (i.e. both dev->type and dev->type->pm are defined), the
|
||||
callbacks included in that object (i.e. dev->type->pm) will be used. Otherwise,
|
||||
if the class provides a struct dev_pm_ops object pointed to by its pm field
|
||||
(i.e. both dev->class and dev->class->pm are defined), the PM core will use the
|
||||
callbacks from that object (i.e. dev->class->pm). Finally, if the pm fields of
|
||||
both the device type and class objects are NULL (or those objects do not exist),
|
||||
the callbacks provided by the bus (that is, the callbacks from dev->bus->pm)
|
||||
will be used (this allows device types to override callbacks provided by bus
|
||||
types or classes if necessary).
|
||||
|
||||
These callbacks may in turn invoke device- or driver-specific methods stored in
|
||||
dev->driver->pm, but they don't have to.
|
||||
|
@ -507,6 +502,49 @@ routines. Nevertheless, different callback pointers are used in case there is a
|
|||
situation where it actually matters.
|
||||
|
||||
|
||||
Device Power Domains
|
||||
--------------------
|
||||
Sometimes devices share reference clocks or other power resources. In those
|
||||
cases it generally is not possible to put devices into low-power states
|
||||
individually. Instead, a set of devices sharing a power resource can be put
|
||||
into a low-power state together at the same time by turning off the shared
|
||||
power resource. Of course, they also need to be put into the full-power state
|
||||
together, by turning the shared power resource on. A set of devices with this
|
||||
property is often referred to as a power domain.
|
||||
|
||||
Support for power domains is provided through the pwr_domain field of struct
|
||||
device. This field is a pointer to an object of type struct dev_power_domain,
|
||||
defined in include/linux/pm.h, providing a set of power management callbacks
|
||||
analogous to the subsystem-level and device driver callbacks that are executed
|
||||
for the given device during all power transitions, in addition to the respective
|
||||
subsystem-level callbacks. Specifically, the power domain "suspend" callbacks
|
||||
(i.e. ->runtime_suspend(), ->suspend(), ->freeze(), ->poweroff(), etc.) are
|
||||
executed after the analogous subsystem-level callbacks, while the power domain
|
||||
"resume" callbacks (i.e. ->runtime_resume(), ->resume(), ->thaw(), ->restore,
|
||||
etc.) are executed before the analogous subsystem-level callbacks. Error codes
|
||||
returned by the "suspend" and "resume" power domain callbacks are ignored.
|
||||
|
||||
Power domain ->runtime_idle() callback is executed before the subsystem-level
|
||||
->runtime_idle() callback and the result returned by it is not ignored. Namely,
|
||||
if it returns error code, the subsystem-level ->runtime_idle() callback will not
|
||||
be called and the helper function rpm_idle() executing it will return error
|
||||
code. This mechanism is intended to help platforms where saving device state
|
||||
is a time consuming operation and should only be carried out if all devices
|
||||
in the power domain are idle, before turning off the shared power resource(s).
|
||||
Namely, the power domain ->runtime_idle() callback may return error code until
|
||||
the pm_runtime_idle() helper (or its asychronous version) has been called for
|
||||
all devices in the power domain (it is recommended that the returned error code
|
||||
be -EBUSY in those cases), preventing the subsystem-level ->runtime_idle()
|
||||
callback from being run prematurely.
|
||||
|
||||
The support for device power domains is only relevant to platforms needing to
|
||||
use the same subsystem-level (e.g. platform bus type) and device driver power
|
||||
management callbacks in many different power domain configurations and wanting
|
||||
to avoid incorporating the support for power domains into the subsystem-level
|
||||
callbacks. The other platforms need not implement it or take it into account
|
||||
in any way.
|
||||
|
||||
|
||||
System Devices
|
||||
--------------
|
||||
System devices (sysdevs) follow a slightly different API, which can be found in
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
Run-time Power Management Framework for I/O Devices
|
||||
|
||||
(C) 2009 Rafael J. Wysocki <rjw@sisk.pl>, Novell Inc.
|
||||
(C) 2009-2011 Rafael J. Wysocki <rjw@sisk.pl>, Novell Inc.
|
||||
(C) 2010 Alan Stern <stern@rowland.harvard.edu>
|
||||
|
||||
1. Introduction
|
||||
|
@ -44,11 +44,12 @@ struct dev_pm_ops {
|
|||
};
|
||||
|
||||
The ->runtime_suspend(), ->runtime_resume() and ->runtime_idle() callbacks are
|
||||
executed by the PM core for either the bus type, or device type (if the bus
|
||||
type's callback is not defined), or device class (if the bus type's and device
|
||||
type's callbacks are not defined) of given device. The bus type, device type
|
||||
and device class callbacks are referred to as subsystem-level callbacks in what
|
||||
follows.
|
||||
executed by the PM core for either the device type, or the class (if the device
|
||||
type's struct dev_pm_ops object does not exist), or the bus type (if the
|
||||
device type's and class' struct dev_pm_ops objects do not exist) of the given
|
||||
device (this allows device types to override callbacks provided by bus types or
|
||||
classes if necessary). The bus type, device type and class callbacks are
|
||||
referred to as subsystem-level callbacks in what follows.
|
||||
|
||||
By default, the callbacks are always invoked in process context with interrupts
|
||||
enabled. However, subsystems can use the pm_runtime_irq_safe() helper function
|
||||
|
|
|
@ -62,12 +62,12 @@ setup via another operating system for it to use. Despite the
|
|||
inconvenience, this method requires minimal work by the kernel, since
|
||||
the firmware will also handle restoring memory contents on resume.
|
||||
|
||||
For suspend-to-disk, a mechanism called swsusp called 'swsusp' (Swap
|
||||
Suspend) is used to write memory contents to free swap space.
|
||||
swsusp has some restrictive requirements, but should work in most
|
||||
cases. Some, albeit outdated, documentation can be found in
|
||||
Documentation/power/swsusp.txt. Alternatively, userspace can do most
|
||||
of the actual suspend to disk work, see userland-swsusp.txt.
|
||||
For suspend-to-disk, a mechanism called 'swsusp' (Swap Suspend) is used
|
||||
to write memory contents to free swap space. swsusp has some restrictive
|
||||
requirements, but should work in most cases. Some, albeit outdated,
|
||||
documentation can be found in Documentation/power/swsusp.txt.
|
||||
Alternatively, userspace can do most of the actual suspend to disk work,
|
||||
see userland-swsusp.txt.
|
||||
|
||||
Once memory state is written to disk, the system may either enter a
|
||||
low-power state (like ACPI S4), or it may simply power down. Powering
|
||||
|
|
|
@ -227,6 +227,7 @@
|
|||
#include <linux/suspend.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/acpi.h>
|
||||
|
||||
#include <asm/system.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
@ -2331,12 +2332,11 @@ static int __init apm_init(void)
|
|||
apm_info.disabled = 1;
|
||||
return -ENODEV;
|
||||
}
|
||||
if (pm_flags & PM_ACPI) {
|
||||
if (!acpi_disabled) {
|
||||
printk(KERN_NOTICE "apm: overridden by ACPI.\n");
|
||||
apm_info.disabled = 1;
|
||||
return -ENODEV;
|
||||
}
|
||||
pm_flags |= PM_APM;
|
||||
|
||||
/*
|
||||
* Set up the long jump entry point to the APM BIOS, which is called
|
||||
|
@ -2428,7 +2428,6 @@ static void __exit apm_exit(void)
|
|||
kthread_stop(kapmd_task);
|
||||
kapmd_task = NULL;
|
||||
}
|
||||
pm_flags &= ~PM_APM;
|
||||
}
|
||||
|
||||
module_init(apm_init);
|
||||
|
|
|
@ -38,7 +38,7 @@ config XEN_MAX_DOMAIN_MEMORY
|
|||
|
||||
config XEN_SAVE_RESTORE
|
||||
bool
|
||||
depends on XEN && PM
|
||||
depends on XEN
|
||||
default y
|
||||
|
||||
config XEN_DEBUG_FS
|
||||
|
|
|
@ -7,7 +7,6 @@ menuconfig ACPI
|
|||
depends on !IA64_HP_SIM
|
||||
depends on IA64 || X86
|
||||
depends on PCI
|
||||
depends on PM
|
||||
select PNP
|
||||
default y
|
||||
help
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
#include <acpi/acpi_bus.h>
|
||||
#include <acpi/acpi_drivers.h>
|
||||
#include <linux/dmi.h>
|
||||
#include <linux/suspend.h>
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
|
@ -1006,8 +1007,7 @@ struct kobject *acpi_kobj;
|
|||
|
||||
static int __init acpi_init(void)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
int result;
|
||||
|
||||
if (acpi_disabled) {
|
||||
printk(KERN_INFO PREFIX "Interpreter disabled.\n");
|
||||
|
@ -1022,29 +1022,18 @@ static int __init acpi_init(void)
|
|||
|
||||
init_acpi_device_notify();
|
||||
result = acpi_bus_init();
|
||||
|
||||
if (!result) {
|
||||
pci_mmcfg_late_init();
|
||||
if (!(pm_flags & PM_APM))
|
||||
pm_flags |= PM_ACPI;
|
||||
else {
|
||||
printk(KERN_INFO PREFIX
|
||||
"APM is already active, exiting\n");
|
||||
disable_acpi();
|
||||
result = -ENODEV;
|
||||
}
|
||||
} else
|
||||
if (result) {
|
||||
disable_acpi();
|
||||
|
||||
if (acpi_disabled)
|
||||
return result;
|
||||
}
|
||||
|
||||
pci_mmcfg_late_init();
|
||||
acpi_scan_init();
|
||||
acpi_ec_init();
|
||||
acpi_debugfs_init();
|
||||
acpi_sleep_proc_init();
|
||||
acpi_wakeup_device_init();
|
||||
return result;
|
||||
return 0;
|
||||
}
|
||||
|
||||
subsys_initcall(acpi_init);
|
||||
|
|
|
@ -585,7 +585,7 @@ int acpi_suspend(u32 acpi_state)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_OPS
|
||||
#ifdef CONFIG_PM
|
||||
/**
|
||||
* acpi_pm_device_sleep_state - return preferred power state of ACPI device
|
||||
* in the system sleep state given by %acpi_target_sleep_state
|
||||
|
@ -671,7 +671,7 @@ int acpi_pm_device_sleep_state(struct device *dev, int *d_min_p)
|
|||
*d_min_p = d_min;
|
||||
return d_max;
|
||||
}
|
||||
#endif /* CONFIG_PM_OPS */
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
/**
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# Makefile for the Linux device tree
|
||||
|
||||
obj-y := core.o sys.o bus.o dd.o \
|
||||
obj-y := core.o sys.o bus.o dd.o syscore.o \
|
||||
driver.o class.o platform.o \
|
||||
cpu.o firmware.o init.o map.o devres.o \
|
||||
attribute_container.o transport_class.o
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
obj-$(CONFIG_PM) += sysfs.o
|
||||
obj-$(CONFIG_PM) += sysfs.o generic_ops.o
|
||||
obj-$(CONFIG_PM_SLEEP) += main.o wakeup.o
|
||||
obj-$(CONFIG_PM_RUNTIME) += runtime.o
|
||||
obj-$(CONFIG_PM_OPS) += generic_ops.o
|
||||
obj-$(CONFIG_PM_TRACE_RTC) += trace.o
|
||||
obj-$(CONFIG_PM_OPP) += opp.o
|
||||
|
||||
|
|
|
@ -423,26 +423,22 @@ static int device_resume_noirq(struct device *dev, pm_message_t state)
|
|||
TRACE_DEVICE(dev);
|
||||
TRACE_RESUME(0);
|
||||
|
||||
if (dev->bus && dev->bus->pm) {
|
||||
pm_dev_dbg(dev, state, "EARLY ");
|
||||
error = pm_noirq_op(dev, dev->bus->pm, state);
|
||||
if (error)
|
||||
goto End;
|
||||
if (dev->pwr_domain) {
|
||||
pm_dev_dbg(dev, state, "EARLY power domain ");
|
||||
pm_noirq_op(dev, &dev->pwr_domain->ops, state);
|
||||
}
|
||||
|
||||
if (dev->type && dev->type->pm) {
|
||||
pm_dev_dbg(dev, state, "EARLY type ");
|
||||
error = pm_noirq_op(dev, dev->type->pm, state);
|
||||
if (error)
|
||||
goto End;
|
||||
}
|
||||
|
||||
if (dev->class && dev->class->pm) {
|
||||
} else if (dev->class && dev->class->pm) {
|
||||
pm_dev_dbg(dev, state, "EARLY class ");
|
||||
error = pm_noirq_op(dev, dev->class->pm, state);
|
||||
} else if (dev->bus && dev->bus->pm) {
|
||||
pm_dev_dbg(dev, state, "EARLY ");
|
||||
error = pm_noirq_op(dev, dev->bus->pm, state);
|
||||
}
|
||||
|
||||
End:
|
||||
TRACE_RESUME(error);
|
||||
return error;
|
||||
}
|
||||
|
@ -518,6 +514,29 @@ static int device_resume(struct device *dev, pm_message_t state, bool async)
|
|||
|
||||
dev->power.in_suspend = false;
|
||||
|
||||
if (dev->pwr_domain) {
|
||||
pm_dev_dbg(dev, state, "power domain ");
|
||||
pm_op(dev, &dev->pwr_domain->ops, state);
|
||||
}
|
||||
|
||||
if (dev->type && dev->type->pm) {
|
||||
pm_dev_dbg(dev, state, "type ");
|
||||
error = pm_op(dev, dev->type->pm, state);
|
||||
goto End;
|
||||
}
|
||||
|
||||
if (dev->class) {
|
||||
if (dev->class->pm) {
|
||||
pm_dev_dbg(dev, state, "class ");
|
||||
error = pm_op(dev, dev->class->pm, state);
|
||||
goto End;
|
||||
} else if (dev->class->resume) {
|
||||
pm_dev_dbg(dev, state, "legacy class ");
|
||||
error = legacy_resume(dev, dev->class->resume);
|
||||
goto End;
|
||||
}
|
||||
}
|
||||
|
||||
if (dev->bus) {
|
||||
if (dev->bus->pm) {
|
||||
pm_dev_dbg(dev, state, "");
|
||||
|
@ -526,28 +545,8 @@ static int device_resume(struct device *dev, pm_message_t state, bool async)
|
|||
pm_dev_dbg(dev, state, "legacy ");
|
||||
error = legacy_resume(dev, dev->bus->resume);
|
||||
}
|
||||
if (error)
|
||||
goto End;
|
||||
}
|
||||
|
||||
if (dev->type) {
|
||||
if (dev->type->pm) {
|
||||
pm_dev_dbg(dev, state, "type ");
|
||||
error = pm_op(dev, dev->type->pm, state);
|
||||
}
|
||||
if (error)
|
||||
goto End;
|
||||
}
|
||||
|
||||
if (dev->class) {
|
||||
if (dev->class->pm) {
|
||||
pm_dev_dbg(dev, state, "class ");
|
||||
error = pm_op(dev, dev->class->pm, state);
|
||||
} else if (dev->class->resume) {
|
||||
pm_dev_dbg(dev, state, "legacy class ");
|
||||
error = legacy_resume(dev, dev->class->resume);
|
||||
}
|
||||
}
|
||||
End:
|
||||
device_unlock(dev);
|
||||
complete_all(&dev->power.completion);
|
||||
|
@ -629,19 +628,23 @@ static void device_complete(struct device *dev, pm_message_t state)
|
|||
{
|
||||
device_lock(dev);
|
||||
|
||||
if (dev->class && dev->class->pm && dev->class->pm->complete) {
|
||||
pm_dev_dbg(dev, state, "completing class ");
|
||||
dev->class->pm->complete(dev);
|
||||
if (dev->pwr_domain && dev->pwr_domain->ops.complete) {
|
||||
pm_dev_dbg(dev, state, "completing power domain ");
|
||||
dev->pwr_domain->ops.complete(dev);
|
||||
}
|
||||
|
||||
if (dev->type && dev->type->pm && dev->type->pm->complete) {
|
||||
if (dev->type && dev->type->pm) {
|
||||
pm_dev_dbg(dev, state, "completing type ");
|
||||
dev->type->pm->complete(dev);
|
||||
}
|
||||
|
||||
if (dev->bus && dev->bus->pm && dev->bus->pm->complete) {
|
||||
if (dev->type->pm->complete)
|
||||
dev->type->pm->complete(dev);
|
||||
} else if (dev->class && dev->class->pm) {
|
||||
pm_dev_dbg(dev, state, "completing class ");
|
||||
if (dev->class->pm->complete)
|
||||
dev->class->pm->complete(dev);
|
||||
} else if (dev->bus && dev->bus->pm) {
|
||||
pm_dev_dbg(dev, state, "completing ");
|
||||
dev->bus->pm->complete(dev);
|
||||
if (dev->bus->pm->complete)
|
||||
dev->bus->pm->complete(dev);
|
||||
}
|
||||
|
||||
device_unlock(dev);
|
||||
|
@ -669,7 +672,6 @@ static void dpm_complete(pm_message_t state)
|
|||
mutex_unlock(&dpm_list_mtx);
|
||||
|
||||
device_complete(dev, state);
|
||||
pm_runtime_put_sync(dev);
|
||||
|
||||
mutex_lock(&dpm_list_mtx);
|
||||
put_device(dev);
|
||||
|
@ -727,29 +729,31 @@ static pm_message_t resume_event(pm_message_t sleep_state)
|
|||
*/
|
||||
static int device_suspend_noirq(struct device *dev, pm_message_t state)
|
||||
{
|
||||
int error = 0;
|
||||
|
||||
if (dev->class && dev->class->pm) {
|
||||
pm_dev_dbg(dev, state, "LATE class ");
|
||||
error = pm_noirq_op(dev, dev->class->pm, state);
|
||||
if (error)
|
||||
goto End;
|
||||
}
|
||||
int error;
|
||||
|
||||
if (dev->type && dev->type->pm) {
|
||||
pm_dev_dbg(dev, state, "LATE type ");
|
||||
error = pm_noirq_op(dev, dev->type->pm, state);
|
||||
if (error)
|
||||
goto End;
|
||||
}
|
||||
|
||||
if (dev->bus && dev->bus->pm) {
|
||||
return error;
|
||||
} else if (dev->class && dev->class->pm) {
|
||||
pm_dev_dbg(dev, state, "LATE class ");
|
||||
error = pm_noirq_op(dev, dev->class->pm, state);
|
||||
if (error)
|
||||
return error;
|
||||
} else if (dev->bus && dev->bus->pm) {
|
||||
pm_dev_dbg(dev, state, "LATE ");
|
||||
error = pm_noirq_op(dev, dev->bus->pm, state);
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
|
||||
End:
|
||||
return error;
|
||||
if (dev->pwr_domain) {
|
||||
pm_dev_dbg(dev, state, "LATE power domain ");
|
||||
pm_noirq_op(dev, &dev->pwr_domain->ops, state);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -836,25 +840,22 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
|
|||
goto End;
|
||||
}
|
||||
|
||||
if (dev->type && dev->type->pm) {
|
||||
pm_dev_dbg(dev, state, "type ");
|
||||
error = pm_op(dev, dev->type->pm, state);
|
||||
goto Domain;
|
||||
}
|
||||
|
||||
if (dev->class) {
|
||||
if (dev->class->pm) {
|
||||
pm_dev_dbg(dev, state, "class ");
|
||||
error = pm_op(dev, dev->class->pm, state);
|
||||
goto Domain;
|
||||
} else if (dev->class->suspend) {
|
||||
pm_dev_dbg(dev, state, "legacy class ");
|
||||
error = legacy_suspend(dev, state, dev->class->suspend);
|
||||
goto Domain;
|
||||
}
|
||||
if (error)
|
||||
goto End;
|
||||
}
|
||||
|
||||
if (dev->type) {
|
||||
if (dev->type->pm) {
|
||||
pm_dev_dbg(dev, state, "type ");
|
||||
error = pm_op(dev, dev->type->pm, state);
|
||||
}
|
||||
if (error)
|
||||
goto End;
|
||||
}
|
||||
|
||||
if (dev->bus) {
|
||||
|
@ -867,6 +868,12 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
|
|||
}
|
||||
}
|
||||
|
||||
Domain:
|
||||
if (!error && dev->pwr_domain) {
|
||||
pm_dev_dbg(dev, state, "power domain ");
|
||||
pm_op(dev, &dev->pwr_domain->ops, state);
|
||||
}
|
||||
|
||||
End:
|
||||
device_unlock(dev);
|
||||
complete_all(&dev->power.completion);
|
||||
|
@ -957,27 +964,34 @@ static int device_prepare(struct device *dev, pm_message_t state)
|
|||
|
||||
device_lock(dev);
|
||||
|
||||
if (dev->bus && dev->bus->pm && dev->bus->pm->prepare) {
|
||||
if (dev->type && dev->type->pm) {
|
||||
pm_dev_dbg(dev, state, "preparing type ");
|
||||
if (dev->type->pm->prepare)
|
||||
error = dev->type->pm->prepare(dev);
|
||||
suspend_report_result(dev->type->pm->prepare, error);
|
||||
if (error)
|
||||
goto End;
|
||||
} else if (dev->class && dev->class->pm) {
|
||||
pm_dev_dbg(dev, state, "preparing class ");
|
||||
if (dev->class->pm->prepare)
|
||||
error = dev->class->pm->prepare(dev);
|
||||
suspend_report_result(dev->class->pm->prepare, error);
|
||||
if (error)
|
||||
goto End;
|
||||
} else if (dev->bus && dev->bus->pm) {
|
||||
pm_dev_dbg(dev, state, "preparing ");
|
||||
error = dev->bus->pm->prepare(dev);
|
||||
if (dev->bus->pm->prepare)
|
||||
error = dev->bus->pm->prepare(dev);
|
||||
suspend_report_result(dev->bus->pm->prepare, error);
|
||||
if (error)
|
||||
goto End;
|
||||
}
|
||||
|
||||
if (dev->type && dev->type->pm && dev->type->pm->prepare) {
|
||||
pm_dev_dbg(dev, state, "preparing type ");
|
||||
error = dev->type->pm->prepare(dev);
|
||||
suspend_report_result(dev->type->pm->prepare, error);
|
||||
if (error)
|
||||
goto End;
|
||||
if (dev->pwr_domain && dev->pwr_domain->ops.prepare) {
|
||||
pm_dev_dbg(dev, state, "preparing power domain ");
|
||||
dev->pwr_domain->ops.prepare(dev);
|
||||
}
|
||||
|
||||
if (dev->class && dev->class->pm && dev->class->pm->prepare) {
|
||||
pm_dev_dbg(dev, state, "preparing class ");
|
||||
error = dev->class->pm->prepare(dev);
|
||||
suspend_report_result(dev->class->pm->prepare, error);
|
||||
}
|
||||
End:
|
||||
device_unlock(dev);
|
||||
|
||||
|
@ -1005,12 +1019,9 @@ static int dpm_prepare(pm_message_t state)
|
|||
if (pm_runtime_barrier(dev) && device_may_wakeup(dev))
|
||||
pm_wakeup_event(dev, 0);
|
||||
|
||||
if (pm_wakeup_pending()) {
|
||||
pm_runtime_put_sync(dev);
|
||||
error = -EBUSY;
|
||||
} else {
|
||||
error = device_prepare(dev, state);
|
||||
}
|
||||
pm_runtime_put_sync(dev);
|
||||
error = pm_wakeup_pending() ?
|
||||
-EBUSY : device_prepare(dev, state);
|
||||
|
||||
mutex_lock(&dpm_list_mtx);
|
||||
if (error) {
|
||||
|
|
|
@ -222,7 +222,7 @@ int opp_get_opp_count(struct device *dev)
|
|||
* opp_find_freq_exact() - search for an exact frequency
|
||||
* @dev: device for which we do this operation
|
||||
* @freq: frequency to search for
|
||||
* @is_available: true/false - match for available opp
|
||||
* @available: true/false - match for available opp
|
||||
*
|
||||
* Searches for exact match in the opp list and returns pointer to the matching
|
||||
* opp if found, else returns ERR_PTR in case of error and should be handled
|
||||
|
|
|
@ -58,19 +58,18 @@ static inline void device_pm_move_last(struct device *dev) {}
|
|||
* sysfs.c
|
||||
*/
|
||||
|
||||
extern int dpm_sysfs_add(struct device *);
|
||||
extern void dpm_sysfs_remove(struct device *);
|
||||
extern void rpm_sysfs_remove(struct device *);
|
||||
extern int dpm_sysfs_add(struct device *dev);
|
||||
extern void dpm_sysfs_remove(struct device *dev);
|
||||
extern void rpm_sysfs_remove(struct device *dev);
|
||||
extern int wakeup_sysfs_add(struct device *dev);
|
||||
extern void wakeup_sysfs_remove(struct device *dev);
|
||||
|
||||
#else /* CONFIG_PM */
|
||||
|
||||
static inline int dpm_sysfs_add(struct device *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void dpm_sysfs_remove(struct device *dev)
|
||||
{
|
||||
}
|
||||
static inline int dpm_sysfs_add(struct device *dev) { return 0; }
|
||||
static inline void dpm_sysfs_remove(struct device *dev) {}
|
||||
static inline void rpm_sysfs_remove(struct device *dev) {}
|
||||
static inline int wakeup_sysfs_add(struct device *dev) { return 0; }
|
||||
static inline void wakeup_sysfs_remove(struct device *dev) {}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -168,6 +168,7 @@ static int rpm_check_suspend_allowed(struct device *dev)
|
|||
static int rpm_idle(struct device *dev, int rpmflags)
|
||||
{
|
||||
int (*callback)(struct device *);
|
||||
int (*domain_callback)(struct device *);
|
||||
int retval;
|
||||
|
||||
retval = rpm_check_suspend_allowed(dev);
|
||||
|
@ -213,19 +214,28 @@ static int rpm_idle(struct device *dev, int rpmflags)
|
|||
|
||||
dev->power.idle_notification = true;
|
||||
|
||||
if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_idle)
|
||||
callback = dev->bus->pm->runtime_idle;
|
||||
else if (dev->type && dev->type->pm && dev->type->pm->runtime_idle)
|
||||
if (dev->type && dev->type->pm)
|
||||
callback = dev->type->pm->runtime_idle;
|
||||
else if (dev->class && dev->class->pm)
|
||||
callback = dev->class->pm->runtime_idle;
|
||||
else if (dev->bus && dev->bus->pm)
|
||||
callback = dev->bus->pm->runtime_idle;
|
||||
else
|
||||
callback = NULL;
|
||||
|
||||
if (callback) {
|
||||
if (dev->pwr_domain)
|
||||
domain_callback = dev->pwr_domain->ops.runtime_idle;
|
||||
else
|
||||
domain_callback = NULL;
|
||||
|
||||
if (callback || domain_callback) {
|
||||
spin_unlock_irq(&dev->power.lock);
|
||||
|
||||
callback(dev);
|
||||
if (domain_callback)
|
||||
retval = domain_callback(dev);
|
||||
|
||||
if (!retval && callback)
|
||||
callback(dev);
|
||||
|
||||
spin_lock_irq(&dev->power.lock);
|
||||
}
|
||||
|
@ -372,12 +382,12 @@ static int rpm_suspend(struct device *dev, int rpmflags)
|
|||
|
||||
__update_runtime_status(dev, RPM_SUSPENDING);
|
||||
|
||||
if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_suspend)
|
||||
callback = dev->bus->pm->runtime_suspend;
|
||||
else if (dev->type && dev->type->pm && dev->type->pm->runtime_suspend)
|
||||
if (dev->type && dev->type->pm)
|
||||
callback = dev->type->pm->runtime_suspend;
|
||||
else if (dev->class && dev->class->pm)
|
||||
callback = dev->class->pm->runtime_suspend;
|
||||
else if (dev->bus && dev->bus->pm)
|
||||
callback = dev->bus->pm->runtime_suspend;
|
||||
else
|
||||
callback = NULL;
|
||||
|
||||
|
@ -390,6 +400,8 @@ static int rpm_suspend(struct device *dev, int rpmflags)
|
|||
else
|
||||
pm_runtime_cancel_pending(dev);
|
||||
} else {
|
||||
if (dev->pwr_domain)
|
||||
rpm_callback(dev->pwr_domain->ops.runtime_suspend, dev);
|
||||
no_callback:
|
||||
__update_runtime_status(dev, RPM_SUSPENDED);
|
||||
pm_runtime_deactivate_timer(dev);
|
||||
|
@ -569,12 +581,15 @@ static int rpm_resume(struct device *dev, int rpmflags)
|
|||
|
||||
__update_runtime_status(dev, RPM_RESUMING);
|
||||
|
||||
if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_resume)
|
||||
callback = dev->bus->pm->runtime_resume;
|
||||
else if (dev->type && dev->type->pm && dev->type->pm->runtime_resume)
|
||||
if (dev->pwr_domain)
|
||||
rpm_callback(dev->pwr_domain->ops.runtime_resume, dev);
|
||||
|
||||
if (dev->type && dev->type->pm)
|
||||
callback = dev->type->pm->runtime_resume;
|
||||
else if (dev->class && dev->class->pm)
|
||||
callback = dev->class->pm->runtime_resume;
|
||||
else if (dev->bus && dev->bus->pm)
|
||||
callback = dev->bus->pm->runtime_resume;
|
||||
else
|
||||
callback = NULL;
|
||||
|
||||
|
|
|
@ -431,9 +431,28 @@ static ssize_t async_store(struct device *dev, struct device_attribute *attr,
|
|||
static DEVICE_ATTR(async, 0644, async_show, async_store);
|
||||
#endif /* CONFIG_PM_ADVANCED_DEBUG */
|
||||
|
||||
static struct attribute * power_attrs[] = {
|
||||
&dev_attr_wakeup.attr,
|
||||
static struct attribute *power_attrs[] = {
|
||||
#ifdef CONFIG_PM_ADVANCED_DEBUG
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
&dev_attr_async.attr,
|
||||
#endif
|
||||
#ifdef CONFIG_PM_RUNTIME
|
||||
&dev_attr_runtime_status.attr,
|
||||
&dev_attr_runtime_usage.attr,
|
||||
&dev_attr_runtime_active_kids.attr,
|
||||
&dev_attr_runtime_enabled.attr,
|
||||
#endif
|
||||
#endif /* CONFIG_PM_ADVANCED_DEBUG */
|
||||
NULL,
|
||||
};
|
||||
static struct attribute_group pm_attr_group = {
|
||||
.name = power_group_name,
|
||||
.attrs = power_attrs,
|
||||
};
|
||||
|
||||
static struct attribute *wakeup_attrs[] = {
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
&dev_attr_wakeup.attr,
|
||||
&dev_attr_wakeup_count.attr,
|
||||
&dev_attr_wakeup_active_count.attr,
|
||||
&dev_attr_wakeup_hit_count.attr,
|
||||
|
@ -441,26 +460,16 @@ static struct attribute * power_attrs[] = {
|
|||
&dev_attr_wakeup_total_time_ms.attr,
|
||||
&dev_attr_wakeup_max_time_ms.attr,
|
||||
&dev_attr_wakeup_last_time_ms.attr,
|
||||
#endif
|
||||
#ifdef CONFIG_PM_ADVANCED_DEBUG
|
||||
&dev_attr_async.attr,
|
||||
#ifdef CONFIG_PM_RUNTIME
|
||||
&dev_attr_runtime_status.attr,
|
||||
&dev_attr_runtime_usage.attr,
|
||||
&dev_attr_runtime_active_kids.attr,
|
||||
&dev_attr_runtime_enabled.attr,
|
||||
#endif
|
||||
#endif
|
||||
NULL,
|
||||
};
|
||||
static struct attribute_group pm_attr_group = {
|
||||
static struct attribute_group pm_wakeup_attr_group = {
|
||||
.name = power_group_name,
|
||||
.attrs = power_attrs,
|
||||
.attrs = wakeup_attrs,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_PM_RUNTIME
|
||||
|
||||
static struct attribute *runtime_attrs[] = {
|
||||
#ifdef CONFIG_PM_RUNTIME
|
||||
#ifndef CONFIG_PM_ADVANCED_DEBUG
|
||||
&dev_attr_runtime_status.attr,
|
||||
#endif
|
||||
|
@ -468,6 +477,7 @@ static struct attribute *runtime_attrs[] = {
|
|||
&dev_attr_runtime_suspended_time.attr,
|
||||
&dev_attr_runtime_active_time.attr,
|
||||
&dev_attr_autosuspend_delay_ms.attr,
|
||||
#endif /* CONFIG_PM_RUNTIME */
|
||||
NULL,
|
||||
};
|
||||
static struct attribute_group pm_runtime_attr_group = {
|
||||
|
@ -480,14 +490,41 @@ int dpm_sysfs_add(struct device *dev)
|
|||
int rc;
|
||||
|
||||
rc = sysfs_create_group(&dev->kobj, &pm_attr_group);
|
||||
if (rc == 0 && !dev->power.no_callbacks) {
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (pm_runtime_callbacks_present(dev)) {
|
||||
rc = sysfs_merge_group(&dev->kobj, &pm_runtime_attr_group);
|
||||
if (rc)
|
||||
sysfs_remove_group(&dev->kobj, &pm_attr_group);
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
if (device_can_wakeup(dev)) {
|
||||
rc = sysfs_merge_group(&dev->kobj, &pm_wakeup_attr_group);
|
||||
if (rc) {
|
||||
if (pm_runtime_callbacks_present(dev))
|
||||
sysfs_unmerge_group(&dev->kobj,
|
||||
&pm_runtime_attr_group);
|
||||
goto err_out;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
||||
err_out:
|
||||
sysfs_remove_group(&dev->kobj, &pm_attr_group);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int wakeup_sysfs_add(struct device *dev)
|
||||
{
|
||||
return sysfs_merge_group(&dev->kobj, &pm_wakeup_attr_group);
|
||||
}
|
||||
|
||||
void wakeup_sysfs_remove(struct device *dev)
|
||||
{
|
||||
sysfs_unmerge_group(&dev->kobj, &pm_wakeup_attr_group);
|
||||
}
|
||||
|
||||
void rpm_sysfs_remove(struct device *dev)
|
||||
{
|
||||
sysfs_unmerge_group(&dev->kobj, &pm_runtime_attr_group);
|
||||
|
@ -496,19 +533,6 @@ void rpm_sysfs_remove(struct device *dev)
|
|||
void dpm_sysfs_remove(struct device *dev)
|
||||
{
|
||||
rpm_sysfs_remove(dev);
|
||||
sysfs_unmerge_group(&dev->kobj, &pm_wakeup_attr_group);
|
||||
sysfs_remove_group(&dev->kobj, &pm_attr_group);
|
||||
}
|
||||
|
||||
#else /* CONFIG_PM_RUNTIME */
|
||||
|
||||
int dpm_sysfs_add(struct device * dev)
|
||||
{
|
||||
return sysfs_create_group(&dev->kobj, &pm_attr_group);
|
||||
}
|
||||
|
||||
void dpm_sysfs_remove(struct device * dev)
|
||||
{
|
||||
sysfs_remove_group(&dev->kobj, &pm_attr_group);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -112,7 +112,7 @@ static unsigned int read_magic_time(void)
|
|||
unsigned int val;
|
||||
|
||||
get_rtc_time(&time);
|
||||
printk("Time: %2d:%02d:%02d Date: %02d/%02d/%02d\n",
|
||||
pr_info("Time: %2d:%02d:%02d Date: %02d/%02d/%02d\n",
|
||||
time.tm_hour, time.tm_min, time.tm_sec,
|
||||
time.tm_mon + 1, time.tm_mday, time.tm_year % 100);
|
||||
val = time.tm_year; /* 100 years */
|
||||
|
@ -179,7 +179,7 @@ static int show_file_hash(unsigned int value)
|
|||
unsigned int hash = hash_string(lineno, file, FILEHASH);
|
||||
if (hash != value)
|
||||
continue;
|
||||
printk(" hash matches %s:%u\n", file, lineno);
|
||||
pr_info(" hash matches %s:%u\n", file, lineno);
|
||||
match++;
|
||||
}
|
||||
return match;
|
||||
|
@ -255,7 +255,7 @@ static int late_resume_init(void)
|
|||
val = val / FILEHASH;
|
||||
dev = val /* % DEVHASH */;
|
||||
|
||||
printk(" Magic number: %d:%d:%d\n", user, file, dev);
|
||||
pr_info(" Magic number: %d:%d:%d\n", user, file, dev);
|
||||
show_file_hash(file);
|
||||
show_dev_hash(dev);
|
||||
return 0;
|
||||
|
|
|
@ -24,12 +24,26 @@
|
|||
*/
|
||||
bool events_check_enabled;
|
||||
|
||||
/* The counter of registered wakeup events. */
|
||||
static atomic_t event_count = ATOMIC_INIT(0);
|
||||
/* A preserved old value of event_count. */
|
||||
/*
|
||||
* Combined counters of registered wakeup events and wakeup events in progress.
|
||||
* They need to be modified together atomically, so it's better to use one
|
||||
* atomic variable to hold them both.
|
||||
*/
|
||||
static atomic_t combined_event_count = ATOMIC_INIT(0);
|
||||
|
||||
#define IN_PROGRESS_BITS (sizeof(int) * 4)
|
||||
#define MAX_IN_PROGRESS ((1 << IN_PROGRESS_BITS) - 1)
|
||||
|
||||
static void split_counters(unsigned int *cnt, unsigned int *inpr)
|
||||
{
|
||||
unsigned int comb = atomic_read(&combined_event_count);
|
||||
|
||||
*cnt = (comb >> IN_PROGRESS_BITS);
|
||||
*inpr = comb & MAX_IN_PROGRESS;
|
||||
}
|
||||
|
||||
/* A preserved old value of the events counter. */
|
||||
static unsigned int saved_count;
|
||||
/* The counter of wakeup events being processed. */
|
||||
static atomic_t events_in_progress = ATOMIC_INIT(0);
|
||||
|
||||
static DEFINE_SPINLOCK(events_lock);
|
||||
|
||||
|
@ -227,6 +241,35 @@ int device_wakeup_disable(struct device *dev)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(device_wakeup_disable);
|
||||
|
||||
/**
|
||||
* device_set_wakeup_capable - Set/reset device wakeup capability flag.
|
||||
* @dev: Device to handle.
|
||||
* @capable: Whether or not @dev is capable of waking up the system from sleep.
|
||||
*
|
||||
* If @capable is set, set the @dev's power.can_wakeup flag and add its
|
||||
* wakeup-related attributes to sysfs. Otherwise, unset the @dev's
|
||||
* power.can_wakeup flag and remove its wakeup-related attributes from sysfs.
|
||||
*
|
||||
* This function may sleep and it can't be called from any context where
|
||||
* sleeping is not allowed.
|
||||
*/
|
||||
void device_set_wakeup_capable(struct device *dev, bool capable)
|
||||
{
|
||||
if (!!dev->power.can_wakeup == !!capable)
|
||||
return;
|
||||
|
||||
if (device_is_registered(dev)) {
|
||||
if (capable) {
|
||||
if (wakeup_sysfs_add(dev))
|
||||
return;
|
||||
} else {
|
||||
wakeup_sysfs_remove(dev);
|
||||
}
|
||||
}
|
||||
dev->power.can_wakeup = capable;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(device_set_wakeup_capable);
|
||||
|
||||
/**
|
||||
* device_init_wakeup - Device wakeup initialization.
|
||||
* @dev: Device to handle.
|
||||
|
@ -307,7 +350,8 @@ static void wakeup_source_activate(struct wakeup_source *ws)
|
|||
ws->timer_expires = jiffies;
|
||||
ws->last_time = ktime_get();
|
||||
|
||||
atomic_inc(&events_in_progress);
|
||||
/* Increment the counter of events in progress. */
|
||||
atomic_inc(&combined_event_count);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -394,14 +438,10 @@ static void wakeup_source_deactivate(struct wakeup_source *ws)
|
|||
del_timer(&ws->timer);
|
||||
|
||||
/*
|
||||
* event_count has to be incremented before events_in_progress is
|
||||
* modified, so that the callers of pm_check_wakeup_events() and
|
||||
* pm_save_wakeup_count() don't see the old value of event_count and
|
||||
* events_in_progress equal to zero at the same time.
|
||||
* Increment the counter of registered wakeup events and decrement the
|
||||
* couter of wakeup events in progress simultaneously.
|
||||
*/
|
||||
atomic_inc(&event_count);
|
||||
smp_mb__before_atomic_dec();
|
||||
atomic_dec(&events_in_progress);
|
||||
atomic_add(MAX_IN_PROGRESS, &combined_event_count);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -556,8 +596,10 @@ bool pm_wakeup_pending(void)
|
|||
|
||||
spin_lock_irqsave(&events_lock, flags);
|
||||
if (events_check_enabled) {
|
||||
ret = ((unsigned int)atomic_read(&event_count) != saved_count)
|
||||
|| atomic_read(&events_in_progress);
|
||||
unsigned int cnt, inpr;
|
||||
|
||||
split_counters(&cnt, &inpr);
|
||||
ret = (cnt != saved_count || inpr > 0);
|
||||
events_check_enabled = !ret;
|
||||
}
|
||||
spin_unlock_irqrestore(&events_lock, flags);
|
||||
|
@ -573,25 +615,25 @@ bool pm_wakeup_pending(void)
|
|||
* Store the number of registered wakeup events at the address in @count. Block
|
||||
* if the current number of wakeup events being processed is nonzero.
|
||||
*
|
||||
* Return false if the wait for the number of wakeup events being processed to
|
||||
* Return 'false' if the wait for the number of wakeup events being processed to
|
||||
* drop down to zero has been interrupted by a signal (and the current number
|
||||
* of wakeup events being processed is still nonzero). Otherwise return true.
|
||||
* of wakeup events being processed is still nonzero). Otherwise return 'true'.
|
||||
*/
|
||||
bool pm_get_wakeup_count(unsigned int *count)
|
||||
{
|
||||
bool ret;
|
||||
unsigned int cnt, inpr;
|
||||
|
||||
if (capable(CAP_SYS_ADMIN))
|
||||
events_check_enabled = false;
|
||||
|
||||
while (atomic_read(&events_in_progress) && !signal_pending(current)) {
|
||||
for (;;) {
|
||||
split_counters(&cnt, &inpr);
|
||||
if (inpr == 0 || signal_pending(current))
|
||||
break;
|
||||
pm_wakeup_update_hit_counts();
|
||||
schedule_timeout_interruptible(msecs_to_jiffies(TIMEOUT));
|
||||
}
|
||||
|
||||
ret = !atomic_read(&events_in_progress);
|
||||
*count = atomic_read(&event_count);
|
||||
return ret;
|
||||
split_counters(&cnt, &inpr);
|
||||
*count = cnt;
|
||||
return !inpr;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -600,24 +642,25 @@ bool pm_get_wakeup_count(unsigned int *count)
|
|||
*
|
||||
* If @count is equal to the current number of registered wakeup events and the
|
||||
* current number of wakeup events being processed is zero, store @count as the
|
||||
* old number of registered wakeup events to be used by pm_check_wakeup_events()
|
||||
* and return true. Otherwise return false.
|
||||
* old number of registered wakeup events for pm_check_wakeup_events(), enable
|
||||
* wakeup events detection and return 'true'. Otherwise disable wakeup events
|
||||
* detection and return 'false'.
|
||||
*/
|
||||
bool pm_save_wakeup_count(unsigned int count)
|
||||
{
|
||||
bool ret = false;
|
||||
unsigned int cnt, inpr;
|
||||
|
||||
events_check_enabled = false;
|
||||
spin_lock_irq(&events_lock);
|
||||
if (count == (unsigned int)atomic_read(&event_count)
|
||||
&& !atomic_read(&events_in_progress)) {
|
||||
split_counters(&cnt, &inpr);
|
||||
if (cnt == count && inpr == 0) {
|
||||
saved_count = count;
|
||||
events_check_enabled = true;
|
||||
ret = true;
|
||||
}
|
||||
spin_unlock_irq(&events_lock);
|
||||
if (!ret)
|
||||
if (!events_check_enabled)
|
||||
pm_wakeup_update_hit_counts();
|
||||
return ret;
|
||||
return events_check_enabled;
|
||||
}
|
||||
|
||||
static struct dentry *wakeup_sources_stats_dentry;
|
||||
|
|
117
drivers/base/syscore.c
Normal file
117
drivers/base/syscore.c
Normal file
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
* syscore.c - Execution of system core operations.
|
||||
*
|
||||
* Copyright (C) 2011 Rafael J. Wysocki <rjw@sisk.pl>, Novell Inc.
|
||||
*
|
||||
* This file is released under the GPLv2.
|
||||
*/
|
||||
|
||||
#include <linux/syscore_ops.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
static LIST_HEAD(syscore_ops_list);
|
||||
static DEFINE_MUTEX(syscore_ops_lock);
|
||||
|
||||
/**
|
||||
* register_syscore_ops - Register a set of system core operations.
|
||||
* @ops: System core operations to register.
|
||||
*/
|
||||
void register_syscore_ops(struct syscore_ops *ops)
|
||||
{
|
||||
mutex_lock(&syscore_ops_lock);
|
||||
list_add_tail(&ops->node, &syscore_ops_list);
|
||||
mutex_unlock(&syscore_ops_lock);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(register_syscore_ops);
|
||||
|
||||
/**
|
||||
* unregister_syscore_ops - Unregister a set of system core operations.
|
||||
* @ops: System core operations to unregister.
|
||||
*/
|
||||
void unregister_syscore_ops(struct syscore_ops *ops)
|
||||
{
|
||||
mutex_lock(&syscore_ops_lock);
|
||||
list_del(&ops->node);
|
||||
mutex_unlock(&syscore_ops_lock);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(unregister_syscore_ops);
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
/**
|
||||
* syscore_suspend - Execute all the registered system core suspend callbacks.
|
||||
*
|
||||
* This function is executed with one CPU on-line and disabled interrupts.
|
||||
*/
|
||||
int syscore_suspend(void)
|
||||
{
|
||||
struct syscore_ops *ops;
|
||||
int ret = 0;
|
||||
|
||||
WARN_ONCE(!irqs_disabled(),
|
||||
"Interrupts enabled before system core suspend.\n");
|
||||
|
||||
list_for_each_entry_reverse(ops, &syscore_ops_list, node)
|
||||
if (ops->suspend) {
|
||||
if (initcall_debug)
|
||||
pr_info("PM: Calling %pF\n", ops->suspend);
|
||||
ret = ops->suspend();
|
||||
if (ret)
|
||||
goto err_out;
|
||||
WARN_ONCE(!irqs_disabled(),
|
||||
"Interrupts enabled after %pF\n", ops->suspend);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_out:
|
||||
pr_err("PM: System core suspend callback %pF failed.\n", ops->suspend);
|
||||
|
||||
list_for_each_entry_continue(ops, &syscore_ops_list, node)
|
||||
if (ops->resume)
|
||||
ops->resume();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* syscore_resume - Execute all the registered system core resume callbacks.
|
||||
*
|
||||
* This function is executed with one CPU on-line and disabled interrupts.
|
||||
*/
|
||||
void syscore_resume(void)
|
||||
{
|
||||
struct syscore_ops *ops;
|
||||
|
||||
WARN_ONCE(!irqs_disabled(),
|
||||
"Interrupts enabled before system core resume.\n");
|
||||
|
||||
list_for_each_entry(ops, &syscore_ops_list, node)
|
||||
if (ops->resume) {
|
||||
if (initcall_debug)
|
||||
pr_info("PM: Calling %pF\n", ops->resume);
|
||||
ops->resume();
|
||||
WARN_ONCE(!irqs_disabled(),
|
||||
"Interrupts enabled after %pF\n", ops->resume);
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_PM_SLEEP */
|
||||
|
||||
/**
|
||||
* syscore_shutdown - Execute all the registered system core shutdown callbacks.
|
||||
*/
|
||||
void syscore_shutdown(void)
|
||||
{
|
||||
struct syscore_ops *ops;
|
||||
|
||||
mutex_lock(&syscore_ops_lock);
|
||||
|
||||
list_for_each_entry_reverse(ops, &syscore_ops_list, node)
|
||||
if (ops->shutdown) {
|
||||
if (initcall_debug)
|
||||
pr_info("PM: Calling %pF\n", ops->shutdown);
|
||||
ops->shutdown();
|
||||
}
|
||||
|
||||
mutex_unlock(&syscore_ops_lock);
|
||||
}
|
|
@ -5338,7 +5338,7 @@ void e1000e_disable_aspm(struct pci_dev *pdev, u16 state)
|
|||
__e1000e_disable_aspm(pdev, state);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_OPS
|
||||
#ifdef CONFIG_PM
|
||||
static bool e1000e_pm_ready(struct e1000_adapter *adapter)
|
||||
{
|
||||
return !!adapter->tx_ring->buffer_info;
|
||||
|
@ -5489,7 +5489,7 @@ static int e1000_runtime_resume(struct device *dev)
|
|||
return __e1000_resume(pdev);
|
||||
}
|
||||
#endif /* CONFIG_PM_RUNTIME */
|
||||
#endif /* CONFIG_PM_OPS */
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
static void e1000_shutdown(struct pci_dev *pdev)
|
||||
{
|
||||
|
@ -6196,7 +6196,7 @@ static DEFINE_PCI_DEVICE_TABLE(e1000_pci_tbl) = {
|
|||
};
|
||||
MODULE_DEVICE_TABLE(pci, e1000_pci_tbl);
|
||||
|
||||
#ifdef CONFIG_PM_OPS
|
||||
#ifdef CONFIG_PM
|
||||
static const struct dev_pm_ops e1000_pm_ops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(e1000_suspend, e1000_resume)
|
||||
SET_RUNTIME_PM_OPS(e1000_runtime_suspend,
|
||||
|
@ -6210,7 +6210,7 @@ static struct pci_driver e1000_driver = {
|
|||
.id_table = e1000_pci_tbl,
|
||||
.probe = e1000_probe,
|
||||
.remove = __devexit_p(e1000_remove),
|
||||
#ifdef CONFIG_PM_OPS
|
||||
#ifdef CONFIG_PM
|
||||
.driver.pm = &e1000_pm_ops,
|
||||
#endif
|
||||
.shutdown = e1000_shutdown,
|
||||
|
|
|
@ -2446,7 +2446,7 @@ static struct pci_driver pch_gbe_pcidev = {
|
|||
.id_table = pch_gbe_pcidev_id,
|
||||
.probe = pch_gbe_probe,
|
||||
.remove = pch_gbe_remove,
|
||||
#ifdef CONFIG_PM_OPS
|
||||
#ifdef CONFIG_PM
|
||||
.driver.pm = &pch_gbe_pm_ops,
|
||||
#endif
|
||||
.shutdown = pch_gbe_shutdown,
|
||||
|
|
|
@ -431,7 +431,7 @@ static void pci_device_shutdown(struct device *dev)
|
|||
pci_msix_shutdown(pci_dev);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_OPS
|
||||
#ifdef CONFIG_PM
|
||||
|
||||
/* Auxiliary functions used for system resume and run-time resume. */
|
||||
|
||||
|
@ -1059,7 +1059,7 @@ static int pci_pm_runtime_idle(struct device *dev)
|
|||
|
||||
#endif /* !CONFIG_PM_RUNTIME */
|
||||
|
||||
#ifdef CONFIG_PM_OPS
|
||||
#ifdef CONFIG_PM
|
||||
|
||||
const struct dev_pm_ops pci_dev_pm_ops = {
|
||||
.prepare = pci_pm_prepare,
|
||||
|
|
|
@ -165,7 +165,7 @@ scsi_mod-$(CONFIG_SCSI_NETLINK) += scsi_netlink.o
|
|||
scsi_mod-$(CONFIG_SYSCTL) += scsi_sysctl.o
|
||||
scsi_mod-$(CONFIG_SCSI_PROC_FS) += scsi_proc.o
|
||||
scsi_mod-y += scsi_trace.o
|
||||
scsi_mod-$(CONFIG_PM_OPS) += scsi_pm.o
|
||||
scsi_mod-$(CONFIG_PM) += scsi_pm.o
|
||||
|
||||
scsi_tgt-y += scsi_tgt_lib.o scsi_tgt_if.o
|
||||
|
||||
|
|
|
@ -146,7 +146,7 @@ static inline void scsi_netlink_exit(void) {}
|
|||
#endif
|
||||
|
||||
/* scsi_pm.c */
|
||||
#ifdef CONFIG_PM_OPS
|
||||
#ifdef CONFIG_PM
|
||||
extern const struct dev_pm_ops scsi_bus_pm_ops;
|
||||
#endif
|
||||
#ifdef CONFIG_PM_RUNTIME
|
||||
|
|
|
@ -383,7 +383,7 @@ struct bus_type scsi_bus_type = {
|
|||
.name = "scsi",
|
||||
.match = scsi_bus_match,
|
||||
.uevent = scsi_bus_uevent,
|
||||
#ifdef CONFIG_PM_OPS
|
||||
#ifdef CONFIG_PM
|
||||
.pm = &scsi_bus_pm_ops,
|
||||
#endif
|
||||
};
|
||||
|
|
|
@ -335,7 +335,7 @@ void usb_hcd_pci_shutdown(struct pci_dev *dev)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(usb_hcd_pci_shutdown);
|
||||
|
||||
#ifdef CONFIG_PM_OPS
|
||||
#ifdef CONFIG_PM
|
||||
|
||||
#ifdef CONFIG_PPC_PMAC
|
||||
static void powermac_set_asic(struct pci_dev *pci_dev, int enable)
|
||||
|
@ -580,4 +580,4 @@ const struct dev_pm_ops usb_hcd_pci_pm_ops = {
|
|||
};
|
||||
EXPORT_SYMBOL_GPL(usb_hcd_pci_pm_ops);
|
||||
|
||||
#endif /* CONFIG_PM_OPS */
|
||||
#endif /* CONFIG_PM */
|
||||
|
|
|
@ -1465,6 +1465,7 @@ void usb_set_device_state(struct usb_device *udev,
|
|||
enum usb_device_state new_state)
|
||||
{
|
||||
unsigned long flags;
|
||||
int wakeup = -1;
|
||||
|
||||
spin_lock_irqsave(&device_state_lock, flags);
|
||||
if (udev->state == USB_STATE_NOTATTACHED)
|
||||
|
@ -1479,11 +1480,10 @@ void usb_set_device_state(struct usb_device *udev,
|
|||
|| new_state == USB_STATE_SUSPENDED)
|
||||
; /* No change to wakeup settings */
|
||||
else if (new_state == USB_STATE_CONFIGURED)
|
||||
device_set_wakeup_capable(&udev->dev,
|
||||
(udev->actconfig->desc.bmAttributes
|
||||
& USB_CONFIG_ATT_WAKEUP));
|
||||
wakeup = udev->actconfig->desc.bmAttributes
|
||||
& USB_CONFIG_ATT_WAKEUP;
|
||||
else
|
||||
device_set_wakeup_capable(&udev->dev, 0);
|
||||
wakeup = 0;
|
||||
}
|
||||
if (udev->state == USB_STATE_SUSPENDED &&
|
||||
new_state != USB_STATE_SUSPENDED)
|
||||
|
@ -1495,6 +1495,8 @@ void usb_set_device_state(struct usb_device *udev,
|
|||
} else
|
||||
recursively_mark_NOTATTACHED(udev);
|
||||
spin_unlock_irqrestore(&device_state_lock, flags);
|
||||
if (wakeup >= 0)
|
||||
device_set_wakeup_capable(&udev->dev, wakeup);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_set_device_state);
|
||||
|
||||
|
|
|
@ -381,7 +381,7 @@ struct acpi_pci_root *acpi_pci_find_root(acpi_handle handle);
|
|||
int acpi_enable_wakeup_device_power(struct acpi_device *dev, int state);
|
||||
int acpi_disable_wakeup_device_power(struct acpi_device *dev);
|
||||
|
||||
#ifdef CONFIG_PM_OPS
|
||||
#ifdef CONFIG_PM
|
||||
int acpi_pm_device_sleep_state(struct device *, int *);
|
||||
#else
|
||||
static inline int acpi_pm_device_sleep_state(struct device *d, int *p)
|
||||
|
|
|
@ -420,6 +420,7 @@ struct device {
|
|||
void *platform_data; /* Platform specific data, device
|
||||
core doesn't touch it */
|
||||
struct dev_pm_info power;
|
||||
struct dev_power_domain *pwr_domain;
|
||||
|
||||
#ifdef CONFIG_NUMA
|
||||
int numa_node; /* NUMA node this device is close to */
|
||||
|
|
|
@ -267,7 +267,7 @@ const struct dev_pm_ops name = { \
|
|||
* callbacks provided by device drivers supporting both the system sleep PM and
|
||||
* runtime PM, make the pm member point to generic_subsys_pm_ops.
|
||||
*/
|
||||
#ifdef CONFIG_PM_OPS
|
||||
#ifdef CONFIG_PM
|
||||
extern struct dev_pm_ops generic_subsys_pm_ops;
|
||||
#define GENERIC_SUBSYS_PM_OPS (&generic_subsys_pm_ops)
|
||||
#else
|
||||
|
@ -465,6 +465,14 @@ struct dev_pm_info {
|
|||
|
||||
extern void update_pm_runtime_accounting(struct device *dev);
|
||||
|
||||
/*
|
||||
* Power domains provide callbacks that are executed during system suspend,
|
||||
* hibernation, system resume and during runtime PM transitions along with
|
||||
* subsystem-level and driver-level callbacks.
|
||||
*/
|
||||
struct dev_power_domain {
|
||||
struct dev_pm_ops ops;
|
||||
};
|
||||
|
||||
/*
|
||||
* The PM_EVENT_ messages are also used by drivers implementing the legacy
|
||||
|
@ -565,15 +573,6 @@ enum dpm_order {
|
|||
DPM_ORDER_DEV_LAST,
|
||||
};
|
||||
|
||||
/*
|
||||
* Global Power Management flags
|
||||
* Used to keep APM and ACPI from both being active
|
||||
*/
|
||||
extern unsigned int pm_flags;
|
||||
|
||||
#define PM_APM 1
|
||||
#define PM_ACPI 2
|
||||
|
||||
extern int pm_generic_suspend(struct device *dev);
|
||||
extern int pm_generic_resume(struct device *dev);
|
||||
extern int pm_generic_freeze(struct device *dev);
|
||||
|
|
|
@ -87,6 +87,11 @@ static inline bool pm_runtime_enabled(struct device *dev)
|
|||
return !dev->power.disable_depth;
|
||||
}
|
||||
|
||||
static inline bool pm_runtime_callbacks_present(struct device *dev)
|
||||
{
|
||||
return !dev->power.no_callbacks;
|
||||
}
|
||||
|
||||
static inline void pm_runtime_mark_last_busy(struct device *dev)
|
||||
{
|
||||
ACCESS_ONCE(dev->power.last_busy) = jiffies;
|
||||
|
@ -133,6 +138,7 @@ static inline int pm_generic_runtime_resume(struct device *dev) { return 0; }
|
|||
static inline void pm_runtime_no_callbacks(struct device *dev) {}
|
||||
static inline void pm_runtime_irq_safe(struct device *dev) {}
|
||||
|
||||
static inline bool pm_runtime_callbacks_present(struct device *dev) { return false; }
|
||||
static inline void pm_runtime_mark_last_busy(struct device *dev) {}
|
||||
static inline void __pm_runtime_use_autosuspend(struct device *dev,
|
||||
bool use) {}
|
||||
|
|
|
@ -62,18 +62,11 @@ struct wakeup_source {
|
|||
* Changes to device_may_wakeup take effect on the next pm state change.
|
||||
*/
|
||||
|
||||
static inline void device_set_wakeup_capable(struct device *dev, bool capable)
|
||||
{
|
||||
dev->power.can_wakeup = capable;
|
||||
}
|
||||
|
||||
static inline bool device_can_wakeup(struct device *dev)
|
||||
{
|
||||
return dev->power.can_wakeup;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static inline bool device_may_wakeup(struct device *dev)
|
||||
{
|
||||
return dev->power.can_wakeup && !!dev->power.wakeup;
|
||||
|
@ -88,6 +81,7 @@ extern struct wakeup_source *wakeup_source_register(const char *name);
|
|||
extern void wakeup_source_unregister(struct wakeup_source *ws);
|
||||
extern int device_wakeup_enable(struct device *dev);
|
||||
extern int device_wakeup_disable(struct device *dev);
|
||||
extern void device_set_wakeup_capable(struct device *dev, bool capable);
|
||||
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);
|
||||
|
|
29
include/linux/syscore_ops.h
Normal file
29
include/linux/syscore_ops.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* syscore_ops.h - System core operations.
|
||||
*
|
||||
* Copyright (C) 2011 Rafael J. Wysocki <rjw@sisk.pl>, Novell Inc.
|
||||
*
|
||||
* This file is released under the GPLv2.
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_SYSCORE_OPS_H
|
||||
#define _LINUX_SYSCORE_OPS_H
|
||||
|
||||
#include <linux/list.h>
|
||||
|
||||
struct syscore_ops {
|
||||
struct list_head node;
|
||||
int (*suspend)(void);
|
||||
void (*resume)(void);
|
||||
void (*shutdown)(void);
|
||||
};
|
||||
|
||||
extern void register_syscore_ops(struct syscore_ops *ops);
|
||||
extern void unregister_syscore_ops(struct syscore_ops *ops);
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
extern int syscore_suspend(void);
|
||||
extern void syscore_resume(void);
|
||||
#endif
|
||||
extern void syscore_shutdown(void);
|
||||
|
||||
#endif
|
|
@ -103,11 +103,14 @@ static struct pm_qos_object *pm_qos_array[] = {
|
|||
|
||||
static ssize_t pm_qos_power_write(struct file *filp, const char __user *buf,
|
||||
size_t count, loff_t *f_pos);
|
||||
static ssize_t pm_qos_power_read(struct file *filp, char __user *buf,
|
||||
size_t count, loff_t *f_pos);
|
||||
static int pm_qos_power_open(struct inode *inode, struct file *filp);
|
||||
static int pm_qos_power_release(struct inode *inode, struct file *filp);
|
||||
|
||||
static const struct file_operations pm_qos_power_fops = {
|
||||
.write = pm_qos_power_write,
|
||||
.read = pm_qos_power_read,
|
||||
.open = pm_qos_power_open,
|
||||
.release = pm_qos_power_release,
|
||||
.llseek = noop_llseek,
|
||||
|
@ -376,6 +379,27 @@ static int pm_qos_power_release(struct inode *inode, struct file *filp)
|
|||
}
|
||||
|
||||
|
||||
static ssize_t pm_qos_power_read(struct file *filp, char __user *buf,
|
||||
size_t count, loff_t *f_pos)
|
||||
{
|
||||
s32 value;
|
||||
unsigned long flags;
|
||||
struct pm_qos_object *o;
|
||||
struct pm_qos_request_list *pm_qos_req = filp->private_data;;
|
||||
|
||||
if (!pm_qos_req)
|
||||
return -EINVAL;
|
||||
if (!pm_qos_request_active(pm_qos_req))
|
||||
return -EINVAL;
|
||||
|
||||
o = pm_qos_array[pm_qos_req->pm_qos_class];
|
||||
spin_lock_irqsave(&pm_qos_lock, flags);
|
||||
value = pm_qos_get_value(o);
|
||||
spin_unlock_irqrestore(&pm_qos_lock, flags);
|
||||
|
||||
return simple_read_from_buffer(buf, count, f_pos, &value, sizeof(s32));
|
||||
}
|
||||
|
||||
static ssize_t pm_qos_power_write(struct file *filp, const char __user *buf,
|
||||
size_t count, loff_t *f_pos)
|
||||
{
|
||||
|
|
|
@ -1,125 +1,12 @@
|
|||
config PM
|
||||
bool "Power Management support"
|
||||
depends on !IA64_HP_SIM
|
||||
---help---
|
||||
"Power Management" means that parts of your computer are shut
|
||||
off or put into a power conserving "sleep" mode if they are not
|
||||
being used. There are two competing standards for doing this: APM
|
||||
and ACPI. If you want to use either one, say Y here and then also
|
||||
to the requisite support below.
|
||||
|
||||
Power Management is most important for battery powered laptop
|
||||
computers; if you have a laptop, check out the Linux Laptop home
|
||||
page on the WWW at <http://www.linux-on-laptops.com/> or
|
||||
Tuxmobil - Linux on Mobile Computers at <http://www.tuxmobil.org/>
|
||||
and the Battery Powered Linux mini-HOWTO, available from
|
||||
<http://www.tldp.org/docs.html#howto>.
|
||||
|
||||
Note that, even if you say N here, Linux on the x86 architecture
|
||||
will issue the hlt instruction if nothing is to be done, thereby
|
||||
sending the processor to sleep and saving power.
|
||||
|
||||
config PM_DEBUG
|
||||
bool "Power Management Debug Support"
|
||||
depends on PM
|
||||
---help---
|
||||
This option enables various debugging support in the Power Management
|
||||
code. This is helpful when debugging and reporting PM bugs, like
|
||||
suspend support.
|
||||
|
||||
config PM_ADVANCED_DEBUG
|
||||
bool "Extra PM attributes in sysfs for low-level debugging/testing"
|
||||
depends on PM_DEBUG
|
||||
default n
|
||||
---help---
|
||||
Add extra sysfs attributes allowing one to access some Power Management
|
||||
fields of device objects from user space. If you are not a kernel
|
||||
developer interested in debugging/testing Power Management, say "no".
|
||||
|
||||
config PM_VERBOSE
|
||||
bool "Verbose Power Management debugging"
|
||||
depends on PM_DEBUG
|
||||
default n
|
||||
---help---
|
||||
This option enables verbose messages from the Power Management code.
|
||||
|
||||
config CAN_PM_TRACE
|
||||
def_bool y
|
||||
depends on PM_DEBUG && PM_SLEEP && EXPERIMENTAL
|
||||
|
||||
config PM_TRACE
|
||||
bool
|
||||
help
|
||||
This enables code to save the last PM event point across
|
||||
reboot. The architecture needs to support this, x86 for
|
||||
example does by saving things in the RTC, see below.
|
||||
|
||||
The architecture specific code must provide the extern
|
||||
functions from <linux/resume-trace.h> as well as the
|
||||
<asm/resume-trace.h> header with a TRACE_RESUME() macro.
|
||||
|
||||
The way the information is presented is architecture-
|
||||
dependent, x86 will print the information during a
|
||||
late_initcall.
|
||||
|
||||
config PM_TRACE_RTC
|
||||
bool "Suspend/resume event tracing"
|
||||
depends on CAN_PM_TRACE
|
||||
depends on X86
|
||||
select PM_TRACE
|
||||
default n
|
||||
---help---
|
||||
This enables some cheesy code to save the last PM event point in the
|
||||
RTC across reboots, so that you can debug a machine that just hangs
|
||||
during suspend (or more commonly, during resume).
|
||||
|
||||
To use this debugging feature you should attempt to suspend the
|
||||
machine, reboot it and then run
|
||||
|
||||
dmesg -s 1000000 | grep 'hash matches'
|
||||
|
||||
CAUTION: this option will cause your machine's real-time clock to be
|
||||
set to an invalid time after a resume.
|
||||
|
||||
config PM_SLEEP_SMP
|
||||
bool
|
||||
depends on SMP
|
||||
depends on ARCH_SUSPEND_POSSIBLE || ARCH_HIBERNATION_POSSIBLE
|
||||
depends on PM_SLEEP
|
||||
select HOTPLUG
|
||||
select HOTPLUG_CPU
|
||||
default y
|
||||
|
||||
config PM_SLEEP
|
||||
bool
|
||||
depends on SUSPEND || HIBERNATION || XEN_SAVE_RESTORE
|
||||
default y
|
||||
|
||||
config PM_SLEEP_ADVANCED_DEBUG
|
||||
bool
|
||||
depends on PM_ADVANCED_DEBUG
|
||||
default n
|
||||
|
||||
config SUSPEND
|
||||
bool "Suspend to RAM and standby"
|
||||
depends on PM && ARCH_SUSPEND_POSSIBLE
|
||||
depends on ARCH_SUSPEND_POSSIBLE
|
||||
default y
|
||||
---help---
|
||||
Allow the system to enter sleep states in which main memory is
|
||||
powered and thus its contents are preserved, such as the
|
||||
suspend-to-RAM state (e.g. the ACPI S3 state).
|
||||
|
||||
config PM_TEST_SUSPEND
|
||||
bool "Test suspend/resume and wakealarm during bootup"
|
||||
depends on SUSPEND && PM_DEBUG && RTC_CLASS=y
|
||||
---help---
|
||||
This option will let you suspend your machine during bootup, and
|
||||
make it wake up a few seconds later using an RTC wakeup alarm.
|
||||
Enable this with a kernel parameter like "test_suspend=mem".
|
||||
|
||||
You probably want to have your system's RTC driver statically
|
||||
linked, ensuring that it's available when this test runs.
|
||||
|
||||
config SUSPEND_FREEZER
|
||||
bool "Enable freezer for suspend to RAM/standby" \
|
||||
if ARCH_WANTS_FREEZER_CONTROL || BROKEN
|
||||
|
@ -133,7 +20,7 @@ config SUSPEND_FREEZER
|
|||
|
||||
config HIBERNATION
|
||||
bool "Hibernation (aka 'suspend to disk')"
|
||||
depends on PM && SWAP && ARCH_HIBERNATION_POSSIBLE
|
||||
depends on SWAP && ARCH_HIBERNATION_POSSIBLE
|
||||
select LZO_COMPRESS
|
||||
select LZO_DECOMPRESS
|
||||
---help---
|
||||
|
@ -196,6 +83,106 @@ config PM_STD_PARTITION
|
|||
suspended image to. It will simply pick the first available swap
|
||||
device.
|
||||
|
||||
config PM_SLEEP
|
||||
def_bool y
|
||||
depends on SUSPEND || HIBERNATION || XEN_SAVE_RESTORE
|
||||
|
||||
config PM_SLEEP_SMP
|
||||
def_bool y
|
||||
depends on SMP
|
||||
depends on ARCH_SUSPEND_POSSIBLE || ARCH_HIBERNATION_POSSIBLE
|
||||
depends on PM_SLEEP
|
||||
select HOTPLUG
|
||||
select HOTPLUG_CPU
|
||||
|
||||
config PM_RUNTIME
|
||||
bool "Run-time PM core functionality"
|
||||
depends on !IA64_HP_SIM
|
||||
---help---
|
||||
Enable functionality allowing I/O devices to be put into energy-saving
|
||||
(low power) states at run time (or autosuspended) after a specified
|
||||
period of inactivity and woken up in response to a hardware-generated
|
||||
wake-up event or a driver's request.
|
||||
|
||||
Hardware support is generally required for this functionality to work
|
||||
and the bus type drivers of the buses the devices are on are
|
||||
responsible for the actual handling of the autosuspend requests and
|
||||
wake-up events.
|
||||
|
||||
config PM
|
||||
def_bool y
|
||||
depends on PM_SLEEP || PM_RUNTIME
|
||||
|
||||
config PM_DEBUG
|
||||
bool "Power Management Debug Support"
|
||||
depends on PM
|
||||
---help---
|
||||
This option enables various debugging support in the Power Management
|
||||
code. This is helpful when debugging and reporting PM bugs, like
|
||||
suspend support.
|
||||
|
||||
config PM_VERBOSE
|
||||
bool "Verbose Power Management debugging"
|
||||
depends on PM_DEBUG
|
||||
---help---
|
||||
This option enables verbose messages from the Power Management code.
|
||||
|
||||
config PM_ADVANCED_DEBUG
|
||||
bool "Extra PM attributes in sysfs for low-level debugging/testing"
|
||||
depends on PM_DEBUG
|
||||
---help---
|
||||
Add extra sysfs attributes allowing one to access some Power Management
|
||||
fields of device objects from user space. If you are not a kernel
|
||||
developer interested in debugging/testing Power Management, say "no".
|
||||
|
||||
config PM_TEST_SUSPEND
|
||||
bool "Test suspend/resume and wakealarm during bootup"
|
||||
depends on SUSPEND && PM_DEBUG && RTC_CLASS=y
|
||||
---help---
|
||||
This option will let you suspend your machine during bootup, and
|
||||
make it wake up a few seconds later using an RTC wakeup alarm.
|
||||
Enable this with a kernel parameter like "test_suspend=mem".
|
||||
|
||||
You probably want to have your system's RTC driver statically
|
||||
linked, ensuring that it's available when this test runs.
|
||||
|
||||
config CAN_PM_TRACE
|
||||
def_bool y
|
||||
depends on PM_DEBUG && PM_SLEEP
|
||||
|
||||
config PM_TRACE
|
||||
bool
|
||||
help
|
||||
This enables code to save the last PM event point across
|
||||
reboot. The architecture needs to support this, x86 for
|
||||
example does by saving things in the RTC, see below.
|
||||
|
||||
The architecture specific code must provide the extern
|
||||
functions from <linux/resume-trace.h> as well as the
|
||||
<asm/resume-trace.h> header with a TRACE_RESUME() macro.
|
||||
|
||||
The way the information is presented is architecture-
|
||||
dependent, x86 will print the information during a
|
||||
late_initcall.
|
||||
|
||||
config PM_TRACE_RTC
|
||||
bool "Suspend/resume event tracing"
|
||||
depends on CAN_PM_TRACE
|
||||
depends on X86
|
||||
select PM_TRACE
|
||||
---help---
|
||||
This enables some cheesy code to save the last PM event point in the
|
||||
RTC across reboots, so that you can debug a machine that just hangs
|
||||
during suspend (or more commonly, during resume).
|
||||
|
||||
To use this debugging feature you should attempt to suspend the
|
||||
machine, reboot it and then run
|
||||
|
||||
dmesg -s 1000000 | grep 'hash matches'
|
||||
|
||||
CAUTION: this option will cause your machine's real-time clock to be
|
||||
set to an invalid time after a resume.
|
||||
|
||||
config APM_EMULATION
|
||||
tristate "Advanced Power Management Emulation"
|
||||
depends on PM && SYS_SUPPORTS_APM_EMULATION
|
||||
|
@ -222,31 +209,11 @@ config APM_EMULATION
|
|||
anything, try disabling/enabling this option (or disabling/enabling
|
||||
APM in your BIOS).
|
||||
|
||||
config PM_RUNTIME
|
||||
bool "Run-time PM core functionality"
|
||||
depends on PM
|
||||
---help---
|
||||
Enable functionality allowing I/O devices to be put into energy-saving
|
||||
(low power) states at run time (or autosuspended) after a specified
|
||||
period of inactivity and woken up in response to a hardware-generated
|
||||
wake-up event or a driver's request.
|
||||
|
||||
Hardware support is generally required for this functionality to work
|
||||
and the bus type drivers of the buses the devices are on are
|
||||
responsible for the actual handling of the autosuspend requests and
|
||||
wake-up events.
|
||||
|
||||
config PM_OPS
|
||||
bool
|
||||
depends on PM_SLEEP || PM_RUNTIME
|
||||
default y
|
||||
|
||||
config ARCH_HAS_OPP
|
||||
bool
|
||||
|
||||
config PM_OPP
|
||||
bool "Operating Performance Point (OPP) Layer library"
|
||||
depends on PM
|
||||
depends on ARCH_HAS_OPP
|
||||
---help---
|
||||
SOCs have a standard set of tuples consisting of frequency and
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include <linux/cpu.h>
|
||||
#include <linux/freezer.h>
|
||||
#include <linux/gfp.h>
|
||||
#include <linux/syscore_ops.h>
|
||||
#include <scsi/scsi_scan.h>
|
||||
#include <asm/suspend.h>
|
||||
|
||||
|
@ -272,6 +273,8 @@ static int create_image(int platform_mode)
|
|||
local_irq_disable();
|
||||
|
||||
error = sysdev_suspend(PMSG_FREEZE);
|
||||
if (!error)
|
||||
error = syscore_suspend();
|
||||
if (error) {
|
||||
printk(KERN_ERR "PM: Some system devices failed to power down, "
|
||||
"aborting hibernation\n");
|
||||
|
@ -295,6 +298,7 @@ static int create_image(int platform_mode)
|
|||
}
|
||||
|
||||
Power_up:
|
||||
syscore_resume();
|
||||
sysdev_resume();
|
||||
/* NOTE: dpm_resume_noirq() is just a resume() for devices
|
||||
* that suspended with irqs off ... no overall powerup.
|
||||
|
@ -403,6 +407,8 @@ static int resume_target_kernel(bool platform_mode)
|
|||
local_irq_disable();
|
||||
|
||||
error = sysdev_suspend(PMSG_QUIESCE);
|
||||
if (!error)
|
||||
error = syscore_suspend();
|
||||
if (error)
|
||||
goto Enable_irqs;
|
||||
|
||||
|
@ -429,6 +435,7 @@ static int resume_target_kernel(bool platform_mode)
|
|||
restore_processor_state();
|
||||
touch_softlockup_watchdog();
|
||||
|
||||
syscore_resume();
|
||||
sysdev_resume();
|
||||
|
||||
Enable_irqs:
|
||||
|
@ -516,6 +523,7 @@ int hibernation_platform_enter(void)
|
|||
|
||||
local_irq_disable();
|
||||
sysdev_suspend(PMSG_HIBERNATE);
|
||||
syscore_suspend();
|
||||
if (pm_wakeup_pending()) {
|
||||
error = -EAGAIN;
|
||||
goto Power_up;
|
||||
|
@ -526,6 +534,7 @@ int hibernation_platform_enter(void)
|
|||
while (1);
|
||||
|
||||
Power_up:
|
||||
syscore_resume();
|
||||
sysdev_resume();
|
||||
local_irq_enable();
|
||||
enable_nonboot_cpus();
|
||||
|
|
|
@ -17,9 +17,6 @@
|
|||
|
||||
DEFINE_MUTEX(pm_mutex);
|
||||
|
||||
unsigned int pm_flags;
|
||||
EXPORT_SYMBOL(pm_flags);
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
|
||||
/* Routines for PM-transition notifications */
|
||||
|
|
|
@ -42,15 +42,15 @@ static void swsusp_unset_page_forbidden(struct page *);
|
|||
|
||||
/*
|
||||
* Preferred image size in bytes (tunable via /sys/power/image_size).
|
||||
* When it is set to N, swsusp will do its best to ensure the image
|
||||
* size will not exceed N bytes, but if that is impossible, it will
|
||||
* try to create the smallest image possible.
|
||||
* When it is set to N, the image creating code will do its best to
|
||||
* ensure the image size will not exceed N bytes, but if that is
|
||||
* impossible, it will try to create the smallest image possible.
|
||||
*/
|
||||
unsigned long image_size;
|
||||
|
||||
void __init hibernate_image_size_init(void)
|
||||
{
|
||||
image_size = ((totalram_pages * 2) / 5) * PAGE_SIZE;
|
||||
image_size = (totalram_pages / 3) * PAGE_SIZE;
|
||||
}
|
||||
|
||||
/* List of PBEs needed for restoring the pages that were allocated before
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include <linux/mm.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/suspend.h>
|
||||
#include <linux/syscore_ops.h>
|
||||
#include <trace/events/power.h>
|
||||
|
||||
#include "power.h"
|
||||
|
@ -163,11 +164,14 @@ static int suspend_enter(suspend_state_t state)
|
|||
BUG_ON(!irqs_disabled());
|
||||
|
||||
error = sysdev_suspend(PMSG_SUSPEND);
|
||||
if (!error)
|
||||
error = syscore_suspend();
|
||||
if (!error) {
|
||||
if (!(suspend_test(TEST_CORE) || pm_wakeup_pending())) {
|
||||
error = suspend_ops->enter(state);
|
||||
events_check_enabled = false;
|
||||
}
|
||||
syscore_resume();
|
||||
sysdev_resume();
|
||||
}
|
||||
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
#include <linux/ptrace.h>
|
||||
#include <linux/fs_struct.h>
|
||||
#include <linux/gfp.h>
|
||||
#include <linux/syscore_ops.h>
|
||||
|
||||
#include <linux/compat.h>
|
||||
#include <linux/syscalls.h>
|
||||
|
@ -298,6 +299,7 @@ void kernel_restart_prepare(char *cmd)
|
|||
system_state = SYSTEM_RESTART;
|
||||
device_shutdown();
|
||||
sysdev_shutdown();
|
||||
syscore_shutdown();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -336,6 +338,7 @@ void kernel_halt(void)
|
|||
{
|
||||
kernel_shutdown_prepare(SYSTEM_HALT);
|
||||
sysdev_shutdown();
|
||||
syscore_shutdown();
|
||||
printk(KERN_EMERG "System halted.\n");
|
||||
kmsg_dump(KMSG_DUMP_HALT);
|
||||
machine_halt();
|
||||
|
@ -355,6 +358,7 @@ void kernel_power_off(void)
|
|||
pm_power_off_prepare();
|
||||
disable_nonboot_cpus();
|
||||
sysdev_shutdown();
|
||||
syscore_shutdown();
|
||||
printk(KERN_EMERG "Power down.\n");
|
||||
kmsg_dump(KMSG_DUMP_POWEROFF);
|
||||
machine_power_off();
|
||||
|
|
Loading…
Reference in a new issue