Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 18 Nov 2014 01:38:40 +0000 (UTC)
From:      Luiz Otavio O Souza <loos@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r274638 - head/sys/dev/gpio
Message-ID:  <201411180138.sAI1ceUv003900@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: loos
Date: Tue Nov 18 01:38:39 2014
New Revision: 274638
URL: https://svnweb.freebsd.org/changeset/base/274638

Log:
  Add basic interrupt management code to gpiobus and ofw_gpiobus.
  
  This is the general support to allow the use of GPIO pins as interrupt
  sources for direct gpiobus children.
  
  The use of GPIO pins as generic interrupt sources (for an ethernet driver
  for example) will only be possible when arm/intrng is complete.  Then, most
  of this code will need to be rewritten, but it works for now, is better
  than what we have and will allow further developments.
  
  Tested on:	ar71xx (RSPRO), am335x (BBB), bcm2835 (Raspberry pi)
  Differential Revision:	https://reviews.freebsd.org/D999
  Reviewed by:	rpaulo

Modified:
  head/sys/dev/gpio/gpiobus.c
  head/sys/dev/gpio/gpiobusvar.h
  head/sys/dev/gpio/ofw_gpiobus.c

Modified: head/sys/dev/gpio/gpiobus.c
==============================================================================
--- head/sys/dev/gpio/gpiobus.c	Mon Nov 17 22:22:16 2014	(r274637)
+++ head/sys/dev/gpio/gpiobus.c	Tue Nov 18 01:38:39 2014	(r274638)
@@ -38,6 +38,13 @@ __FBSDID("$FreeBSD$");
 
 #include "gpiobus_if.h"
 
+#undef GPIOBUS_DEBUG
+#ifdef GPIOBUS_DEBUG
+#define	dprintf printf
+#else
+#define	dprintf(x, arg...)
+#endif
+
 static int gpiobus_parse_pins(struct gpiobus_softc *, device_t, int);
 static int gpiobus_probe(device_t);
 static int gpiobus_attach(device_t);
@@ -105,6 +112,11 @@ gpiobus_init_softc(device_t dev)
 	sc = GPIOBUS_SOFTC(dev);
 	sc->sc_busdev = dev;
 	sc->sc_dev = device_get_parent(dev);
+	sc->sc_intr_rman.rm_type = RMAN_ARRAY;
+	sc->sc_intr_rman.rm_descr = "GPIO Interrupts";
+	if (rman_init(&sc->sc_intr_rman) != 0 ||
+	    rman_manage_region(&sc->sc_intr_rman, 0, ~0) != 0)
+		panic("%s: failed to set up rman.", __func__);
 
 	if (GPIO_PIN_MAX(sc->sc_dev, &sc->sc_npins) != 0)
 		return (ENXIO);
@@ -267,6 +279,7 @@ gpiobus_print_child(device_t dev, device
 	retval += bus_print_child_header(dev, child);
 	retval += printf(" at pin(s) ");
 	gpiobus_print_pins(devi);
+	resource_list_print_type(&devi->rl, "irq", SYS_RES_IRQ, "%ld");
 	retval += bus_print_child_footer(dev, child);
 
 	return (retval);
@@ -304,7 +317,9 @@ gpiobus_add_child(device_t dev, u_int or
 		device_delete_child(dev, child);
 		return (0);
 	}
+	resource_list_init(&devi->rl);
 	device_set_ivars(child, devi);
+
 	return (child);
 }
 
@@ -314,14 +329,103 @@ gpiobus_hinted_child(device_t bus, const
 	struct gpiobus_softc *sc = GPIOBUS_SOFTC(bus);
 	struct gpiobus_ivar *devi;
 	device_t child;
-	int pins;
-
+	int irq, pins;
 
 	child = BUS_ADD_CHILD(bus, 0, dname, dunit);
 	devi = GPIOBUS_IVAR(child);
 	resource_int_value(dname, dunit, "pins", &pins);
 	if (gpiobus_parse_pins(sc, child, pins))
 		device_delete_child(bus, child);
+	if (resource_int_value(dname, dunit, "irq", &irq) == 0) {
+		if (bus_set_resource(child, SYS_RES_IRQ, 0, irq, 1) != 0)
+			device_printf(bus,
+			    "warning: bus_set_resource() failed\n");
+	}
+}
+
+static int
+gpiobus_set_resource(device_t dev, device_t child, int type, int rid,
+    u_long start, u_long count)
+{
+	struct gpiobus_ivar *devi;
+	struct resource_list_entry *rle;
+
+	dprintf("%s: entry (%p, %p, %d, %d, %p, %ld)\n",
+	    __func__, dev, child, type, rid, (void *)(intptr_t)start, count);
+	devi = GPIOBUS_IVAR(child);
+	rle = resource_list_add(&devi->rl, type, rid, start,
+	    start + count - 1, count);
+	if (rle == NULL)
+		return (ENXIO);
+
+	return (0);
+}
+
+static struct resource *
+gpiobus_alloc_resource(device_t bus, device_t child, int type, int *rid,
+    u_long start, u_long end, u_long count, u_int flags)
+{
+	struct gpiobus_softc *sc;
+	struct resource *rv;
+	struct resource_list *rl;
+	struct resource_list_entry *rle;
+	int isdefault;
+
+	if (type != SYS_RES_IRQ)
+		return (NULL);
+	isdefault = (start == 0UL && end == ~0UL && count == 1);
+	rle = NULL;
+	if (isdefault) {
+		rl = BUS_GET_RESOURCE_LIST(bus, child);
+		if (rl == NULL)
+			return (NULL);
+		rle = resource_list_find(rl, type, *rid);
+		if (rle == NULL)
+			return (NULL);
+		if (rle->res != NULL)
+			panic("%s: resource entry is busy", __func__);
+		start = rle->start;
+		count = rle->count;
+		end = rle->end;
+	}
+	sc = device_get_softc(bus);
+	rv = rman_reserve_resource(&sc->sc_intr_rman, start, end, count, flags,
+	    child);
+	if (rv == NULL)
+		return (NULL);
+	rman_set_rid(rv, *rid);
+	if ((flags & RF_ACTIVE) != 0 &&
+	    bus_activate_resource(child, type, *rid, rv) != 0) {
+		rman_release_resource(rv);
+		return (NULL);
+	}
+
+	return (rv);
+}
+
+static int
+gpiobus_release_resource(device_t bus __unused, device_t child, int type,
+    int rid, struct resource *r)
+{
+	int error;
+
+	if (rman_get_flags(r) & RF_ACTIVE) {
+		error = bus_deactivate_resource(child, type, rid, r);
+		if (error)
+			return (error);
+	}
+
+	return (rman_release_resource(r));
+}
+
+static struct resource_list *
+gpiobus_get_resource_list(device_t bus __unused, device_t child)
+{
+	struct gpiobus_ivar *ivar;
+
+	ivar = GPIOBUS_IVAR(child);
+
+	return (&ivar->rl);
 }
 
 static int
@@ -450,6 +554,15 @@ static device_method_t gpiobus_methods[]
 	DEVMETHOD(device_resume,	gpiobus_resume),
 
 	/* Bus interface */
+	DEVMETHOD(bus_setup_intr,	bus_generic_setup_intr),
+	DEVMETHOD(bus_config_intr,	bus_generic_config_intr),
+	DEVMETHOD(bus_teardown_intr,	bus_generic_teardown_intr),
+	DEVMETHOD(bus_set_resource,	gpiobus_set_resource),
+	DEVMETHOD(bus_alloc_resource,	gpiobus_alloc_resource),
+	DEVMETHOD(bus_release_resource,	gpiobus_release_resource),
+	DEVMETHOD(bus_activate_resource,	bus_generic_activate_resource),
+	DEVMETHOD(bus_deactivate_resource,	bus_generic_deactivate_resource),
+	DEVMETHOD(bus_get_resource_list,	gpiobus_get_resource_list),
 	DEVMETHOD(bus_add_child,	gpiobus_add_child),
 	DEVMETHOD(bus_print_child,	gpiobus_print_child),
 	DEVMETHOD(bus_child_pnpinfo_str, gpiobus_child_pnpinfo_str),

Modified: head/sys/dev/gpio/gpiobusvar.h
==============================================================================
--- head/sys/dev/gpio/gpiobusvar.h	Mon Nov 17 22:22:16 2014	(r274637)
+++ head/sys/dev/gpio/gpiobusvar.h	Tue Nov 18 01:38:39 2014	(r274638)
@@ -34,6 +34,7 @@
 
 #include <sys/lock.h>
 #include <sys/mutex.h>
+#include <sys/rman.h>
 
 #ifdef FDT
 #include <dev/ofw/ofw_bus_subr.h>
@@ -62,6 +63,7 @@
 struct gpiobus_softc
 {
 	struct mtx	sc_mtx;		/* bus mutex */
+	struct rman	sc_intr_rman;	/* isr resources */
 	device_t	sc_busdev;	/* bus device */
 	device_t	sc_owner;	/* bus owner */
 	device_t	sc_dev;		/* driver device */
@@ -71,6 +73,7 @@ struct gpiobus_softc
 
 struct gpiobus_ivar
 {
+	struct resource_list	rl;	/* isr resource list */
 	uint32_t	npins;	/* pins total */
 	uint32_t	*flags;	/* pins flags */
 	uint32_t	*pins;	/* pins map */

Modified: head/sys/dev/gpio/ofw_gpiobus.c
==============================================================================
--- head/sys/dev/gpio/ofw_gpiobus.c	Mon Nov 17 22:22:16 2014	(r274637)
+++ head/sys/dev/gpio/ofw_gpiobus.c	Tue Nov 18 01:38:39 2014	(r274638)
@@ -238,6 +238,13 @@ ofw_gpiobus_setup_devinfo(device_t dev, 
 		free(dinfo, M_DEVBUF);
 		return (NULL);
 	}
+	/* And now the interrupt resources. */
+	resource_list_init(&dinfo->opd_dinfo.rl);
+	if (ofw_bus_intr_to_rl(dev, node, &dinfo->opd_dinfo.rl) != 0) {
+		ofw_bus_gen_destroy_devinfo(&dinfo->opd_obdinfo);
+		free(dinfo, M_DEVBUF);
+		return (NULL);
+	}
 
 	return (dinfo);
 }
@@ -246,6 +253,7 @@ static void
 ofw_gpiobus_destroy_devinfo(struct ofw_gpiobus_devinfo *dinfo)
 {
 
+	resource_list_free(&dinfo->opd_dinfo.rl);
 	ofw_bus_gen_destroy_devinfo(&dinfo->opd_obdinfo);
 	free(dinfo, M_DEVBUF);
 }
@@ -326,6 +334,8 @@ ofw_gpiobus_print_child(device_t dev, de
 	retval += bus_print_child_header(dev, child);
 	retval += printf(" at pin(s) ");
 	gpiobus_print_pins(&devi->opd_dinfo);
+	resource_list_print_type(&devi->opd_dinfo.rl, "irq", SYS_RES_IRQ,
+	    "%ld");
 	retval += bus_print_child_footer(dev, child);
 
 	return (retval);



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