CRISv32: ETRAXFS: Fix recursive spinlock
authorJesper Nilsson <jespern@axis.com>
Mon, 27 Oct 2014 08:11:31 +0000 (09:11 +0100)
committerJesper Nilsson <jespern@axis.com>
Fri, 19 Dec 2014 23:06:04 +0000 (00:06 +0100)
Move pinmux alloc/dealloc code into functions that don't take
the spinlock so we can use from code that has the spinlock already.

CRISv32 has no working SMP, so spinlocks becomes a NOP,
so deadlock was never seen.

Signed-off-by: Jesper Nilsson <jesper.nilsson@axis.com>
arch/cris/arch-v32/mach-fs/pinmux.c
arch/cris/include/arch-v32/mach-fs/mach/pinmux.h

index 38f29eec14a617af2691c8ce35545f1fcc8a4422..05a04708b8eb45b43bfe6cb615e306b472c3de32 100644 (file)
@@ -26,7 +26,29 @@ static DEFINE_SPINLOCK(pinmux_lock);
 
 static void crisv32_pinmux_set(int port);
 
-int crisv32_pinmux_init(void)
+static int __crisv32_pinmux_alloc(int port, int first_pin, int last_pin,
+                                enum pin_mode mode)
+{
+       int i;
+
+       for (i = first_pin; i <= last_pin; i++) {
+               if ((pins[port][i] != pinmux_none)
+                   && (pins[port][i] != pinmux_gpio)
+                   && (pins[port][i] != mode)) {
+#ifdef DEBUG
+                       panic("Pinmux alloc failed!\n");
+#endif
+                       return -EPERM;
+               }
+       }
+
+       for (i = first_pin; i <= last_pin; i++)
+               pins[port][i] = mode;
+
+       crisv32_pinmux_set(port);
+}
+
+static int crisv32_pinmux_init(void)
 {
        static int initialized;
 
@@ -37,20 +59,20 @@ int crisv32_pinmux_init(void)
                pa.pa0 = pa.pa1 = pa.pa2 = pa.pa3 =
                    pa.pa4 = pa.pa5 = pa.pa6 = pa.pa7 = regk_pinmux_yes;
                REG_WR(pinmux, regi_pinmux, rw_pa, pa);
-               crisv32_pinmux_alloc(PORT_B, 0, PORT_PINS - 1, pinmux_gpio);
-               crisv32_pinmux_alloc(PORT_C, 0, PORT_PINS - 1, pinmux_gpio);
-               crisv32_pinmux_alloc(PORT_D, 0, PORT_PINS - 1, pinmux_gpio);
-               crisv32_pinmux_alloc(PORT_E, 0, PORT_PINS - 1, pinmux_gpio);
+               __crisv32_pinmux_alloc(PORT_B, 0, PORT_PINS - 1, pinmux_gpio);
+               __crisv32_pinmux_alloc(PORT_C, 0, PORT_PINS - 1, pinmux_gpio);
+               __crisv32_pinmux_alloc(PORT_D, 0, PORT_PINS - 1, pinmux_gpio);
+               __crisv32_pinmux_alloc(PORT_E, 0, PORT_PINS - 1, pinmux_gpio);
        }
 
        return 0;
 }
 
-int
-crisv32_pinmux_alloc(int port, int first_pin, int last_pin, enum pin_mode mode)
+int crisv32_pinmux_alloc(int port, int first_pin, int last_pin,
+                        enum pin_mode mode)
 {
-       int i;
        unsigned long flags;
+       int ret;
 
        crisv32_pinmux_init();
 
@@ -59,26 +81,11 @@ crisv32_pinmux_alloc(int port, int first_pin, int last_pin, enum pin_mode mode)
 
        spin_lock_irqsave(&pinmux_lock, flags);
 
-       for (i = first_pin; i <= last_pin; i++) {
-               if ((pins[port][i] != pinmux_none)
-                   && (pins[port][i] != pinmux_gpio)
-                   && (pins[port][i] != mode)) {
-                       spin_unlock_irqrestore(&pinmux_lock, flags);
-#ifdef DEBUG
-                       panic("Pinmux alloc failed!\n");
-#endif
-                       return -EPERM;
-               }
-       }
-
-       for (i = first_pin; i <= last_pin; i++)
-               pins[port][i] = mode;
-
-       crisv32_pinmux_set(port);
+       ret = __crisv32_pinmux_alloc(port, first_pin, last_pin, mode);
 
        spin_unlock_irqrestore(&pinmux_lock, flags);
 
-       return 0;
+       return ret;
 }
 
 int crisv32_pinmux_alloc_fixed(enum fixed_function function)
@@ -98,58 +105,58 @@ int crisv32_pinmux_alloc_fixed(enum fixed_function function)
 
        switch (function) {
        case pinmux_ser1:
-               ret = crisv32_pinmux_alloc(PORT_C, 4, 7, pinmux_fixed);
+               ret = __crisv32_pinmux_alloc(PORT_C, 4, 7, pinmux_fixed);
                hwprot.ser1 = regk_pinmux_yes;
                break;
        case pinmux_ser2:
-               ret = crisv32_pinmux_alloc(PORT_C, 8, 11, pinmux_fixed);
+               ret = __crisv32_pinmux_alloc(PORT_C, 8, 11, pinmux_fixed);
                hwprot.ser2 = regk_pinmux_yes;
                break;
        case pinmux_ser3:
-               ret = crisv32_pinmux_alloc(PORT_C, 12, 15, pinmux_fixed);
+               ret = __crisv32_pinmux_alloc(PORT_C, 12, 15, pinmux_fixed);
                hwprot.ser3 = regk_pinmux_yes;
                break;
        case pinmux_sser0:
-               ret = crisv32_pinmux_alloc(PORT_C, 0, 3, pinmux_fixed);
-               ret |= crisv32_pinmux_alloc(PORT_C, 16, 16, pinmux_fixed);
+               ret = __crisv32_pinmux_alloc(PORT_C, 0, 3, pinmux_fixed);
+               ret |= __crisv32_pinmux_alloc(PORT_C, 16, 16, pinmux_fixed);
                hwprot.sser0 = regk_pinmux_yes;
                break;
        case pinmux_sser1:
-               ret = crisv32_pinmux_alloc(PORT_D, 0, 4, pinmux_fixed);
+               ret = __crisv32_pinmux_alloc(PORT_D, 0, 4, pinmux_fixed);
                hwprot.sser1 = regk_pinmux_yes;
                break;
        case pinmux_ata0:
-               ret = crisv32_pinmux_alloc(PORT_D, 5, 7, pinmux_fixed);
-               ret |= crisv32_pinmux_alloc(PORT_D, 15, 17, pinmux_fixed);
+               ret = __crisv32_pinmux_alloc(PORT_D, 5, 7, pinmux_fixed);
+               ret |= __crisv32_pinmux_alloc(PORT_D, 15, 17, pinmux_fixed);
                hwprot.ata0 = regk_pinmux_yes;
                break;
        case pinmux_ata1:
-               ret = crisv32_pinmux_alloc(PORT_D, 0, 4, pinmux_fixed);
-               ret |= crisv32_pinmux_alloc(PORT_E, 17, 17, pinmux_fixed);
+               ret = __crisv32_pinmux_alloc(PORT_D, 0, 4, pinmux_fixed);
+               ret |= __crisv32_pinmux_alloc(PORT_E, 17, 17, pinmux_fixed);
                hwprot.ata1 = regk_pinmux_yes;
                break;
        case pinmux_ata2:
-               ret = crisv32_pinmux_alloc(PORT_C, 11, 15, pinmux_fixed);
-               ret |= crisv32_pinmux_alloc(PORT_E, 3, 3, pinmux_fixed);
+               ret = __crisv32_pinmux_alloc(PORT_C, 11, 15, pinmux_fixed);
+               ret |= __crisv32_pinmux_alloc(PORT_E, 3, 3, pinmux_fixed);
                hwprot.ata2 = regk_pinmux_yes;
                break;
        case pinmux_ata3:
-               ret = crisv32_pinmux_alloc(PORT_C, 8, 10, pinmux_fixed);
-               ret |= crisv32_pinmux_alloc(PORT_C, 0, 2, pinmux_fixed);
+               ret = __crisv32_pinmux_alloc(PORT_C, 8, 10, pinmux_fixed);
+               ret |= __crisv32_pinmux_alloc(PORT_C, 0, 2, pinmux_fixed);
                hwprot.ata2 = regk_pinmux_yes;
                break;
        case pinmux_ata:
-               ret = crisv32_pinmux_alloc(PORT_B, 0, 15, pinmux_fixed);
-               ret |= crisv32_pinmux_alloc(PORT_D, 8, 15, pinmux_fixed);
+               ret = __crisv32_pinmux_alloc(PORT_B, 0, 15, pinmux_fixed);
+               ret |= __crisv32_pinmux_alloc(PORT_D, 8, 15, pinmux_fixed);
                hwprot.ata = regk_pinmux_yes;
                break;
        case pinmux_eth1:
-               ret = crisv32_pinmux_alloc(PORT_E, 0, 17, pinmux_fixed);
+               ret = __crisv32_pinmux_alloc(PORT_E, 0, 17, pinmux_fixed);
                hwprot.eth1 = regk_pinmux_yes;
                hwprot.eth1_mgm = regk_pinmux_yes;
                break;
        case pinmux_timer:
-               ret = crisv32_pinmux_alloc(PORT_C, 16, 16, pinmux_fixed);
+               ret = __crisv32_pinmux_alloc(PORT_C, 16, 16, pinmux_fixed);
                hwprot.timer = regk_pinmux_yes;
                spin_unlock_irqrestore(&pinmux_lock, flags);
                return ret;
@@ -188,9 +195,19 @@ void crisv32_pinmux_set(int port)
 #endif
 }
 
-int crisv32_pinmux_dealloc(int port, int first_pin, int last_pin)
+static int __crisv32_pinmux_dealloc(int port, int first_pin, int last_pin)
 {
        int i;
+
+       for (i = first_pin; i <= last_pin; i++)
+               pins[port][i] = pinmux_none;
+
+       crisv32_pinmux_set(port);
+       return 0;
+}
+
+int crisv32_pinmux_dealloc(int port, int first_pin, int last_pin)
+{
        unsigned long flags;
 
        crisv32_pinmux_init();
@@ -199,11 +216,7 @@ int crisv32_pinmux_dealloc(int port, int first_pin, int last_pin)
                return -EINVAL;
 
        spin_lock_irqsave(&pinmux_lock, flags);
-
-       for (i = first_pin; i <= last_pin; i++)
-               pins[port][i] = pinmux_none;
-
-       crisv32_pinmux_set(port);
+       __crisv32_pinmux_dealloc(port, first_pin, last_pin);
        spin_unlock_irqrestore(&pinmux_lock, flags);
 
        return 0;
@@ -226,58 +239,58 @@ int crisv32_pinmux_dealloc_fixed(enum fixed_function function)
 
        switch (function) {
        case pinmux_ser1:
-               ret = crisv32_pinmux_dealloc(PORT_C, 4, 7);
+               ret = __crisv32_pinmux_dealloc(PORT_C, 4, 7);
                hwprot.ser1 = regk_pinmux_no;
                break;
        case pinmux_ser2:
-               ret = crisv32_pinmux_dealloc(PORT_C, 8, 11);
+               ret = __crisv32_pinmux_dealloc(PORT_C, 8, 11);
                hwprot.ser2 = regk_pinmux_no;
                break;
        case pinmux_ser3:
-               ret = crisv32_pinmux_dealloc(PORT_C, 12, 15);
+               ret = __crisv32_pinmux_dealloc(PORT_C, 12, 15);
                hwprot.ser3 = regk_pinmux_no;
                break;
        case pinmux_sser0:
-               ret = crisv32_pinmux_dealloc(PORT_C, 0, 3);
-               ret |= crisv32_pinmux_dealloc(PORT_C, 16, 16);
+               ret = __crisv32_pinmux_dealloc(PORT_C, 0, 3);
+               ret |= __crisv32_pinmux_dealloc(PORT_C, 16, 16);
                hwprot.sser0 = regk_pinmux_no;
                break;
        case pinmux_sser1:
-               ret = crisv32_pinmux_dealloc(PORT_D, 0, 4);
+               ret = __crisv32_pinmux_dealloc(PORT_D, 0, 4);
                hwprot.sser1 = regk_pinmux_no;
                break;
        case pinmux_ata0:
-               ret = crisv32_pinmux_dealloc(PORT_D, 5, 7);
-               ret |= crisv32_pinmux_dealloc(PORT_D, 15, 17);
+               ret = __crisv32_pinmux_dealloc(PORT_D, 5, 7);
+               ret |= __crisv32_pinmux_dealloc(PORT_D, 15, 17);
                hwprot.ata0 = regk_pinmux_no;
                break;
        case pinmux_ata1:
-               ret = crisv32_pinmux_dealloc(PORT_D, 0, 4);
-               ret |= crisv32_pinmux_dealloc(PORT_E, 17, 17);
+               ret = __crisv32_pinmux_dealloc(PORT_D, 0, 4);
+               ret |= __crisv32_pinmux_dealloc(PORT_E, 17, 17);
                hwprot.ata1 = regk_pinmux_no;
                break;
        case pinmux_ata2:
-               ret = crisv32_pinmux_dealloc(PORT_C, 11, 15);
-               ret |= crisv32_pinmux_dealloc(PORT_E, 3, 3);
+               ret = __crisv32_pinmux_dealloc(PORT_C, 11, 15);
+               ret |= __crisv32_pinmux_dealloc(PORT_E, 3, 3);
                hwprot.ata2 = regk_pinmux_no;
                break;
        case pinmux_ata3:
-               ret = crisv32_pinmux_dealloc(PORT_C, 8, 10);
-               ret |= crisv32_pinmux_dealloc(PORT_C, 0, 2);
+               ret = __crisv32_pinmux_dealloc(PORT_C, 8, 10);
+               ret |= __crisv32_pinmux_dealloc(PORT_C, 0, 2);
                hwprot.ata2 = regk_pinmux_no;
                break;
        case pinmux_ata:
-               ret = crisv32_pinmux_dealloc(PORT_B, 0, 15);
-               ret |= crisv32_pinmux_dealloc(PORT_D, 8, 15);
+               ret = __crisv32_pinmux_dealloc(PORT_B, 0, 15);
+               ret |= __crisv32_pinmux_dealloc(PORT_D, 8, 15);
                hwprot.ata = regk_pinmux_no;
                break;
        case pinmux_eth1:
-               ret = crisv32_pinmux_dealloc(PORT_E, 0, 17);
+               ret = __crisv32_pinmux_dealloc(PORT_E, 0, 17);
                hwprot.eth1 = regk_pinmux_no;
                hwprot.eth1_mgm = regk_pinmux_no;
                break;
        case pinmux_timer:
-               ret = crisv32_pinmux_dealloc(PORT_C, 16, 16);
+               ret = __crisv32_pinmux_dealloc(PORT_C, 16, 16);
                hwprot.timer = regk_pinmux_no;
                spin_unlock_irqrestore(&pinmux_lock, flags);
                return ret;
@@ -293,7 +306,8 @@ int crisv32_pinmux_dealloc_fixed(enum fixed_function function)
        return ret;
 }
 
-void crisv32_pinmux_dump(void)
+#ifdef DEBUG
+static void crisv32_pinmux_dump(void)
 {
        int i, j;
 
@@ -305,5 +319,5 @@ void crisv32_pinmux_dump(void)
                        printk(KERN_DEBUG "  Pin %d = %d\n", j, pins[i][j]);
        }
 }
-
+#endif
 __initcall(crisv32_pinmux_init);
index c2b3036779df5ad3b52e7d24b2c228398da3dc8e..09bf0c90d2d3d59ee924003ce963cc10d9b07328 100644 (file)
@@ -28,11 +28,9 @@ enum fixed_function {
   pinmux_timer
 };
 
-int crisv32_pinmux_init(void);
 int crisv32_pinmux_alloc(int port, int first_pin, int last_pin, enum pin_mode);
 int crisv32_pinmux_alloc_fixed(enum fixed_function function);
 int crisv32_pinmux_dealloc(int port, int first_pin, int last_pin);
 int crisv32_pinmux_dealloc_fixed(enum fixed_function function);
-void crisv32_pinmux_dump(void);
 
 #endif