Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael...
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 16 Mar 2011 16:24:44 +0000 (09:24 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 16 Mar 2011 16:24:44 +0000 (09:24 -0700)
* '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
  ...

40 files changed:
Documentation/ABI/testing/sysfs-devices-power
Documentation/power/devices.txt
Documentation/power/runtime_pm.txt
Documentation/power/states.txt
arch/x86/kernel/apm_32.c
arch/x86/xen/Kconfig
drivers/acpi/Kconfig
drivers/acpi/bus.c
drivers/acpi/sleep.c
drivers/base/Makefile
drivers/base/power/Makefile
drivers/base/power/main.c
drivers/base/power/opp.c
drivers/base/power/power.h
drivers/base/power/runtime.c
drivers/base/power/sysfs.c
drivers/base/power/trace.c
drivers/base/power/wakeup.c
drivers/base/syscore.c [new file with mode: 0644]
drivers/net/e1000e/netdev.c
drivers/net/pch_gbe/pch_gbe_main.c
drivers/pci/pci-driver.c
drivers/scsi/Makefile
drivers/scsi/scsi_priv.h
drivers/scsi/scsi_sysfs.c
drivers/usb/core/hcd-pci.c
drivers/usb/core/hub.c
include/acpi/acpi_bus.h
include/linux/device.h
include/linux/pm.h
include/linux/pm_runtime.h
include/linux/pm_wakeup.h
include/linux/syscore_ops.h [new file with mode: 0644]
kernel/pm_qos_params.c
kernel/power/Kconfig
kernel/power/hibernate.c
kernel/power/main.c
kernel/power/snapshot.c
kernel/power/suspend.c
kernel/sys.c

index 7628cd1bc36a5e8080a646da492736c3e43b917d..8ffbc25376a0f59cfcde7b10157a0d58b235a748 100644 (file)
@@ -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
index 57080cd74575511ccaa3eebfb119a8560f343871..f023ba6bba62c2dcbd514691de267ab7229d0942 100644 (file)
@@ -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
index ffe55ffa540a1b59a6e37979e86b842022cc2b56..654097b130b46175c4c5165ded5f535718266cc7 100644 (file)
@@ -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
index 34800cc521bfd6c26cf56bfdae81791ad670425d..4416b28630df8d62cbba43e2fedb0cee42d6b3b1 100644 (file)
@@ -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
index 0e4f24c2a746f11b21ec534db5180c50e0d69cbd..15f47f74198398d9b7064e2a90602d92f6969f2b 100644 (file)
 #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);
index e4343fe488ed2768b0db811cf4971ae865240fb8..1c7121ba18ffdc902740c396427e448ae62250d4 100644 (file)
@@ -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
index 2aa042a5da6d06c05e29de99419e0322c77414a6..3a17ca5fff6f022d207107ff741b6b22ba300190 100644 (file)
@@ -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
index 7ced61f394924e3e0eeb208de094f894cfd5e623..9749980ca6ca6c7669aa8c669a1102b881a2929f 100644 (file)
@@ -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);
index d6a8cd14de2e824ddb15563aa625fa1d5236ea5a..8ea092fad3f69181383c80e5a14a8303f9d36185 100644 (file)
@@ -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
 /**
index 5f51c3b4451e2a3c39fcefbc1c5c0a97e810d78b..4c5701c15f53a1d4ed4c5d55ada286d57d3b85b7 100644 (file)
@@ -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
index abe46edfe5b41b9c2c5b39640c94c2208ffe283b..118c1b92a511c3819ac27e424eaad23831dee0c6 100644 (file)
@@ -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
 
index 83404973f97aa31fe1065bb5c93351b8e88640f7..052dc53eef388db918f2a0f6ce961be366691577 100644 (file)
@@ -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,36 +514,39 @@ static int device_resume(struct device *dev, pm_message_t state, bool async)
 
        dev->power.in_suspend = false;
 
-       if (dev->bus) {
-               if (dev->bus->pm) {
-                       pm_dev_dbg(dev, state, "");
-                       error = pm_op(dev, dev->bus->pm, state);
-               } else if (dev->bus->resume) {
-                       pm_dev_dbg(dev, state, "legacy ");
-                       error = legacy_resume(dev, dev->bus->resume);
-               }
-               if (error)
-                       goto End;
+       if (dev->pwr_domain) {
+               pm_dev_dbg(dev, state, "power domain ");
+               pm_op(dev, &dev->pwr_domain->ops, state);
        }
 
-       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->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, "");
+                       error = pm_op(dev, dev->bus->pm, state);
+               } else if (dev->bus->resume) {
+                       pm_dev_dbg(dev, state, "legacy ");
+                       error = legacy_resume(dev, dev->bus->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) {
index 2bb9b4cf59d7d56e408265e9c98c2d080b69ffe1..56a6899f5e9e4ba35ae044eba9e482e51ee58c8d 100644 (file)
@@ -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
index 698dde74258792544098eb8866e77ee72303c865..f2a25f18fde7caaa3a1949c893afae3c872b76c3 100644 (file)
@@ -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
index 42615b419dfb5bc4f30e0f6dfb2ad607015d95b7..54597c859ecbc295d9691af86f6382c52f48395b 100644 (file)
@@ -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;
 
index 0b1e46bf3e56950e45366ab46a664992ac2c1f0f..fff49bee781d44f4fd2f35dda22f86a388fd9259 100644 (file)
@@ -431,26 +431,18 @@ 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,
-#ifdef CONFIG_PM_SLEEP
-       &dev_attr_wakeup_count.attr,
-       &dev_attr_wakeup_active_count.attr,
-       &dev_attr_wakeup_hit_count.attr,
-       &dev_attr_wakeup_active.attr,
-       &dev_attr_wakeup_total_time_ms.attr,
-       &dev_attr_wakeup_max_time_ms.attr,
-       &dev_attr_wakeup_last_time_ms.attr,
-#endif
+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
+#endif /* CONFIG_PM_ADVANCED_DEBUG */
        NULL,
 };
 static struct attribute_group pm_attr_group = {
@@ -458,9 +450,26 @@ static struct attribute_group pm_attr_group = {
        .attrs  = power_attrs,
 };
 
-#ifdef CONFIG_PM_RUNTIME
+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,
+       &dev_attr_wakeup_active.attr,
+       &dev_attr_wakeup_total_time_ms.attr,
+       &dev_attr_wakeup_max_time_ms.attr,
+       &dev_attr_wakeup_last_time_ms.attr,
+#endif
+       NULL,
+};
+static struct attribute_group pm_wakeup_attr_group = {
+       .name   = power_group_name,
+       .attrs  = wakeup_attrs,
+};
 
 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,35 +490,49 @@ 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;
 }
 
-void rpm_sysfs_remove(struct device *dev)
+int wakeup_sysfs_add(struct device *dev)
 {
-       sysfs_unmerge_group(&dev->kobj, &pm_runtime_attr_group);
+       return sysfs_merge_group(&dev->kobj, &pm_wakeup_attr_group);
 }
 
-void dpm_sysfs_remove(struct device *dev)
+void wakeup_sysfs_remove(struct device *dev)
 {
-       rpm_sysfs_remove(dev);
-       sysfs_remove_group(&dev->kobj, &pm_attr_group);
+       sysfs_unmerge_group(&dev->kobj, &pm_wakeup_attr_group);
 }
 
-#else /* CONFIG_PM_RUNTIME */
-
-int dpm_sysfs_add(struct device * dev)
+void rpm_sysfs_remove(struct device *dev)
 {
-       return sysfs_create_group(&dev->kobj, &pm_attr_group);
+       sysfs_unmerge_group(&dev->kobj, &pm_runtime_attr_group);
 }
 
-void dpm_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);
 }
-
-#endif
index 9f4258df4cfdbace7c80d889154738f17c7d8461..c80e138b62fe91d2d14b459ae87288d632cf4d20 100644 (file)
@@ -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;
index 8ec406d8f548eae6b84ed692236c12ee45139fa4..4573c83df6ddc4d996e342bc47bb54f717063474 100644 (file)
  */
 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;
-
-       if (capable(CAP_SYS_ADMIN))
-               events_check_enabled = false;
+       unsigned int cnt, inpr;
 
-       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;
diff --git a/drivers/base/syscore.c b/drivers/base/syscore.c
new file mode 100644 (file)
index 0000000..90af294
--- /dev/null
@@ -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);
+}
index 2e5022849f1828c19a1bc968e7112cdf487d4145..6d513a383340c17c21b6c210e881c70189bc9012 100644 (file)
@@ -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,
index b99e90aca37dc4afa70cfc58195b5d59c90b7b48..8c66e22c3a0a5444c30d44efa846553f640c22e3 100644 (file)
@@ -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,
index 88246dd4645258d865102cbc20dba99ccfe0a5e3..d86ea8b0113701ecbbcb26de06c20f6d60089510 100644 (file)
@@ -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,
index 2e9a87e8e7d83579142383fbb21c4c55338ac29e..ef6de669424b709720fd71c7f0fa1fca72446f5d 100644 (file)
@@ -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
 
index b4056d14f812d7ecc4e8affc0c234bf6e4837424..342ee1a9c41d0fbfd3504de5d2c8ea8727269b7f 100644 (file)
@@ -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
index 490ce213204e9dc2bfb5d1699abdb99066cd8c05..e44ff64233fd5fbe00a4aa675081bcac319739af 100644 (file)
@@ -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
 };
index f71e8e307e0f0c0b513c763b1ddfcb7b81f0cded..64a035ba2eab7098cdbbbd1432e308c948a339d0 100644 (file)
@@ -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 */
index 0f299b7aad609bc232e7d10c0c142f47f180534b..19d3435e61408032506e790067dfca5072c27155 100644 (file)
@@ -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);
 
index 78ca429929f7438959e6509dcd0f547cfb44afd5..ff103ba96b78cb4956cd49259ce0dfa4947b04e3 100644 (file)
@@ -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)
index ca5d25225aabd9ecaff16854ac483b14b3c635fa..dba775a68752685e4f02eae24db4ddd63d2e8512 100644 (file)
@@ -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 */
index 21415cc91cbb440492f06091b8237c9bed42d00d..6618216bb973a96f595cc2a0d3803586c84c1947 100644 (file)
@@ -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);
index d34f067e2a7f31e5b391b22382b811913b407515..8de9aa6e7def9a4e2380b3f2d4e9a17727518890 100644 (file)
@@ -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) {}
index 03a67db03d01e4133e027d22871929e5c150956e..a32da962d6932963196cf0ea3783d27db33c9fbe 100644 (file)
@@ -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);
diff --git a/include/linux/syscore_ops.h b/include/linux/syscore_ops.h
new file mode 100644 (file)
index 0000000..27b3b0b
--- /dev/null
@@ -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
index aeaa7f8468216eb1d8795b14ff74cfc502318771..0da058bff8eb280ee2604086a23f89382176133e 100644 (file)
@@ -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)
 {
index 265729966ece61898c9f37a5b8fde49978bcce8c..4603f08dc47b1e7687b09ca51e31b3e7c48b4c55 100644 (file)
-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
index 1832bd2642192970f2fe9e1b759b737e9519b1cf..aeabd26e3342788e4330cfb4e8e2a5ba40b348d0 100644 (file)
@@ -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();
index 701853042c281c010303a1230f42b6fa5a08cae0..8eaba5f27b1017f62456e1dc40bae5e73804ee9e 100644 (file)
@@ -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 */
index 64db648ff911e13eb09461e8ffa1a4266b19c306..ca0aacc2487426522df9b9cf71297a61d9faa0b1 100644 (file)
@@ -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
index de6f86bfa30389e965f857cdd28b8ff03aeda32e..2814c32aed51c121a7ff9689aa38f6b98d025b15 100644 (file)
@@ -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();
        }
 
index 18da702ec813c491c758b6f28e86a31a71ba60b5..1ad48b3b9068ff7454d753c7e36e844ab507afd8 100644 (file)
@@ -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();
This page took 0.062111 seconds and 5 git commands to generate.