PM: Reset transition_started at dpm_resume_noirq
[pandora-kernel.git] / drivers / base / power / main.c
index 58a3e57..e0dc407 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/kallsyms.h>
 #include <linux/mutex.h>
 #include <linux/pm.h>
+#include <linux/pm_runtime.h>
 #include <linux/resume-trace.h>
 #include <linux/rwsem.h>
 #include <linux/interrupt.h>
@@ -49,7 +50,17 @@ static DEFINE_MUTEX(dpm_list_mtx);
 static bool transition_started;
 
 /**
- *     device_pm_lock - lock the list of active devices used by the PM core
+ * device_pm_init - Initialize the PM-related part of a device object.
+ * @dev: Device object being initialized.
+ */
+void device_pm_init(struct device *dev)
+{
+       dev->power.status = DPM_ON;
+       pm_runtime_init(dev);
+}
+
+/**
+ * device_pm_lock - Lock the list of active devices used by the PM core.
  */
 void device_pm_lock(void)
 {
@@ -57,7 +68,7 @@ void device_pm_lock(void)
 }
 
 /**
- *     device_pm_unlock - unlock the list of active devices used by the PM core
+ * device_pm_unlock - Unlock the list of active devices used by the PM core.
  */
 void device_pm_unlock(void)
 {
@@ -65,8 +76,8 @@ void device_pm_unlock(void)
 }
 
 /**
- *     device_pm_add - add a device to the list of active devices
- *     @dev:   Device to be added to the list
+ * device_pm_add - Add a device to the PM core's list of active devices.
+ * @dev: Device to add to the list.
  */
 void device_pm_add(struct device *dev)
 {
@@ -92,10 +103,8 @@ void device_pm_add(struct device *dev)
 }
 
 /**
- *     device_pm_remove - remove a device from the list of active devices
- *     @dev:   Device to be removed from the list
- *
- *     This function also removes the device's PM-related sysfs attributes.
+ * device_pm_remove - Remove a device from the PM core's list of active devices.
+ * @dev: Device to be removed from the list.
  */
 void device_pm_remove(struct device *dev)
 {
@@ -105,12 +114,13 @@ void device_pm_remove(struct device *dev)
        mutex_lock(&dpm_list_mtx);
        list_del_init(&dev->power.entry);
        mutex_unlock(&dpm_list_mtx);
+       pm_runtime_remove(dev);
 }
 
 /**
- *     device_pm_move_before - move device in dpm_list
- *     @deva:  Device to move in dpm_list
- *     @devb:  Device @deva should come before
+ * device_pm_move_before - Move device in the PM core's list of active devices.
+ * @deva: Device to move in dpm_list.
+ * @devb: Device @deva should come before.
  */
 void device_pm_move_before(struct device *deva, struct device *devb)
 {
@@ -124,9 +134,9 @@ void device_pm_move_before(struct device *deva, struct device *devb)
 }
 
 /**
- *     device_pm_move_after - move device in dpm_list
- *     @deva:  Device to move in dpm_list
- *     @devb:  Device @deva should come after
+ * device_pm_move_after - Move device in the PM core's list of active devices.
+ * @deva: Device to move in dpm_list.
+ * @devb: Device @deva should come after.
  */
 void device_pm_move_after(struct device *deva, struct device *devb)
 {
@@ -140,8 +150,8 @@ void device_pm_move_after(struct device *deva, struct device *devb)
 }
 
 /**
- *     device_pm_move_last - move device to end of dpm_list
- *     @dev:   Device to move in dpm_list
+ * device_pm_move_last - Move device to end of the PM core's list of devices.
+ * @dev: Device to move in dpm_list.
  */
 void device_pm_move_last(struct device *dev)
 {
@@ -152,13 +162,14 @@ void device_pm_move_last(struct device *dev)
 }
 
 /**
- *     pm_op - execute the PM operation appropiate for given PM event
- *     @dev:   Device.
- *     @ops:   PM operations to choose from.
- *     @state: PM transition of the system being carried out.
+ * pm_op - Execute the PM operation appropriate for given PM event.
+ * @dev: Device to handle.
+ * @ops: PM operations to choose from.
+ * @state: PM transition of the system being carried out.
  */
-static int pm_op(struct device *dev, struct dev_pm_ops *ops,
-                       pm_message_t state)
+static int pm_op(struct device *dev,
+                const struct dev_pm_ops *ops,
+                pm_message_t state)
 {
        int error = 0;
 
@@ -212,15 +223,16 @@ static int pm_op(struct device *dev, struct dev_pm_ops *ops,
 }
 
 /**
- *     pm_noirq_op - execute the PM operation appropiate for given PM event
- *     @dev:   Device.
- *     @ops:   PM operations to choose from.
- *     @state: PM transition of the system being carried out.
+ * pm_noirq_op - Execute the PM operation appropriate for given PM event.
+ * @dev: Device to handle.
+ * @ops: PM operations to choose from.
+ * @state: PM transition of the system being carried out.
  *
- *     The operation is executed with interrupts disabled by the only remaining
- *     functional CPU in the system.
+ * The driver of @dev will not receive interrupts while this function is being
+ * executed.
  */
-static int pm_noirq_op(struct device *dev, struct dev_pm_ops *ops,
+static int pm_noirq_op(struct device *dev,
+                       const struct dev_pm_ops *ops,
                        pm_message_t state)
 {
        int error = 0;
@@ -315,11 +327,12 @@ static void pm_dev_err(struct device *dev, pm_message_t state, char *info,
 /*------------------------- Resume routines -------------------------*/
 
 /**
- *     device_resume_noirq - Power on one device (early resume).
- *     @dev:   Device.
- *     @state: PM transition of the system being carried out.
+ * device_resume_noirq - Execute an "early resume" callback for given device.
+ * @dev: Device to handle.
+ * @state: PM transition of the system being carried out.
  *
- *     Must be called with interrupts disabled.
+ * The driver of @dev will not receive interrupts while this function is being
+ * executed.
  */
 static int device_resume_noirq(struct device *dev, pm_message_t state)
 {
@@ -341,20 +354,18 @@ static int device_resume_noirq(struct device *dev, pm_message_t state)
 }
 
 /**
- *     dpm_resume_noirq - Power on all regular (non-sysdev) devices.
- *     @state: PM transition of the system being carried out.
- *
- *     Call the "noirq" resume handlers for all devices marked as
- *     DPM_OFF_IRQ and enable device drivers to receive interrupts.
+ * dpm_resume_noirq - Execute "early resume" callbacks for non-sysdev devices.
+ * @state: PM transition of the system being carried out.
  *
- *     Must be called under dpm_list_mtx.  Device drivers should not receive
- *     interrupts while it's being executed.
+ * Call the "noirq" resume handlers for all devices marked as DPM_OFF_IRQ and
+ * enable device drivers to receive interrupts.
  */
 void dpm_resume_noirq(pm_message_t state)
 {
        struct device *dev;
 
        mutex_lock(&dpm_list_mtx);
+       transition_started = false;
        list_for_each_entry(dev, &dpm_list, power.entry)
                if (dev->power.status > DPM_OFF) {
                        int error;
@@ -370,9 +381,9 @@ void dpm_resume_noirq(pm_message_t state)
 EXPORT_SYMBOL_GPL(dpm_resume_noirq);
 
 /**
- *     device_resume - Restore state for one device.
- *     @dev:   Device.
- *     @state: PM transition of the system being carried out.
+ * device_resume - Execute "resume" callbacks for given device.
+ * @dev: Device to handle.
+ * @state: PM transition of the system being carried out.
  */
 static int device_resume(struct device *dev, pm_message_t state)
 {
@@ -421,11 +432,11 @@ static int device_resume(struct device *dev, pm_message_t state)
 }
 
 /**
- *     dpm_resume - Resume every device.
- *     @state: PM transition of the system being carried out.
+ * dpm_resume - Execute "resume" callbacks for non-sysdev devices.
+ * @state: PM transition of the system being carried out.
  *
- *     Execute the appropriate "resume" callback for all devices the status of
- *     which indicates that they are inactive.
+ * Execute the appropriate "resume" callback for all devices whose status
+ * indicates that they are suspended.
  */
 static void dpm_resume(pm_message_t state)
 {
@@ -433,7 +444,6 @@ static void dpm_resume(pm_message_t state)
 
        INIT_LIST_HEAD(&list);
        mutex_lock(&dpm_list_mtx);
-       transition_started = false;
        while (!list_empty(&dpm_list)) {
                struct device *dev = to_device(dpm_list.next);
 
@@ -462,9 +472,9 @@ static void dpm_resume(pm_message_t state)
 }
 
 /**
- *     device_complete - Complete a PM transition for given device
- *     @dev:   Device.
- *     @state: PM transition of the system being carried out.
+ * device_complete - Complete a PM transition for given device.
+ * @dev: Device to handle.
+ * @state: PM transition of the system being carried out.
  */
 static void device_complete(struct device *dev, pm_message_t state)
 {
@@ -489,11 +499,11 @@ static void device_complete(struct device *dev, pm_message_t state)
 }
 
 /**
- *     dpm_complete - Complete a PM transition for all devices.
- *     @state: PM transition of the system being carried out.
+ * dpm_complete - Complete a PM transition for all non-sysdev devices.
+ * @state: PM transition of the system being carried out.
  *
- *     Execute the ->complete() callbacks for all devices that are not marked
- *     as DPM_ON.
+ * Execute the ->complete() callbacks for all devices whose PM status is not
+ * DPM_ON (this allows new devices to be registered).
  */
 static void dpm_complete(pm_message_t state)
 {
@@ -510,6 +520,7 @@ static void dpm_complete(pm_message_t state)
                        mutex_unlock(&dpm_list_mtx);
 
                        device_complete(dev, state);
+                       pm_runtime_put_noidle(dev);
 
                        mutex_lock(&dpm_list_mtx);
                }
@@ -522,11 +533,11 @@ static void dpm_complete(pm_message_t state)
 }
 
 /**
- *     dpm_resume_end - Restore state of each device in system.
- *     @state: PM transition of the system being carried out.
+ * dpm_resume_end - Execute "resume" callbacks and complete system transition.
+ * @state: PM transition of the system being carried out.
  *
- *     Resume all the devices, unlock them all, and allow new
- *     devices to be registered once again.
+ * Execute "resume" callbacks for all devices and complete the PM transition of
+ * the system.
  */
 void dpm_resume_end(pm_message_t state)
 {
@@ -540,9 +551,11 @@ EXPORT_SYMBOL_GPL(dpm_resume_end);
 /*------------------------- Suspend routines -------------------------*/
 
 /**
- *     resume_event - return a PM message representing the resume event
- *                    corresponding to given sleep state.
- *     @sleep_state: PM message representing a sleep state.
+ * resume_event - Return a "resume" message for given "suspend" sleep state.
+ * @sleep_state: PM message representing a sleep state.
+ *
+ * Return a PM message representing the resume event corresponding to given
+ * sleep state.
  */
 static pm_message_t resume_event(pm_message_t sleep_state)
 {
@@ -559,11 +572,12 @@ static pm_message_t resume_event(pm_message_t sleep_state)
 }
 
 /**
- *     device_suspend_noirq - Shut down one device (late suspend).
- *     @dev:   Device.
- *     @state: PM transition of the system being carried out.
+ * device_suspend_noirq - Execute a "late suspend" callback for given device.
+ * @dev: Device to handle.
+ * @state: PM transition of the system being carried out.
  *
- *     This is called with interrupts off and only a single CPU running.
+ * The driver of @dev will not receive interrupts while this function is being
+ * executed.
  */
 static int device_suspend_noirq(struct device *dev, pm_message_t state)
 {
@@ -580,13 +594,11 @@ static int device_suspend_noirq(struct device *dev, pm_message_t state)
 }
 
 /**
- *     dpm_suspend_noirq - Power down all regular (non-sysdev) devices.
- *     @state: PM transition of the system being carried out.
- *
- *     Prevent device drivers from receiving interrupts and call the "noirq"
- *     suspend handlers.
+ * dpm_suspend_noirq - Execute "late suspend" callbacks for non-sysdev devices.
+ * @state: PM transition of the system being carried out.
  *
- *     Must be called under dpm_list_mtx.
+ * Prevent device drivers from receiving interrupts and call the "noirq" suspend
+ * handlers for all non-sysdev devices.
  */
 int dpm_suspend_noirq(pm_message_t state)
 {
@@ -611,9 +623,9 @@ int dpm_suspend_noirq(pm_message_t state)
 EXPORT_SYMBOL_GPL(dpm_suspend_noirq);
 
 /**
- *     device_suspend - Save state of one device.
- *     @dev:   Device.
- *     @state: PM transition of the system being carried out.
+ * device_suspend - Execute "suspend" callbacks for given device.
+ * @dev: Device to handle.
+ * @state: PM transition of the system being carried out.
  */
 static int device_suspend(struct device *dev, pm_message_t state)
 {
@@ -660,10 +672,8 @@ static int device_suspend(struct device *dev, pm_message_t state)
 }
 
 /**
- *     dpm_suspend - Suspend every device.
- *     @state: PM transition of the system being carried out.
- *
- *     Execute the appropriate "suspend" callbacks for all devices.
+ * dpm_suspend - Execute "suspend" callbacks for all non-sysdev devices.
+ * @state: PM transition of the system being carried out.
  */
 static int dpm_suspend(pm_message_t state)
 {
@@ -697,9 +707,12 @@ static int dpm_suspend(pm_message_t state)
 }
 
 /**
- *     device_prepare - Execute the ->prepare() callback(s) for given device.
- *     @dev:   Device.
- *     @state: PM transition of the system being carried out.
+ * device_prepare - Prepare a device for system power transition.
+ * @dev: Device to handle.
+ * @state: PM transition of the system being carried out.
+ *
+ * Execute the ->prepare() callback(s) for given device.  No new children of the
+ * device may be registered after this function has returned.
  */
 static int device_prepare(struct device *dev, pm_message_t state)
 {
@@ -735,10 +748,10 @@ static int device_prepare(struct device *dev, pm_message_t state)
 }
 
 /**
- *     dpm_prepare - Prepare all devices for a PM transition.
- *     @state: PM transition of the system being carried out.
+ * dpm_prepare - Prepare all non-sysdev devices for a system PM transition.
+ * @state: PM transition of the system being carried out.
  *
- *     Execute the ->prepare() callback for all devices.
+ * Execute the ->prepare() callback(s) for all devices.
  */
 static int dpm_prepare(pm_message_t state)
 {
@@ -755,7 +768,14 @@ static int dpm_prepare(pm_message_t state)
                dev->power.status = DPM_PREPARING;
                mutex_unlock(&dpm_list_mtx);
 
-               error = device_prepare(dev, state);
+               pm_runtime_get_noresume(dev);
+               if (pm_runtime_barrier(dev) && device_may_wakeup(dev)) {
+                       /* Wake-up requested during system sleep transition. */
+                       pm_runtime_put_noidle(dev);
+                       error = -EBUSY;
+               } else {
+                       error = device_prepare(dev, state);
+               }
 
                mutex_lock(&dpm_list_mtx);
                if (error) {
@@ -782,10 +802,11 @@ static int dpm_prepare(pm_message_t state)
 }
 
 /**
- *     dpm_suspend_start - Save state and stop all devices in system.
- *     @state: PM transition of the system being carried out.
+ * dpm_suspend_start - Prepare devices for PM transition and suspend them.
+ * @state: PM transition of the system being carried out.
  *
- *     Prepare and suspend all devices.
+ * Prepare all non-sysdev devices for system PM transition and execute "suspend"
+ * callbacks for them.
  */
 int dpm_suspend_start(pm_message_t state)
 {