summary refs log tree commit diff
path: root/drivers/base/power/clock_ops.c
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2011-09-26 20:12:45 +0200
committerRafael J. Wysocki <rjw@sisk.pl>2011-09-26 20:12:45 +0200
commit0d41da2e31e81f5c8aaabe17f769de4304b2d4c8 (patch)
tree540acefba9bf01d3880d7bacb767fbf9b1fe80b4 /drivers/base/power/clock_ops.c
parenta0089bd617adea27ebc352e1e0871649ab1dbaa6 (diff)
parente8b364b88cc4001b21c28c1ecf1e1e3ffbe162e6 (diff)
downloadlinux-0d41da2e31e81f5c8aaabe17f769de4304b2d4c8.tar.gz
Merge branch 'pm-fixes' into pm-domains
Merge commit e8b364b88cc4001b21c28c1ecf1e1e3ffbe162e6
(PM / Clocks: Do not acquire a mutex under a spinlock) fixing
a regression in drivers/base/power/clock_ops.c.

Conflicts:
	drivers/base/power/clock_ops.c
Diffstat (limited to 'drivers/base/power/clock_ops.c')
-rw-r--r--drivers/base/power/clock_ops.c76
1 files changed, 39 insertions, 37 deletions
diff --git a/drivers/base/power/clock_ops.c b/drivers/base/power/clock_ops.c
index cb44b58d6813..b876e60a53ef 100644
--- a/drivers/base/power/clock_ops.c
+++ b/drivers/base/power/clock_ops.c
@@ -32,6 +32,22 @@ struct pm_clock_entry {
 };
 
 /**
+ * pm_clk_acquire - Acquire a device clock.
+ * @dev: Device whose clock is to be acquired.
+ * @ce: PM clock entry corresponding to the clock.
+ */
+static void pm_clk_acquire(struct device *dev, struct pm_clock_entry *ce)
+{
+	ce->clk = clk_get(dev, ce->con_id);
+	if (IS_ERR(ce->clk)) {
+		ce->status = PCE_STATUS_ERROR;
+	} else {
+		ce->status = PCE_STATUS_ACQUIRED;
+		dev_dbg(dev, "Clock %s managed by runtime PM.\n", ce->con_id);
+	}
+}
+
+/**
  * pm_clk_add - Start using a device clock for power management.
  * @dev: Device whose clock is going to be used for power management.
  * @con_id: Connection ID of the clock.
@@ -63,6 +79,8 @@ int pm_clk_add(struct device *dev, const char *con_id)
 		}
 	}
 
+	pm_clk_acquire(dev, ce);
+
 	spin_lock_irq(&psd->lock);
 	list_add_tail(&ce->node, &psd->clock_list);
 	spin_unlock_irq(&psd->lock);
@@ -72,17 +90,12 @@ int pm_clk_add(struct device *dev, const char *con_id)
 /**
  * __pm_clk_remove - Destroy PM clock entry.
  * @ce: PM clock entry to destroy.
- *
- * This routine must be called under the spinlock protecting the PM list of
- * clocks corresponding the the @ce's device.
  */
 static void __pm_clk_remove(struct pm_clock_entry *ce)
 {
 	if (!ce)
 		return;
 
-	list_del(&ce->node);
-
 	if (ce->status < PCE_STATUS_ERROR) {
 		if (ce->status == PCE_STATUS_ENABLED)
 			clk_disable(ce->clk);
@@ -116,18 +129,22 @@ void pm_clk_remove(struct device *dev, const char *con_id)
 	spin_lock_irq(&psd->lock);
 
 	list_for_each_entry(ce, &psd->clock_list, node) {
-		if (!con_id && !ce->con_id) {
-			__pm_clk_remove(ce);
-			break;
-		} else if (!con_id || !ce->con_id) {
+		if (!con_id && !ce->con_id)
+			goto remove;
+		else if (!con_id || !ce->con_id)
 			continue;
-		} else if (!strcmp(con_id, ce->con_id)) {
-			__pm_clk_remove(ce);
-			break;
-		}
+		else if (!strcmp(con_id, ce->con_id))
+			goto remove;
 	}
 
 	spin_unlock_irq(&psd->lock);
+	return;
+
+ remove:
+	list_del(&ce->node);
+	spin_unlock_irq(&psd->lock);
+
+	__pm_clk_remove(ce);
 }
 
 /**
@@ -169,18 +186,26 @@ void pm_clk_destroy(struct device *dev)
 {
 	struct pm_subsys_data *psd = dev_to_psd(dev);
 	struct pm_clock_entry *ce, *c;
+	struct list_head list;
 
 	if (!psd)
 		return;
 
+	INIT_LIST_HEAD(&list);
+
 	spin_lock_irq(&psd->lock);
 
 	list_for_each_entry_safe_reverse(ce, c, &psd->clock_list, node)
-		__pm_clk_remove(ce);
+		list_move(&ce->node, &list);
 
 	spin_unlock_irq(&psd->lock);
 
 	dev_pm_put_subsys_data(dev);
+
+	list_for_each_entry_safe_reverse(ce, c, &list, node) {
+		list_del(&ce->node);
+		__pm_clk_remove(ce);
+	}
 }
 
 #endif /* CONFIG_PM */
@@ -188,23 +213,6 @@ void pm_clk_destroy(struct device *dev)
 #ifdef CONFIG_PM_RUNTIME
 
 /**
- * pm_clk_acquire - Acquire a device clock.
- * @dev: Device whose clock is to be acquired.
- * @con_id: Connection ID of the clock.
- */
-static void pm_clk_acquire(struct device *dev,
-				    struct pm_clock_entry *ce)
-{
-	ce->clk = clk_get(dev, ce->con_id);
-	if (IS_ERR(ce->clk)) {
-		ce->status = PCE_STATUS_ERROR;
-	} else {
-		ce->status = PCE_STATUS_ACQUIRED;
-		dev_dbg(dev, "Clock %s managed by runtime PM.\n", ce->con_id);
-	}
-}
-
-/**
  * pm_clk_suspend - Disable clocks in a device's PM clock list.
  * @dev: Device to disable the clocks for.
  */
@@ -222,9 +230,6 @@ int pm_clk_suspend(struct device *dev)
 	spin_lock_irqsave(&psd->lock, flags);
 
 	list_for_each_entry_reverse(ce, &psd->clock_list, node) {
-		if (ce->status == PCE_STATUS_NONE)
-			pm_clk_acquire(dev, ce);
-
 		if (ce->status < PCE_STATUS_ERROR) {
 			clk_disable(ce->clk);
 			ce->status = PCE_STATUS_ACQUIRED;
@@ -254,9 +259,6 @@ int pm_clk_resume(struct device *dev)
 	spin_lock_irqsave(&psd->lock, flags);
 
 	list_for_each_entry(ce, &psd->clock_list, node) {
-		if (ce->status == PCE_STATUS_NONE)
-			pm_clk_acquire(dev, ce);
-
 		if (ce->status < PCE_STATUS_ERROR) {
 			clk_enable(ce->clk);
 			ce->status = PCE_STATUS_ENABLED;