Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 57119327 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge branch 'pm-fixes' of git://github.com/rjwysocki/linux-pm

* 'pm-fixes' of git://github.com/rjwysocki/linux-pm:
  PM / Clocks: Do not acquire a mutex under a spinlock
parents b6c8069d e8b364b8
Loading
Loading
Loading
Loading
+38 −37
Original line number Diff line number Diff line
@@ -41,6 +41,22 @@ static struct pm_clk_data *__to_pcd(struct device *dev)
	return dev ? dev->power.subsys_data : NULL;
}

/**
 * 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.
@@ -73,6 +89,8 @@ int pm_clk_add(struct device *dev, const char *con_id)
		}
	}

	pm_clk_acquire(dev, ce);

	spin_lock_irq(&pcd->lock);
	list_add_tail(&ce->node, &pcd->clock_list);
	spin_unlock_irq(&pcd->lock);
@@ -82,17 +100,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);
@@ -126,18 +139,22 @@ void pm_clk_remove(struct device *dev, const char *con_id)
	spin_lock_irq(&pcd->lock);

	list_for_each_entry(ce, &pcd->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(&pcd->lock);
	return;

 remove:
	list_del(&ce->node);
	spin_unlock_irq(&pcd->lock);

	__pm_clk_remove(ce);
}

/**
@@ -175,43 +192,33 @@ void pm_clk_destroy(struct device *dev)
{
	struct pm_clk_data *pcd = __to_pcd(dev);
	struct pm_clock_entry *ce, *c;
	struct list_head list;

	if (!pcd)
		return;

	dev->power.subsys_data = NULL;
	INIT_LIST_HEAD(&list);

	spin_lock_irq(&pcd->lock);

	list_for_each_entry_safe_reverse(ce, c, &pcd->clock_list, node)
		__pm_clk_remove(ce);
		list_move(&ce->node, &list);

	spin_unlock_irq(&pcd->lock);

	kfree(pcd);

	list_for_each_entry_safe_reverse(ce, c, &list, node) {
		list_del(&ce->node);
		__pm_clk_remove(ce);
	}
}

#endif /* CONFIG_PM */

#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.
@@ -230,9 +237,6 @@ int pm_clk_suspend(struct device *dev)
	spin_lock_irqsave(&pcd->lock, flags);

	list_for_each_entry_reverse(ce, &pcd->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;
@@ -262,9 +266,6 @@ int pm_clk_resume(struct device *dev)
	spin_lock_irqsave(&pcd->lock, flags);

	list_for_each_entry(ce, &pcd->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;