Author: manu
Date: Sat Sep 16 14:08:20 2017
New Revision: 323639
URL: https://svnweb.freebsd.org/changeset/base/323639

Log:
  Allwinner: a10_gpio Fix panic on multiple lock
  
  r323392 introduce gpio_pin_get/gpio_pin_set for a10_gpio driver.
  When called via gpio method they must aquire the device lock while
  when they are called via gpio_pin_configure the lock is already aquire.
  
  Introduce a10_gpio_pin_{s,g}et_locked and call them in pin_gpio_configure
  instead.
  
  Tested On: BananaPi (A20)
  
  Reported by:  Richard Puga rich...@puga.net

Modified:
  head/sys/arm/allwinner/a10_gpio.c

Modified: head/sys/arm/allwinner/a10_gpio.c
==============================================================================
--- head/sys/arm/allwinner/a10_gpio.c   Sat Sep 16 13:49:26 2017        
(r323638)
+++ head/sys/arm/allwinner/a10_gpio.c   Sat Sep 16 14:08:20 2017        
(r323639)
@@ -197,6 +197,8 @@ struct a10_gpio_softc {
 
 static int a10_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *value);
 static int a10_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value);
+static int a10_gpio_pin_get_locked(struct a10_gpio_softc *sc, uint32_t pin, 
unsigned int *value);
+static int a10_gpio_pin_set_locked(struct a10_gpio_softc *sc, uint32_t pin, 
unsigned int value);
 
 #define        A10_GPIO_WRITE(_sc, _off, _val)         \
     bus_space_write_4(_sc->sc_bst, _sc->sc_bsh, _off, _val)
@@ -333,15 +335,15 @@ a10_gpio_pin_configure(struct a10_gpio_softc *sc, uint
                err = a10_gpio_set_function(sc, pin, A10_GPIO_INPUT);
        } else if (flags & GPIO_PIN_OUTPUT) {
                if (flags & GPIO_PIN_PRESET_LOW) {
-                       a10_gpio_pin_set(sc->sc_dev, pin, 0);
+                       a10_gpio_pin_set_locked(sc, pin, 0);
                } else if (flags & GPIO_PIN_PRESET_HIGH) {
-                       a10_gpio_pin_set(sc->sc_dev, pin, 1);
+                       a10_gpio_pin_set_locked(sc, pin, 1);
                } else {
                        /* Read the pin and preset output to current state. */
                        err = a10_gpio_set_function(sc, pin, A10_GPIO_INPUT);
                        if (err == 0) {
-                               a10_gpio_pin_get(sc->sc_dev, pin, &val);
-                               a10_gpio_pin_set(sc->sc_dev, pin, val); 
+                               a10_gpio_pin_get_locked(sc, pin, &val);
+                               a10_gpio_pin_set_locked(sc, pin, val);
                        }
                }
                if (err == 0)
@@ -473,49 +475,77 @@ a10_gpio_pin_setflags(device_t dev, uint32_t pin, uint
 }
 
 static int
-a10_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value)
+a10_gpio_pin_set_locked(struct a10_gpio_softc *sc, uint32_t pin,
+    unsigned int value)
 {
-       struct a10_gpio_softc *sc;
        uint32_t bank, data;
 
-       sc = device_get_softc(dev);
+       A10_GPIO_LOCK_ASSERT(sc);
+
        if (pin > sc->padconf->npins)
                return (EINVAL);
 
        bank = sc->padconf->pins[pin].port;
        pin = sc->padconf->pins[pin].pin;
 
-       A10_GPIO_LOCK(sc);
        data = A10_GPIO_READ(sc, A10_GPIO_GP_DAT(bank));
        if (value)
                data |= (1 << pin);
        else
                data &= ~(1 << pin);
        A10_GPIO_WRITE(sc, A10_GPIO_GP_DAT(bank), data);
-       A10_GPIO_UNLOCK(sc);
 
        return (0);
 }
 
 static int
-a10_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val)
+a10_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value)
 {
        struct a10_gpio_softc *sc;
-       uint32_t bank, reg_data;
+       int ret;
 
        sc = device_get_softc(dev);
+
+       A10_GPIO_LOCK(sc);
+       ret = a10_gpio_pin_set_locked(sc, pin, value);
+       A10_GPIO_UNLOCK(sc);
+
+       return (ret);
+}
+
+static int
+a10_gpio_pin_get_locked(struct a10_gpio_softc *sc,uint32_t pin,
+    unsigned int *val)
+{
+       uint32_t bank, reg_data;
+
+       A10_GPIO_LOCK_ASSERT(sc);
+
        if (pin > sc->padconf->npins)
                return (EINVAL);
 
        bank = sc->padconf->pins[pin].port;
        pin = sc->padconf->pins[pin].pin;
 
-       A10_GPIO_LOCK(sc);
        reg_data = A10_GPIO_READ(sc, A10_GPIO_GP_DAT(bank));
-       A10_GPIO_UNLOCK(sc);
        *val = (reg_data & (1 << pin)) ? 1 : 0;
 
        return (0);
+}
+
+static int
+a10_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val)
+{
+       struct a10_gpio_softc *sc;
+       int ret;
+
+       sc = device_get_softc(dev);
+
+       A10_GPIO_LOCK(sc);
+       ret = a10_gpio_pin_get_locked(sc, pin, val);
+       A10_GPIO_UNLOCK(sc);
+
+       return (ret);
 }
 
 static int
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to