You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
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:
@@ -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
|
||||
|
||||
+6
-17
@@ -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
|
||||
|
||||
|
||||
+96
-85
@@ -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
|
||||
|
||||
+10
-11
@@ -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;
|
||||
|
||||
|
||||
+55
-31
@@ -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;
|
||||
|
||||
+76
-33
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user