Commit c3391e36 authored by Ben Dooks's avatar Ben Dooks
Browse files

[ARM] S3C24XX: Change clock locking to use spinlocks.



We cannot sleep if we have cpufreq pm enabled during some
of the clock operations, so change to use a spinlock to
protect the clock system.

Signed-off-by: default avatarBen Dooks <ben-linux@fluff.org>
parent 30555476
Loading
Loading
Loading
Loading
+18 −14
Original line number Diff line number Diff line
@@ -37,7 +37,7 @@
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/clk.h>
#include <linux/mutex.h>
#include <linux/spinlock.h>
#include <linux/delay.h>
#include <linux/io.h>

@@ -55,7 +55,11 @@

static LIST_HEAD(clocks);

DEFINE_MUTEX(clocks_mutex);
/* We originally used an mutex here, but some contexts (see resume)
 * are calling functions such as clk_set_parent() with IRQs disabled
 * causing an BUG to be triggered.
 */
DEFINE_SPINLOCK(clocks_lock);

/* enable and disable calls for use with the clk struct */

@@ -77,7 +81,7 @@ struct clk *clk_get(struct device *dev, const char *id)
	else
		idno = to_platform_device(dev)->id;

	mutex_lock(&clocks_mutex);
	spin_lock(&clocks_lock);

	list_for_each_entry(p, &clocks, list) {
		if (p->id == idno &&
@@ -101,7 +105,7 @@ struct clk *clk_get(struct device *dev, const char *id)
		}
	}

	mutex_unlock(&clocks_mutex);
	spin_unlock(&clocks_lock);
	return clk;
}

@@ -117,12 +121,12 @@ int clk_enable(struct clk *clk)

	clk_enable(clk->parent);

	mutex_lock(&clocks_mutex);
	spin_lock(&clocks_lock);

	if ((clk->usage++) == 0)
		(clk->enable)(clk, 1);

	mutex_unlock(&clocks_mutex);
	spin_unlock(&clocks_lock);
	return 0;
}

@@ -131,12 +135,12 @@ void clk_disable(struct clk *clk)
	if (IS_ERR(clk) || clk == NULL)
		return;

	mutex_lock(&clocks_mutex);
	spin_lock(&clocks_lock);

	if ((--clk->usage) == 0)
		(clk->enable)(clk, 0);

	mutex_unlock(&clocks_mutex);
	spin_unlock(&clocks_lock);
	clk_disable(clk->parent);
}

@@ -182,9 +186,9 @@ int clk_set_rate(struct clk *clk, unsigned long rate)
	if (clk->set_rate == NULL)
		return -EINVAL;

	mutex_lock(&clocks_mutex);
	spin_lock(&clocks_lock);
	ret = (clk->set_rate)(clk, rate);
	mutex_unlock(&clocks_mutex);
	spin_unlock(&clocks_lock);

	return ret;
}
@@ -201,12 +205,12 @@ int clk_set_parent(struct clk *clk, struct clk *parent)
	if (IS_ERR(clk))
		return -EINVAL;

	mutex_lock(&clocks_mutex);
	spin_lock(&clocks_lock);

	if (clk->set_parent)
		ret = (clk->set_parent)(clk, parent);

	mutex_unlock(&clocks_mutex);
	spin_unlock(&clocks_lock);

	return ret;
}
@@ -302,9 +306,9 @@ int s3c24xx_register_clock(struct clk *clk)

	/* add to the list of available clocks */

	mutex_lock(&clocks_mutex);
	spin_lock(&clocks_lock);
	list_add(&clk->list, &clocks);
	mutex_unlock(&clocks_mutex);
	spin_unlock(&clocks_lock);

	return 0;
}
+3 −1
Original line number Diff line number Diff line
@@ -10,6 +10,8 @@
 * published by the Free Software Foundation.
*/

#include <linux/spinlock.h>

struct clk {
	struct list_head      list;
	struct module        *owner;
@@ -51,7 +53,7 @@ extern struct clk clk_xtal;
 * Please DO NOT use these outside of arch/arm/mach-s3c2410
*/

extern struct mutex clocks_mutex;
extern spinlock_t clocks_lock;

extern int s3c2410_clkcon_enable(struct clk *clk, int enable);

+2 −3
Original line number Diff line number Diff line
@@ -31,7 +31,6 @@
#include <linux/sysdev.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/mutex.h>
#include <linux/clk.h>
#include <linux/io.h>

@@ -102,13 +101,13 @@ static int s3c244x_clk_add(struct sys_device *sysdev)
	if (clk_get_rate(clock_upll) > (94 * MHZ)) {
		clk_usb_bus.rate = clk_get_rate(clock_upll) / 2;

		mutex_lock(&clocks_mutex);
		spin_lock(&clocks_lock);

		clkdivn = __raw_readl(S3C2410_CLKDIVN);
		clkdivn |= S3C2440_CLKDIVN_UCLK;
		__raw_writel(clkdivn, S3C2410_CLKDIVN);

		mutex_unlock(&clocks_mutex);
		spin_unlock(&clocks_lock);
	}

	return 0;