PM / Domains: Use power.sybsys_data to reduce overhead
authorRafael J. Wysocki <rjw@sisk.pl>
Thu, 25 Aug 2011 13:34:12 +0000 (15:34 +0200)
committerRafael J. Wysocki <rjw@sisk.pl>
Thu, 25 Aug 2011 13:34:12 +0000 (15:34 +0200)
Currently pm_genpd_runtime_resume() has to walk the list of devices
from the device's PM domain to find the corresponding device list
object containing the need_restore field to check if the driver's
.runtime_resume() callback should be executed for the device.
This is suboptimal and can be simplified by using power.sybsys_data
to store device information used by the generic PM domains code.

Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
arch/arm/mach-shmobile/pm-sh7372.c
drivers/base/power/domain.c
include/linux/pm.h
include/linux/pm_domain.h
include/linux/pm_runtime.h

index 54d4d86883c9b6fb860107f5c43e72483b6054dd..4aeca0adae56fdb317fdd2da9bd2f52918216e62 100644 (file)
@@ -114,11 +114,9 @@ void sh7372_add_device_to_domain(struct sh7372_pm_domain *sh7372_pd,
 {
        struct device *dev = &pdev->dev;
 
-       if (!dev->power.subsys_data) {
-               pm_clk_create(dev);
-               pm_clk_add(dev, NULL);
-       }
        pm_genpd_add_device(&sh7372_pd->genpd, dev);
+       if (pm_clk_no_clocks(dev))
+               pm_clk_add(dev, NULL);
 }
 
 void sh7372_pm_add_subdomain(struct sh7372_pm_domain *sh7372_pd,
index 1fc6cc9835ad0a087c6a49a462fe472d4901f5ca..339eb2d9bddab16678048c9526672b4bb4e2139b 100644 (file)
@@ -181,18 +181,18 @@ int pm_genpd_poweron(struct generic_pm_domain *genpd)
 
 /**
  * __pm_genpd_save_device - Save the pre-suspend state of a device.
- * @dle: Device list entry of the device to save the state of.
+ * @pdd: Domain data of the device to save the state of.
  * @genpd: PM domain the device belongs to.
  */
-static int __pm_genpd_save_device(struct dev_list_entry *dle,
+static int __pm_genpd_save_device(struct pm_domain_data *pdd,
                                  struct generic_pm_domain *genpd)
        __releases(&genpd->lock) __acquires(&genpd->lock)
 {
-       struct device *dev = dle->dev;
+       struct device *dev = pdd->dev;
        struct device_driver *drv = dev->driver;
        int ret = 0;
 
-       if (dle->need_restore)
+       if (pdd->need_restore)
                return 0;
 
        mutex_unlock(&genpd->lock);
@@ -210,24 +210,24 @@ static int __pm_genpd_save_device(struct dev_list_entry *dle,
        mutex_lock(&genpd->lock);
 
        if (!ret)
-               dle->need_restore = true;
+               pdd->need_restore = true;
 
        return ret;
 }
 
 /**
  * __pm_genpd_restore_device - Restore the pre-suspend state of a device.
- * @dle: Device list entry of the device to restore the state of.
+ * @pdd: Domain data of the device to restore the state of.
  * @genpd: PM domain the device belongs to.
  */
-static void __pm_genpd_restore_device(struct dev_list_entry *dle,
+static void __pm_genpd_restore_device(struct pm_domain_data *pdd,
                                      struct generic_pm_domain *genpd)
        __releases(&genpd->lock) __acquires(&genpd->lock)
 {
-       struct device *dev = dle->dev;
+       struct device *dev = pdd->dev;
        struct device_driver *drv = dev->driver;
 
-       if (!dle->need_restore)
+       if (!pdd->need_restore)
                return;
 
        mutex_unlock(&genpd->lock);
@@ -244,7 +244,7 @@ static void __pm_genpd_restore_device(struct dev_list_entry *dle,
 
        mutex_lock(&genpd->lock);
 
-       dle->need_restore = false;
+       pdd->need_restore = false;
 }
 
 /**
@@ -286,7 +286,7 @@ void genpd_queue_power_off_work(struct generic_pm_domain *genpd)
 static int pm_genpd_poweroff(struct generic_pm_domain *genpd)
        __releases(&genpd->lock) __acquires(&genpd->lock)
 {
-       struct dev_list_entry *dle;
+       struct pm_domain_data *pdd;
        struct gpd_link *link;
        unsigned int not_suspended;
        int ret = 0;
@@ -308,8 +308,8 @@ static int pm_genpd_poweroff(struct generic_pm_domain *genpd)
                return -EBUSY;
 
        not_suspended = 0;
-       list_for_each_entry(dle, &genpd->dev_list, node)
-               if (dle->dev->driver && !pm_runtime_suspended(dle->dev))
+       list_for_each_entry(pdd, &genpd->dev_list, list_node)
+               if (pdd->dev->driver && !pm_runtime_suspended(pdd->dev))
                        not_suspended++;
 
        if (not_suspended > genpd->in_progress)
@@ -332,9 +332,9 @@ static int pm_genpd_poweroff(struct generic_pm_domain *genpd)
        genpd->status = GPD_STATE_BUSY;
        genpd->poweroff_task = current;
 
-       list_for_each_entry_reverse(dle, &genpd->dev_list, node) {
+       list_for_each_entry_reverse(pdd, &genpd->dev_list, list_node) {
                ret = atomic_read(&genpd->sd_count) == 0 ?
-                       __pm_genpd_save_device(dle, genpd) : -EBUSY;
+                       __pm_genpd_save_device(pdd, genpd) : -EBUSY;
 
                if (genpd_abort_poweroff(genpd))
                        goto out;
@@ -432,24 +432,6 @@ static int pm_genpd_runtime_suspend(struct device *dev)
        return 0;
 }
 
-/**
- * __pm_genpd_runtime_resume - Resume a device belonging to I/O PM domain.
- * @dev: Device to resume.
- * @genpd: PM domain the device belongs to.
- */
-static void __pm_genpd_runtime_resume(struct device *dev,
-                                     struct generic_pm_domain *genpd)
-{
-       struct dev_list_entry *dle;
-
-       list_for_each_entry(dle, &genpd->dev_list, node) {
-               if (dle->dev == dev) {
-                       __pm_genpd_restore_device(dle, genpd);
-                       break;
-               }
-       }
-}
-
 /**
  * pm_genpd_runtime_resume - Resume a device belonging to I/O PM domain.
  * @dev: Device to resume.
@@ -495,7 +477,7 @@ static int pm_genpd_runtime_resume(struct device *dev)
                mutex_lock(&genpd->lock);
        }
        finish_wait(&genpd->status_wait_queue, &wait);
-       __pm_genpd_runtime_resume(dev, genpd);
+       __pm_genpd_restore_device(&dev->power.subsys_data->domain_data, genpd);
        genpd->resume_count--;
        genpd_set_active(genpd);
        wake_up_all(&genpd->status_wait_queue);
@@ -525,8 +507,6 @@ void pm_genpd_poweroff_unused(void)
 #else
 
 static inline void genpd_power_off_work_fn(struct work_struct *work) {}
-static inline void __pm_genpd_runtime_resume(struct device *dev,
-                                            struct generic_pm_domain *genpd) {}
 
 #define pm_genpd_runtime_suspend       NULL
 #define pm_genpd_runtime_resume                NULL
@@ -1083,7 +1063,7 @@ static void pm_genpd_complete(struct device *dev)
  */
 int pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev)
 {
-       struct dev_list_entry *dle;
+       struct pm_domain_data *pdd;
        int ret = 0;
 
        dev_dbg(dev, "%s()\n", __func__);
@@ -1103,26 +1083,20 @@ int pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev)
                goto out;
        }
 
-       list_for_each_entry(dle, &genpd->dev_list, node)
-               if (dle->dev == dev) {
+       list_for_each_entry(pdd, &genpd->dev_list, list_node)
+               if (pdd->dev == dev) {
                        ret = -EINVAL;
                        goto out;
                }
 
-       dle = kzalloc(sizeof(*dle), GFP_KERNEL);
-       if (!dle) {
-               ret = -ENOMEM;
-               goto out;
-       }
-
-       dle->dev = dev;
-       dle->need_restore = false;
-       list_add_tail(&dle->node, &genpd->dev_list);
        genpd->device_count++;
 
-       spin_lock_irq(&dev->power.lock);
        dev->pm_domain = &genpd->domain;
-       spin_unlock_irq(&dev->power.lock);
+       dev_pm_get_subsys_data(dev);
+       pdd = &dev->power.subsys_data->domain_data;
+       pdd->dev = dev;
+       pdd->need_restore = false;
+       list_add_tail(&pdd->list_node, &genpd->dev_list);
 
  out:
        genpd_release_lock(genpd);
@@ -1138,7 +1112,7 @@ int pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev)
 int pm_genpd_remove_device(struct generic_pm_domain *genpd,
                           struct device *dev)
 {
-       struct dev_list_entry *dle;
+       struct pm_domain_data *pdd;
        int ret = -EINVAL;
 
        dev_dbg(dev, "%s()\n", __func__);
@@ -1153,17 +1127,16 @@ int pm_genpd_remove_device(struct generic_pm_domain *genpd,
                goto out;
        }
 
-       list_for_each_entry(dle, &genpd->dev_list, node) {
-               if (dle->dev != dev)
+       list_for_each_entry(pdd, &genpd->dev_list, list_node) {
+               if (pdd->dev != dev)
                        continue;
 
-               spin_lock_irq(&dev->power.lock);
+               list_del_init(&pdd->list_node);
+               pdd->dev = NULL;
+               dev_pm_put_subsys_data(dev);
                dev->pm_domain = NULL;
-               spin_unlock_irq(&dev->power.lock);
 
                genpd->device_count--;
-               list_del(&dle->node);
-               kfree(dle);
 
                ret = 0;
                break;
index c6b5a0a41ab367f1f612e2d718aa66235985822c..ed10f24d525993d50bd4a121b162ae37edeb7f36 100644 (file)
@@ -421,12 +421,21 @@ enum rpm_request {
 
 struct wakeup_source;
 
+struct pm_domain_data {
+       struct list_head list_node;
+       struct device *dev;
+       bool need_restore;
+};
+
 struct pm_subsys_data {
        spinlock_t lock;
        unsigned int refcount;
 #ifdef CONFIG_PM_CLK
        struct list_head clock_list;
 #endif
+#ifdef CONFIG_PM_GENERIC_DOMAINS
+       struct pm_domain_data domain_data;
+#endif
 };
 
 struct dev_pm_info {
index bf679f59f9a85fd617482b2897644c3f03113150..5cce46c2d926a062a56585d683b6f9c266ad7c14 100644 (file)
@@ -61,12 +61,6 @@ struct gpd_link {
        struct list_head slave_node;
 };
 
-struct dev_list_entry {
-       struct list_head node;
-       struct device *dev;
-       bool need_restore;
-};
-
 #ifdef CONFIG_PM_GENERIC_DOMAINS
 extern int pm_genpd_add_device(struct generic_pm_domain *genpd,
                               struct device *dev);
index 6b90630e3c98c571e32c917012a146ce6d9588de..a5a41a850efb0a2cb79ef56c36e81ed92a3fffe7 100644 (file)
@@ -258,6 +258,12 @@ struct pm_clk_notifier_block {
 };
 
 #ifdef CONFIG_PM_CLK
+static inline bool pm_clk_no_clocks(struct device *dev)
+{
+       return dev && dev->power.subsys_data
+               && list_empty(&dev->power.subsys_data->clock_list);
+}
+
 extern void pm_clk_init(struct device *dev);
 extern int pm_clk_create(struct device *dev);
 extern void pm_clk_destroy(struct device *dev);
@@ -266,6 +272,10 @@ extern void pm_clk_remove(struct device *dev, const char *con_id);
 extern int pm_clk_suspend(struct device *dev);
 extern int pm_clk_resume(struct device *dev);
 #else
+static inline bool pm_clk_no_clocks(struct device *dev)
+{
+       return true;
+}
 static inline void pm_clk_init(struct device *dev)
 {
 }