[ARM] S3C24XX: Change clock locking to use spinlocks.
authorBen Dooks <ben-linux@fluff.org>
Tue, 21 Oct 2008 13:06:37 +0000 (14:06 +0100)
committerBen Dooks <ben-linux@fluff.org>
Mon, 15 Dec 2008 21:46:07 +0000 (21:46 +0000)
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: Ben Dooks <ben-linux@fluff.org>
arch/arm/plat-s3c24xx/clock.c
arch/arm/plat-s3c24xx/include/plat/clock.h
arch/arm/plat-s3c24xx/s3c244x-clock.c

index 1ff1b98..334e696 100644 (file)
@@ -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>
 
 
 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;
 }
index 235b753..88a00c3 100644 (file)
@@ -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);
 
index 7c09773..dde41f1 100644 (file)
@@ -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;