]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/base/power/main.c
PM: Handle device registrations during suspend/resume
[linux-2.6-omap-h63xx.git] / drivers / base / power / main.c
index 26de2c0fda8032b9c03d679895f0929d3789f8bb..0e3991a437c60fe64bcffa61b6d090daecbe09ca 100644 (file)
@@ -54,7 +54,8 @@ static LIST_HEAD(dpm_destroy);
 
 static DEFINE_MUTEX(dpm_list_mtx);
 
-static DECLARE_RWSEM(pm_sleep_rwsem);
+/* 'true' if all devices have been suspended, protected by dpm_list_mtx */
+static bool all_sleeping;
 
 int (*platform_enable_wakeup)(struct device *dev, int is_on);
 
@@ -62,14 +63,28 @@ int (*platform_enable_wakeup)(struct device *dev, int is_on);
  *     device_pm_add - add a device to the list of active devices
  *     @dev:   Device to be added to the list
  */
-void device_pm_add(struct device *dev)
+int device_pm_add(struct device *dev)
 {
+       int error = 0;
+
        pr_debug("PM: Adding info for %s:%s\n",
                 dev->bus ? dev->bus->name : "No Bus",
                 kobject_name(&dev->kobj));
        mutex_lock(&dpm_list_mtx);
-       list_add_tail(&dev->power.entry, &dpm_active);
+       if ((dev->parent && dev->parent->power.sleeping) || all_sleeping) {
+               if (dev->parent->power.sleeping)
+                       dev_warn(dev,
+                               "parent %s is sleeping, will not add\n",
+                               dev->parent->bus_id);
+               else
+                       dev_warn(dev, "devices are sleeping, will not add\n");
+               WARN_ON(true);
+               error = -EBUSY;
+       } else {
+               list_add_tail(&dev->power.entry, &dpm_active);
+       }
        mutex_unlock(&dpm_list_mtx);
+       return error;
 }
 
 /**
@@ -107,32 +122,6 @@ void device_pm_schedule_removal(struct device *dev)
 }
 EXPORT_SYMBOL_GPL(device_pm_schedule_removal);
 
-/**
- *     pm_sleep_lock - mutual exclusion for registration and suspend
- *
- *     Returns 0 if no suspend is underway and device registration
- *     may proceed, otherwise -EBUSY.
- */
-int pm_sleep_lock(void)
-{
-       if (down_read_trylock(&pm_sleep_rwsem))
-               return 0;
-
-       return -EBUSY;
-}
-
-/**
- *     pm_sleep_unlock - mutual exclusion for registration and suspend
- *
- *     This routine undoes the effect of device_pm_add_lock
- *     when a device's registration is complete.
- */
-void pm_sleep_unlock(void)
-{
-       up_read(&pm_sleep_rwsem);
-}
-
-
 /*------------------------- Resume routines -------------------------*/
 
 /**
@@ -242,11 +231,13 @@ static int resume_device(struct device *dev)
 static void dpm_resume(void)
 {
        mutex_lock(&dpm_list_mtx);
+       all_sleeping = false;
        while(!list_empty(&dpm_off)) {
                struct list_head *entry = dpm_off.next;
                struct device *dev = to_device(entry);
 
                list_move_tail(entry, &dpm_active);
+               dev->power.sleeping = false;
                mutex_unlock(&dpm_list_mtx);
                resume_device(dev);
                mutex_lock(&dpm_list_mtx);
@@ -285,7 +276,6 @@ void device_resume(void)
        might_sleep();
        dpm_resume();
        unregister_dropped_devices();
-       up_write(&pm_sleep_rwsem);
 }
 EXPORT_SYMBOL_GPL(device_resume);
 
@@ -421,6 +411,9 @@ static int dpm_suspend(pm_message_t state)
                struct list_head *entry = dpm_active.prev;
                struct device *dev = to_device(entry);
 
+               WARN_ON(dev->parent && dev->parent->power.sleeping);
+
+               dev->power.sleeping = true;
                mutex_unlock(&dpm_list_mtx);
                error = suspend_device(dev, state);
                mutex_lock(&dpm_list_mtx);
@@ -432,11 +425,14 @@ static int dpm_suspend(pm_message_t state)
                                        (error == -EAGAIN ?
                                        " (please convert to suspend_late)" :
                                        ""));
+                       dev->power.sleeping = false;
                        break;
                }
                if (!list_empty(&dev->power.entry))
                        list_move(&dev->power.entry, &dpm_off);
        }
+       if (!error)
+               all_sleeping = true;
        mutex_unlock(&dpm_list_mtx);
 
        return error;
@@ -454,7 +450,6 @@ int device_suspend(pm_message_t state)
        int error;
 
        might_sleep();
-       down_write(&pm_sleep_rwsem);
        error = dpm_suspend(state);
        if (error)
                device_resume();