Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 22 Mar 2013 03:25:33 GMT
From:      Brooks Davis <brooks@FreeBSD.org>
To:        Perforce Change Reviews <perforce@FreeBSD.org>
Subject:   PERFORCE change 223121 for review
Message-ID:  <201303220325.r2M3PX8C014234@skunkworks.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://p4web.freebsd.org/@@223121?ac=10

Change 223121 by brooks@brooks_zenith on 2013/03/22 03:24:48

	Implement a driver for Robert Norton's PIC as an FDT
	interrupt controller.  Devices whose interrupt-parent property
	points to a beripic device (or any other interrupt controller
	that registers as an FDT IC) will have their interrupt allocation,
	activation, and setup operations routed through the IC rather
	than down the traditional bus hierarchy.
	
	This driver largely abstracts the underlying CPU away allowing
	the PIC to be implemented on CPU's other than BERI.  Due to
	insufficent abstractions in the FreeBSD codebase a small amount
	of MIPS specific code is currently required in fdt_mips.c and
	implementing counters properly will likely require a bit more
	MIPS specific code.
	
	TODO:
	 * implement filters for each source.
	 * add per-source counters.
	 * SMP support.

Affected files ...

.. //depot/projects/ctsrd/beribsd/src/sys/boot/fdt/dts/beripad-de4.dts#19 edit
.. //depot/projects/ctsrd/beribsd/src/sys/conf/files#16 edit
.. //depot/projects/ctsrd/beribsd/src/sys/dev/fdt/fdt_common.c#7 edit
.. //depot/projects/ctsrd/beribsd/src/sys/dev/fdt/fdt_common.h#6 edit
.. //depot/projects/ctsrd/beribsd/src/sys/dev/fdt/fdt_ic_if.m#1 add
.. //depot/projects/ctsrd/beribsd/src/sys/dev/fdt/fdt_mips.c#5 edit
.. //depot/projects/ctsrd/beribsd/src/sys/dev/fdt/simplebus.c#4 edit
.. //depot/projects/ctsrd/beribsd/src/sys/mips/beri/beri_pic.c#1 add
.. //depot/projects/ctsrd/beribsd/src/sys/mips/beri/files.beri#31 edit

Differences ...

==== //depot/projects/ctsrd/beribsd/src/sys/boot/fdt/dts/beripad-de4.dts#19 (text+ko) ====

@@ -48,6 +48,9 @@
 	#size-cells = <1>;
 
 	cpus {
+		#address-cells = <1>;
+		#size-cells = <1>;
+
 		cpu@0 {
 			compatible = "sri-cambridge,beri";
 		};
@@ -70,6 +73,24 @@
 			reg = <0x0 0x40000000>;		// 1G at 0x0
 		};
 
+		beripic: beripic@7f804000 {
+			compatible = "sri-cambridge,beri-pic";
+			interrupt-controller;
+			#address-cells = <0>;
+			#interrupt-cells = <1>;
+			reg =  <0x7f804000 0x400
+				0x7f806000 0x10
+				0x7f806080 0x10
+				0x7f806100 0x10>;
+			interrupts = <0 1 2 3 4>;
+			hard-interrupt-sources = <64>;
+			soft-interrupt-sources = <64>;
+			/*
+			 * Ideally we'd have phandle to our core here so we
+			 * can query things like nthreads.
+			 */
+		}
+
 		serial@7f000000 {
 			compatible = "altera,jtag_uart-11_0";
 			reg = <0x7f000000 0x40>;
@@ -147,6 +168,7 @@
 				0x7f007420 0x20>;
 			/* RX, TX */
 			interrupts = <1 2>;
+			//interrupt-parent =<&beripic>;
 		};
 
 		ethernet@7f005000 {

==== //depot/projects/ctsrd/beribsd/src/sys/conf/files#16 (text+ko) ====

@@ -1293,6 +1293,7 @@
 dev/fatm/if_fatm.c		optional fatm pci
 dev/fb/splash.c			optional splash
 dev/fdt/fdt_common.c		optional fdt
+dev/fdt/fdt_ic_if.m		optional fdt
 dev/fdt/fdt_pci.c		optional fdt pci
 dev/fdt/fdt_slicer.c		optional fdt cfi | fdt nand
 dev/fdt/fdt_static_dtb.S	optional fdt fdt_dtb_static

==== //depot/projects/ctsrd/beribsd/src/sys/dev/fdt/fdt_common.c#7 (text+ko) ====

@@ -63,6 +63,8 @@
 vm_offset_t fdt_immr_va;
 vm_offset_t fdt_immr_size;
 
+struct fdt_ic_list fdt_ic_list_head = SLIST_HEAD_INITIALIZER(fdt_ic_list_head);
+
 int
 fdt_get_range(phandle_t node, int range_id, u_long *base, u_long *size)
 {

==== //depot/projects/ctsrd/beribsd/src/sys/dev/fdt/fdt_common.h#6 (text+ko) ====

@@ -70,6 +70,13 @@
 };
 extern struct fdt_fixup_entry fdt_fixup_table[];
 
+extern SLIST_HEAD(fdt_ic_list, fdt_ic) fdt_ic_list_head;
+struct fdt_ic {
+	SLIST_ENTRY(fdt_ic)	fdt_ics;
+	ihandle_t		iph;
+	device_t		dev;
+};
+
 extern vm_paddr_t fdt_immr_pa;
 extern vm_offset_t fdt_immr_va;
 extern vm_offset_t fdt_immr_size;

==== //depot/projects/ctsrd/beribsd/src/sys/dev/fdt/fdt_mips.c#5 (text+ko) ====

@@ -68,7 +68,26 @@
 	return (0);
 }
 
+/*
+ * CHERI PIC decoder.
+ */
+static int
+fdt_pic_decode_beri(phandle_t node, pcell_t *intr, int *interrupt,
+    int *trig, int *pol)
+{
+
+	if (!fdt_is_compatible(node, "sri-cambridge,beri-pic"))
+		return (ENXIO);
+
+	*interrupt = fdt32_to_cpu(intr[0]);
+	*trig = INTR_TRIGGER_CONFORM;
+	*pol = INTR_POLARITY_CONFORM;
+
+	return (0);
+}
+
 fdt_pic_decode_t fdt_pic_table[] = {
 	&fdt_pic_decode_mips4k_cp0,
+	&fdt_pic_decode_beri,
 	NULL
 };

==== //depot/projects/ctsrd/beribsd/src/sys/dev/fdt/simplebus.c#4 (text+ko) ====

@@ -47,6 +47,7 @@
 #include <dev/ofw/openfirm.h>
 
 #include "fdt_common.h"
+#include "fdt_ic_if.h"
 #include "ofw_bus_if.h"
 
 #ifdef DEBUG
@@ -80,9 +81,18 @@
 static int simplebus_print_child(device_t, device_t);
 static int simplebus_setup_intr(device_t, device_t, struct resource *, int,
     driver_filter_t *, driver_intr_t *, void *, void **);
+static int simplebus_teardown_intr(device_t, device_t, struct resource *,
+    void *);
 
+static int simplebus_activate_resource(device_t, device_t, int, int,
+    struct resource *);
 static struct resource *simplebus_alloc_resource(device_t, device_t, int,
     int *, u_long, u_long, u_long, u_int);
+static int simplebus_deactivate_resource(device_t, device_t, int, int,
+    struct resource *);
+static int simplebus_release_resource(device_t, device_t, int, int,
+    struct resource *);
+static device_t simplebus_get_interrupt_parent(device_t);
 static struct resource_list *simplebus_get_resource_list(device_t, device_t);
 
 static ofw_bus_get_devinfo_t simplebus_get_devinfo;
@@ -102,11 +112,11 @@
 	/* Bus interface */
 	DEVMETHOD(bus_print_child,	simplebus_print_child),
 	DEVMETHOD(bus_alloc_resource,	simplebus_alloc_resource),
-	DEVMETHOD(bus_release_resource,	bus_generic_release_resource),
-	DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
-	DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
+	DEVMETHOD(bus_release_resource,	simplebus_release_resource),
+	DEVMETHOD(bus_activate_resource, simplebus_activate_resource),
+	DEVMETHOD(bus_deactivate_resource, simplebus_deactivate_resource),
 	DEVMETHOD(bus_setup_intr,	simplebus_setup_intr),
-	DEVMETHOD(bus_teardown_intr,	bus_generic_teardown_intr),
+	DEVMETHOD(bus_teardown_intr,	simplebus_teardown_intr),
 	DEVMETHOD(bus_get_resource_list, simplebus_get_resource_list),
 
 	/* OFW bus interface */
@@ -238,6 +248,7 @@
 simplebus_alloc_resource(device_t bus, device_t child, int type, int *rid,
     u_long start, u_long end, u_long count, u_int flags)
 {
+	device_t ic;
 	struct simplebus_devinfo *di;
 	struct resource_list_entry *rle;
 
@@ -263,10 +274,53 @@
 		count = rle->count;
 	}
 
+	if (type == SYS_RES_IRQ &&
+	    (ic = simplebus_get_interrupt_parent(child)) != NULL)
+		return(FDT_IC_ALLOC_INTR(ic, child, rid, start, flags));
+
 	return (bus_generic_alloc_resource(bus, child, type, rid, start, end,
 	    count, flags));
 }
 
+static int
+simplebus_activate_resource(device_t dev, device_t child, int type, int rid,
+    struct resource *r)
+{
+	device_t ic;
+
+	if (type == SYS_RES_IRQ &&
+	    (ic = simplebus_get_interrupt_parent(child)) != NULL)
+		return (FDT_IC_ACTIVATE_INTR(ic, r));
+
+	return (bus_generic_activate_resource(dev, child, type, rid, r));
+}
+
+static int
+simplebus_deactivate_resource(device_t dev, device_t child, int type, int rid,
+    struct resource *r)
+{
+	device_t ic;
+
+	if (type == SYS_RES_IRQ &&
+	    (ic = simplebus_get_interrupt_parent(child)) != NULL)
+		return (FDT_IC_DEACTIVATE_INTR(ic, r));
+
+	return (bus_generic_deactivate_resource(dev, child, type, rid, r));
+}
+
+static int
+simplebus_release_resource(device_t dev, device_t child, int type, int rid,
+    struct resource *r)
+{
+	device_t ic;
+
+	if (type == SYS_RES_IRQ &&
+	    (ic = simplebus_get_interrupt_parent(child)) != NULL)
+		return (FDT_IC_RELEASE_INTR(ic, r));
+
+	return (bus_generic_release_resource(dev, child, type, rid, r));
+}
+
 static struct resource_list *
 simplebus_get_resource_list(device_t bus, device_t child)
 {
@@ -276,15 +330,40 @@
 	return (&di->di_res);
 }
 
+static device_t
+simplebus_get_interrupt_parent(device_t dev)
+{
+	struct simplebus_devinfo *di;
+	struct fdt_ic *ic;
+	ihandle_t iph;
+	phandle_t ph;
+
+	di = device_get_ivars(dev);
+	if (di == NULL)
+		return (NULL);
+
+	if (OF_getprop(di->di_ofw.obd_node, "interrupt-parent", &iph,
+	    sizeof(iph)) > 0) {
+		iph = fdt32_to_cpu(iph);
+		ph = OF_instance_to_package(iph);
+		SLIST_FOREACH(ic, &fdt_ic_list_head, fdt_ics) {
+			if (ic->iph == ph)
+				return (ic->dev);
+		}
+	}
+	return (NULL);
+}
+
 static int
 simplebus_setup_intr(device_t bus, device_t child, struct resource *res,
     int flags, driver_filter_t *filter, driver_intr_t *ihand, void *arg,
     void **cookiep)
 {
 	struct simplebus_devinfo *di;
+	device_t ic;
 	enum intr_trigger trig;
 	enum intr_polarity pol;
-	int error, rid;
+	int error, irq, rid;
 
 	if (device_get_parent(child) != bus)
 		return (ECHILD);
@@ -300,20 +379,41 @@
 	if (rid >= DI_MAX_INTR_NUM)
 		return (ENOENT);
 
+	ic = simplebus_get_interrupt_parent(child);
+
 	trig = di->di_intr_sl[rid].trig;
 	pol = di->di_intr_sl[rid].pol;
 	if (trig != INTR_TRIGGER_CONFORM || pol != INTR_POLARITY_CONFORM) {
-		error = bus_generic_config_intr(bus, rman_get_start(res),
-		    trig, pol);
+		irq = rman_get_start(res);
+		if (ic != NULL)
+			error = FDT_IC_CONFIG_INTR(ic, irq, trig, pol);
+		else
+			error = bus_generic_config_intr(bus, irq, trig, pol);
 		if (error)
 			return (error);
 	}
 
-	error = bus_generic_setup_intr(bus, child, res, flags, filter, ihand,
-	    arg, cookiep);
+	if (ic != NULL)
+		error = FDT_IC_SETUP_INTR(ic, child, res, flags, filter,
+		    ihand, arg, cookiep);
+	else
+		error = bus_generic_setup_intr(bus, child, res, flags, filter,
+		    ihand, arg, cookiep);
 	return (error);
 }
 
+static int
+simplebus_teardown_intr(device_t bus, device_t child, struct resource *res,
+    void *cookie)
+{
+	device_t ic;
+
+	if ((ic = simplebus_get_interrupt_parent(child)) != NULL)
+		return (FDT_IC_TEARDOWN_INTR(ic, child, res, cookie));
+
+	return (bus_generic_teardown_intr(bus, child, res, cookie));
+}
+
 static const struct ofw_bus_devinfo *
 simplebus_get_devinfo(device_t bus, device_t child)
 {

==== //depot/projects/ctsrd/beribsd/src/sys/mips/beri/files.beri#31 (text+ko) ====

@@ -19,5 +19,6 @@
 mips/beri/beri_asm.S			standard
 mips/beri/beri_machdep.c		standard
 mips/beri/beri_mp.c			optional smp
+mips/beri/beri_pic.c			optional fdt
 mips/mips/intr_machdep.c		standard
 mips/mips/tick.c			standard



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