Commit c3391e36 authored by Ben Dooks's avatar Ben Dooks

[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
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/ioport.h> #include <linux/ioport.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/mutex.h> #include <linux/spinlock.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/io.h> #include <linux/io.h>
...@@ -55,7 +55,11 @@ ...@@ -55,7 +55,11 @@
static LIST_HEAD(clocks); 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 */ /* enable and disable calls for use with the clk struct */
...@@ -77,7 +81,7 @@ struct clk *clk_get(struct device *dev, const char *id) ...@@ -77,7 +81,7 @@ struct clk *clk_get(struct device *dev, const char *id)
else else
idno = to_platform_device(dev)->id; idno = to_platform_device(dev)->id;
mutex_lock(&clocks_mutex); spin_lock(&clocks_lock);
list_for_each_entry(p, &clocks, list) { list_for_each_entry(p, &clocks, list) {
if (p->id == idno && if (p->id == idno &&
...@@ -101,7 +105,7 @@ struct clk *clk_get(struct device *dev, const char *id) ...@@ -101,7 +105,7 @@ struct clk *clk_get(struct device *dev, const char *id)
} }
} }
mutex_unlock(&clocks_mutex); spin_unlock(&clocks_lock);
return clk; return clk;
} }
...@@ -117,12 +121,12 @@ int clk_enable(struct clk *clk) ...@@ -117,12 +121,12 @@ int clk_enable(struct clk *clk)
clk_enable(clk->parent); clk_enable(clk->parent);
mutex_lock(&clocks_mutex); spin_lock(&clocks_lock);
if ((clk->usage++) == 0) if ((clk->usage++) == 0)
(clk->enable)(clk, 1); (clk->enable)(clk, 1);
mutex_unlock(&clocks_mutex); spin_unlock(&clocks_lock);
return 0; return 0;
} }
...@@ -131,12 +135,12 @@ void clk_disable(struct clk *clk) ...@@ -131,12 +135,12 @@ void clk_disable(struct clk *clk)
if (IS_ERR(clk) || clk == NULL) if (IS_ERR(clk) || clk == NULL)
return; return;
mutex_lock(&clocks_mutex); spin_lock(&clocks_lock);
if ((--clk->usage) == 0) if ((--clk->usage) == 0)
(clk->enable)(clk, 0); (clk->enable)(clk, 0);
mutex_unlock(&clocks_mutex); spin_unlock(&clocks_lock);
clk_disable(clk->parent); clk_disable(clk->parent);
} }
...@@ -182,9 +186,9 @@ int clk_set_rate(struct clk *clk, unsigned long rate) ...@@ -182,9 +186,9 @@ int clk_set_rate(struct clk *clk, unsigned long rate)
if (clk->set_rate == NULL) if (clk->set_rate == NULL)
return -EINVAL; return -EINVAL;
mutex_lock(&clocks_mutex); spin_lock(&clocks_lock);
ret = (clk->set_rate)(clk, rate); ret = (clk->set_rate)(clk, rate);
mutex_unlock(&clocks_mutex); spin_unlock(&clocks_lock);
return ret; return ret;
} }
...@@ -201,12 +205,12 @@ int clk_set_parent(struct clk *clk, struct clk *parent) ...@@ -201,12 +205,12 @@ int clk_set_parent(struct clk *clk, struct clk *parent)
if (IS_ERR(clk)) if (IS_ERR(clk))
return -EINVAL; return -EINVAL;
mutex_lock(&clocks_mutex); spin_lock(&clocks_lock);
if (clk->set_parent) if (clk->set_parent)
ret = (clk->set_parent)(clk, parent); ret = (clk->set_parent)(clk, parent);
mutex_unlock(&clocks_mutex); spin_unlock(&clocks_lock);
return ret; return ret;
} }
...@@ -302,9 +306,9 @@ int s3c24xx_register_clock(struct clk *clk) ...@@ -302,9 +306,9 @@ int s3c24xx_register_clock(struct clk *clk)
/* add to the list of available clocks */ /* add to the list of available clocks */
mutex_lock(&clocks_mutex); spin_lock(&clocks_lock);
list_add(&clk->list, &clocks); list_add(&clk->list, &clocks);
mutex_unlock(&clocks_mutex); spin_unlock(&clocks_lock);
return 0; return 0;
} }
......
...@@ -10,6 +10,8 @@ ...@@ -10,6 +10,8 @@
* published by the Free Software Foundation. * published by the Free Software Foundation.
*/ */
#include <linux/spinlock.h>
struct clk { struct clk {
struct list_head list; struct list_head list;
struct module *owner; struct module *owner;
...@@ -51,7 +53,7 @@ extern struct clk clk_xtal; ...@@ -51,7 +53,7 @@ extern struct clk clk_xtal;
* Please DO NOT use these outside of arch/arm/mach-s3c2410 * 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); extern int s3c2410_clkcon_enable(struct clk *clk, int enable);
......
...@@ -31,7 +31,6 @@ ...@@ -31,7 +31,6 @@
#include <linux/sysdev.h> #include <linux/sysdev.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/ioport.h> #include <linux/ioport.h>
#include <linux/mutex.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/io.h> #include <linux/io.h>
...@@ -102,13 +101,13 @@ static int s3c244x_clk_add(struct sys_device *sysdev) ...@@ -102,13 +101,13 @@ static int s3c244x_clk_add(struct sys_device *sysdev)
if (clk_get_rate(clock_upll) > (94 * MHZ)) { if (clk_get_rate(clock_upll) > (94 * MHZ)) {
clk_usb_bus.rate = clk_get_rate(clock_upll) / 2; clk_usb_bus.rate = clk_get_rate(clock_upll) / 2;
mutex_lock(&clocks_mutex); spin_lock(&clocks_lock);
clkdivn = __raw_readl(S3C2410_CLKDIVN); clkdivn = __raw_readl(S3C2410_CLKDIVN);
clkdivn |= S3C2440_CLKDIVN_UCLK; clkdivn |= S3C2440_CLKDIVN_UCLK;
__raw_writel(clkdivn, S3C2410_CLKDIVN); __raw_writel(clkdivn, S3C2410_CLKDIVN);
mutex_unlock(&clocks_mutex); spin_unlock(&clocks_lock);
} }
return 0; return 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment