bcma: add locking around GPIO register accesses
authorHauke Mehrtens <hauke@hauke-m.de>
Tue, 20 Nov 2012 22:24:27 +0000 (22:24 +0000)
committerJohn Crispin <blogic@openwrt.org>
Wed, 21 Nov 2012 20:55:51 +0000 (21:55 +0100)
The GPIOs are access through some registers in the chip common core.
We need locking around these GPIO accesses, all GPIOs are accessed
through the same registers and parallel writes will cause problems.

Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
Patchwork: http://patchwork.linux-mips.org/patch/4585
Acked-by: Florian Fainelli <florian@openwrt.org>
drivers/bcma/driver_chipcommon.c
include/linux/bcma/bcma_driver_chipcommon.h

index a4c3ebcc4c8609de39d7331d23b24bd830ac77cf..c9b63d9ff61d7af88e85832ade0c76990f51441a 100644 (file)
@@ -30,6 +30,8 @@ void bcma_core_chipcommon_init(struct bcma_drv_cc *cc)
        if (cc->setup_done)
                return;
 
+       spin_lock_init(&cc->gpio_lock);
+
        if (cc->core->id.rev >= 11)
                cc->status = bcma_cc_read32(cc, BCMA_CC_CHIPSTAT);
        cc->capabilities = bcma_cc_read32(cc, BCMA_CC_CAP);
@@ -84,28 +86,63 @@ u32 bcma_chipco_gpio_in(struct bcma_drv_cc *cc, u32 mask)
 
 u32 bcma_chipco_gpio_out(struct bcma_drv_cc *cc, u32 mask, u32 value)
 {
-       return bcma_cc_write32_masked(cc, BCMA_CC_GPIOOUT, mask, value);
+       unsigned long flags;
+       u32 res;
+
+       spin_lock_irqsave(&cc->gpio_lock, flags);
+       res = bcma_cc_write32_masked(cc, BCMA_CC_GPIOOUT, mask, value);
+       spin_unlock_irqrestore(&cc->gpio_lock, flags);
+
+       return res;
 }
 
 u32 bcma_chipco_gpio_outen(struct bcma_drv_cc *cc, u32 mask, u32 value)
 {
-       return bcma_cc_write32_masked(cc, BCMA_CC_GPIOOUTEN, mask, value);
+       unsigned long flags;
+       u32 res;
+
+       spin_lock_irqsave(&cc->gpio_lock, flags);
+       res = bcma_cc_write32_masked(cc, BCMA_CC_GPIOOUTEN, mask, value);
+       spin_unlock_irqrestore(&cc->gpio_lock, flags);
+
+       return res;
 }
 
 u32 bcma_chipco_gpio_control(struct bcma_drv_cc *cc, u32 mask, u32 value)
 {
-       return bcma_cc_write32_masked(cc, BCMA_CC_GPIOCTL, mask, value);
+       unsigned long flags;
+       u32 res;
+
+       spin_lock_irqsave(&cc->gpio_lock, flags);
+       res = bcma_cc_write32_masked(cc, BCMA_CC_GPIOCTL, mask, value);
+       spin_unlock_irqrestore(&cc->gpio_lock, flags);
+
+       return res;
 }
 EXPORT_SYMBOL_GPL(bcma_chipco_gpio_control);
 
 u32 bcma_chipco_gpio_intmask(struct bcma_drv_cc *cc, u32 mask, u32 value)
 {
-       return bcma_cc_write32_masked(cc, BCMA_CC_GPIOIRQ, mask, value);
+       unsigned long flags;
+       u32 res;
+
+       spin_lock_irqsave(&cc->gpio_lock, flags);
+       res = bcma_cc_write32_masked(cc, BCMA_CC_GPIOIRQ, mask, value);
+       spin_unlock_irqrestore(&cc->gpio_lock, flags);
+
+       return res;
 }
 
 u32 bcma_chipco_gpio_polarity(struct bcma_drv_cc *cc, u32 mask, u32 value)
 {
-       return bcma_cc_write32_masked(cc, BCMA_CC_GPIOPOL, mask, value);
+       unsigned long flags;
+       u32 res;
+
+       spin_lock_irqsave(&cc->gpio_lock, flags);
+       res = bcma_cc_write32_masked(cc, BCMA_CC_GPIOPOL, mask, value);
+       spin_unlock_irqrestore(&cc->gpio_lock, flags);
+
+       return res;
 }
 
 #ifdef CONFIG_BCMA_DRIVER_MIPS
index 1cf1749440ac66dabd8b0f797e80690bbde9961d..a085d986c804c7f15e8b2c8db13fd75e2167d109 100644 (file)
@@ -567,6 +567,9 @@ struct bcma_drv_cc {
        int nr_serial_ports;
        struct bcma_serial_port serial_ports[4];
 #endif /* CONFIG_BCMA_DRIVER_MIPS */
+
+       /* Lock for GPIO register access. */
+       spinlock_t gpio_lock;
 };
 
 /* Register access */