Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 16 Sep 2017 14:08:20 +0000 (UTC)
From:      Emmanuel Vadot <manu@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r323639 - head/sys/arm/allwinner
Message-ID:  <201709161408.v8GE8KEX090093@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
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 richard@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



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201709161408.v8GE8KEX090093>