Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 11 Aug 2014 16:44:06 +0000 (UTC)
From:      Jakub Wojciech Klama <jceel@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-projects@freebsd.org
Subject:   svn commit: r269817 - in projects/arm_intrng/sys: arm/arm arm/broadcom/bcm2835 arm/conf arm/include arm/lpc arm/ti arm/ti/omap4 boot/fdt/dts/arm conf dev/fdt
Message-ID:  <53e8f2d6.2f8f.71f433d6@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: jceel
Date: Mon Aug 11 16:44:06 2014
New Revision: 269817
URL: http://svnweb.freebsd.org/changeset/base/269817

Log:
  Initial version of refactored interrupt handling framework for
  FreeBSD ARM. Currently supports following interrupt controllers:
  * lpc_intc in lpc port
  * aintc in ti port
  * intc in bcm2835 port (Raspberry PI)
  * ARM GIC
  
  It's mainly based on 2012 Google Summer of Code project, adapted
  for current HEAD and with added SMP (IPI) support. It has been
  tested on LPC3250, Pandaboard and RPI (both with and without SMP
  support).
  
  Introduces hierarchical interrupt controllers in the system, allowing
  to easily utilize multiplexers such as GPIOs to serve as interrupt
  sources. nexus driver is a top-level interrupt controller, exposing
  single interruprt (IRQ) on ARM. The GIC or any other used interrupt
  controller setups handler on that interrupt, exposing new IRQs
  available for other peripherals. In an example SoC, interrupt
  hierarchy may look like that:
  
  nexus0 (1 interrupts)
  |
  \-- gic0 (160 interrupts, uses irq nexus0:0)
      |
      \-- gpio0 (8 interrupts, uses irq gic0:42)
      |   |
      |   \-- mmcsd0 (uses irqs gpio0:1, gpio0:2)
      |   \-- spi0 (uses irq gpio0:3)
      |   ...
      \-- gpio1 (8 interrupts, uses irq gic0:43)
      \-- ehci0 (uses irq gic0:109)
      ...
  
  That change should not break any existing ports in any way, except
  for need to add 'arm/arm/intr.c' to 'files.*' of existing ports,
  as it's no longer compiled-in by default.

Added:
  projects/arm_intrng/sys/arm/arm/intrng.c   (contents, props changed)
  projects/arm_intrng/sys/arm/arm/pic_if.m
Modified:
  projects/arm_intrng/sys/arm/arm/gic.c
  projects/arm_intrng/sys/arm/arm/intr.c
  projects/arm_intrng/sys/arm/arm/mp_machdep.c
  projects/arm_intrng/sys/arm/arm/nexus.c
  projects/arm_intrng/sys/arm/broadcom/bcm2835/bcm2835_intr.c
  projects/arm_intrng/sys/arm/broadcom/bcm2835/files.bcm2835
  projects/arm_intrng/sys/arm/conf/EA3250
  projects/arm_intrng/sys/arm/conf/PANDABOARD
  projects/arm_intrng/sys/arm/conf/RPI-B
  projects/arm_intrng/sys/arm/include/fdt.h
  projects/arm_intrng/sys/arm/include/intr.h
  projects/arm_intrng/sys/arm/include/smp.h
  projects/arm_intrng/sys/arm/lpc/files.lpc
  projects/arm_intrng/sys/arm/lpc/lpc_intc.c
  projects/arm_intrng/sys/arm/lpc/lpcreg.h
  projects/arm_intrng/sys/arm/ti/aintc.c
  projects/arm_intrng/sys/arm/ti/files.ti
  projects/arm_intrng/sys/arm/ti/omap4/omap4_mp.c
  projects/arm_intrng/sys/boot/fdt/dts/arm/bcm2835.dtsi
  projects/arm_intrng/sys/boot/fdt/dts/arm/ea3250.dts
  projects/arm_intrng/sys/boot/fdt/dts/arm/pandaboard.dts
  projects/arm_intrng/sys/conf/files.arm
  projects/arm_intrng/sys/conf/options.arm
  projects/arm_intrng/sys/dev/fdt/simplebus.c

Modified: projects/arm_intrng/sys/arm/arm/gic.c
==============================================================================
--- projects/arm_intrng/sys/arm/arm/gic.c	Mon Aug 11 16:31:28 2014	(r269816)
+++ projects/arm_intrng/sys/arm/arm/gic.c	Mon Aug 11 16:44:06 2014	(r269817)
@@ -55,6 +55,8 @@ __FBSDID("$FreeBSD$");
 #include <dev/ofw/ofw_bus.h>
 #include <dev/ofw/ofw_bus_subr.h>
 
+#include "pic_if.h"
+
 /* We are using GICv2 register naming */
 
 /* Distributor Registers */
@@ -95,42 +97,49 @@ __FBSDID("$FreeBSD$");
 #define GICD_ICFGR_TRIG_MASK	0x2
 
 struct arm_gic_softc {
+	device_t		gic_dev;
 	struct resource *	gic_res[3];
 	bus_space_tag_t		gic_c_bst;
 	bus_space_tag_t		gic_d_bst;
 	bus_space_handle_t	gic_c_bsh;
 	bus_space_handle_t	gic_d_bsh;
+	void *			gic_intrhand;
 	uint8_t			ver;
-	device_t		dev;
 	struct mtx		mutex;
 	uint32_t		nirqs;
 };
-
 static struct resource_spec arm_gic_spec[] = {
 	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },	/* Distributor registers */
 	{ SYS_RES_MEMORY,	1,	RF_ACTIVE },	/* CPU Interrupt Intf. registers */
+	{ SYS_RES_IRQ,		0,	RF_ACTIVE }, 	/* Parent interrupt */
 	{ -1, 0 }
 };
 
 static struct arm_gic_softc *arm_gic_sc = NULL;
 
-#define	gic_c_read_4(reg)		\
-    bus_space_read_4(arm_gic_sc->gic_c_bst, arm_gic_sc->gic_c_bsh, reg)
-#define	gic_c_write_4(reg, val)		\
-    bus_space_write_4(arm_gic_sc->gic_c_bst, arm_gic_sc->gic_c_bsh, reg, val)
-#define	gic_d_read_4(reg)		\
-    bus_space_read_4(arm_gic_sc->gic_d_bst, arm_gic_sc->gic_d_bsh, reg)
-#define	gic_d_write_4(reg, val)		\
-    bus_space_write_4(arm_gic_sc->gic_d_bst, arm_gic_sc->gic_d_bsh, reg, val)
-
-static int gic_config_irq(int irq, enum intr_trigger trig,
-    enum intr_polarity pol);
-static void gic_post_filter(void *);
+static int arm_gic_probe(device_t);
+static int arm_gic_attach(device_t);
+static void arm_gic_init_secondary(device_t);
+static int arm_gic_intr(void *);
+static int arm_gic_config(device_t, int, enum intr_trigger, enum intr_polarity);
+static void arm_gic_eoi(device_t, int);
+static void arm_gic_mask(device_t, int);
+static void arm_gic_unmask(device_t, int);
+static void arm_gic_ipi_send(device_t, cpuset_t, int);
+static void arm_gic_ipi_clear(device_t, int);
+
+#define	gic_c_read_4(_sc, _reg)		\
+    bus_space_read_4((_sc)->gic_c_bst, (_sc)->gic_c_bsh, (_reg))
+#define	gic_c_write_4(_sc, _reg, _val)		\
+    bus_space_write_4((_sc)->gic_c_bst, (_sc)->gic_c_bsh, (_reg), (_val))
+#define	gic_d_read_4(_sc, _reg)		\
+    bus_space_read_4((_sc)->gic_d_bst, (_sc)->gic_d_bsh, (_reg))
+#define	gic_d_write_4(_sc, _reg, _val)		\
+    bus_space_write_4((_sc)->gic_d_bst, (_sc)->gic_d_bsh, (_reg), (_val))
 
 static int
 arm_gic_probe(device_t dev)
 {
-
 	if (!ofw_bus_status_okay(dev))
 		return (ENXIO);
 
@@ -140,17 +149,13 @@ arm_gic_probe(device_t dev)
 	return (BUS_PROBE_DEFAULT);
 }
 
-void
-gic_init_secondary(void)
+static void
+arm_gic_init_secondary(device_t dev)
 {
-	int i, nirqs;
-
-  	/* Get the number of interrupts */
-	nirqs = gic_d_read_4(GICD_TYPER);
-	nirqs = 32 * ((nirqs & 0x1f) + 1);
-
-	for (i = 0; i < nirqs; i += 4)
-		gic_d_write_4(GICD_IPRIORITYR(i >> 2), 0);
+	struct arm_gic_softc *sc = device_get_softc(dev);
+	
+	for (int i = 0; i < sc->nirqs; i += 4)
+		gic_d_write_4(sc, GICD_IPRIORITYR(i >> 2), 0);
 
 	/* Set all the interrupts to be in Group 0 (secure) */
 	for (i = 0; i < nirqs; i += 32) {
@@ -158,14 +163,12 @@ gic_init_secondary(void)
 	}
 
 	/* Enable CPU interface */
-	gic_c_write_4(GICC_CTLR, 1);
-
-	/* Set priority mask register. */
-	gic_c_write_4(GICC_PMR, 0xff);
+	gic_c_write_4(sc, GICC_CTLR, 1);
 
 	/* Enable interrupt distribution */
-	gic_d_write_4(GICD_CTLR, 0x01);
-
+	gic_d_write_4(sc, GICD_CTLR, 0x01);
+		
+	/* Activate IRQ 29, ie private timer IRQ*/
 	/* Activate IRQ 29-30, ie private timer (secure & non-secure) IRQs */
 	gic_d_write_4(GICD_ISENABLER(29 >> 5), (1UL << (29 & 0x1F)));
 	gic_d_write_4(GICD_ISENABLER(30 >> 5), (1UL << (30 & 0x1F)));
@@ -174,21 +177,18 @@ gic_init_secondary(void)
 static int
 arm_gic_attach(device_t dev)
 {
-	struct		arm_gic_softc *sc;
+	struct		arm_gic_softc *sc = device_get_softc(dev);
 	int		i;
 	uint32_t	icciidr;
 
-	if (arm_gic_sc)
-		return (ENXIO);
-
-	sc = device_get_softc(dev);
-	sc->dev = dev;
-
 	if (bus_alloc_resources(dev, arm_gic_spec, sc->gic_res)) {
 		device_printf(dev, "could not allocate resources\n");
 		return (ENXIO);
 	}
 
+	sc->gic_dev = dev;
+	arm_gic_sc = sc;
+
 	/* Initialize mutex */
 	mtx_init(&sc->mutex, "GIC lock", "", MTX_SPIN);
 
@@ -200,32 +200,35 @@ arm_gic_attach(device_t dev)
 	sc->gic_c_bst = rman_get_bustag(sc->gic_res[1]);
 	sc->gic_c_bsh = rman_get_bushandle(sc->gic_res[1]);
 
-	arm_gic_sc = sc;
+	arm_register_pic(dev, PIC_FEATURE_IPI);
+
+	if (bus_setup_intr(dev, sc->gic_res[2], INTR_TYPE_MISC | INTR_CONTROLLER,
+	    arm_gic_intr, NULL, sc, &sc->gic_intrhand)) {
+		device_printf(dev, "could not setup interrupt handler\n");
+		bus_release_resources(dev, arm_gic_spec, sc->gic_res);
+		return (ENXIO);
+	}
 
 	/* Disable interrupt forwarding to the CPU interface */
-	gic_d_write_4(GICD_CTLR, 0x00);
+	gic_d_write_4(sc, GICD_CTLR, 0x00);
 
 	/* Get the number of interrupts */
-	sc->nirqs = gic_d_read_4(GICD_TYPER);
+	sc->nirqs = gic_d_read_4(sc, GICD_TYPER);
 	sc->nirqs = 32 * ((sc->nirqs & 0x1f) + 1);
 
-	/* Set up function pointers */
-	arm_post_filter = gic_post_filter;
-	arm_config_irq = gic_config_irq;
-
-	icciidr = gic_c_read_4(GICC_IIDR);
-	device_printf(dev,"pn 0x%x, arch 0x%x, rev 0x%x, implementer 0x%x sc->nirqs %u\n",
+	icciidr = gic_c_read_4(sc, GICC_IIDR);
+	device_printf(dev,"pn 0x%x, arch 0x%x, rev 0x%x, implementer 0x%x nirqs %u\n", 
 			icciidr>>20, (icciidr>>16) & 0xF, (icciidr>>12) & 0xf,
 			(icciidr & 0xfff), sc->nirqs);
 
 	/* Set all global interrupts to be level triggered, active low. */
 	for (i = 32; i < sc->nirqs; i += 16) {
-		gic_d_write_4(GICD_ICFGR(i >> 4), 0x00000000);
+		gic_d_write_4(sc, GICD_ICFGR(i >> 4), 0x00000000);
 	}
 
 	/* Disable all interrupts. */
 	for (i = 32; i < sc->nirqs; i += 32) {
-		gic_d_write_4(GICD_ICENABLER(i >> 5), 0xFFFFFFFF);
+		gic_d_write_4(sc, GICD_ICENABLER(i >> 5), 0xFFFFFFFF);
 	}
 
 	for (i = 0; i < sc->nirqs; i += 4) {
@@ -235,100 +238,61 @@ arm_gic_attach(device_t dev)
 
 	/* Set all the interrupts to be in Group 0 (secure) */
 	for (i = 0; i < sc->nirqs; i += 32) {
-		gic_d_write_4(GICD_IGROUPR(i >> 5), 0);
+		gic_d_write_4(sc, GICD_IGROUPR(i >> 5), 0);
 	}
 
 	/* Enable CPU interface */
-	gic_c_write_4(GICC_CTLR, 1);
+	gic_c_write_4(sc, GICC_CTLR, 1);
 
 	/* Set priority mask register. */
-	gic_c_write_4(GICC_PMR, 0xff);
+	gic_c_write_4(sc, GICC_PMR, 0xff);
 
 	/* Enable interrupt distribution */
-	gic_d_write_4(GICD_CTLR, 0x01);
+	gic_d_write_4(sc, GICD_CTLR, 0x01);
 
 	return (0);
 }
 
-static device_method_t arm_gic_methods[] = {
-	DEVMETHOD(device_probe,		arm_gic_probe),
-	DEVMETHOD(device_attach,	arm_gic_attach),
-	{ 0, 0 }
-};
-
-static driver_t arm_gic_driver = {
-	"gic",
-	arm_gic_methods,
-	sizeof(struct arm_gic_softc),
-};
-
-static devclass_t arm_gic_devclass;
-
-EARLY_DRIVER_MODULE(gic, simplebus, arm_gic_driver, arm_gic_devclass, 0, 0,
-    BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE);
-
-static void
-gic_post_filter(void *arg)
-{
-	uintptr_t irq = (uintptr_t) arg;
-
-	if (irq > GIC_LAST_IPI)
-		arm_irq_memory_barrier(irq);
-	gic_c_write_4(GICC_EOIR, irq);
-}
-
-int
-arm_get_next_irq(int last_irq)
+static int
+arm_gic_intr(void *arg)
 {
-	uint32_t active_irq;
+	struct arm_gic_softc *sc = (struct arm_gic_softc *)arg;
+	uint32_t active_irq, last_irq = 0;
 
-	active_irq = gic_c_read_4(GICC_IAR);
+	active_irq = gic_c_read_4(sc, GICC_IAR);
 
-	/*
+	/* 
 	 * Immediatly EOIR the SGIs, because doing so requires the other
 	 * bits (ie CPU number), not just the IRQ number, and we do not
 	 * have this information later.
 	 */
-
-	if ((active_irq & 0x3ff) <= GIC_LAST_IPI)
-		gic_c_write_4(GICC_EOIR, active_irq);
+	   
+	if ((active_irq & 0x3ff) < 1)
+		gic_c_write_4(sc, GICC_EOIR, active_irq);
 	active_irq &= 0x3FF;
 
 	if (active_irq == 0x3FF) {
 		if (last_irq == -1)
-			printf("Spurious interrupt detected\n");
-		return -1;
+			printf("Spurious interrupt detected [0x%08x]\n", active_irq);
+		return (FILTER_HANDLED);
 	}
+	
+	gic_c_write_4(sc, GICC_EOIR, active_irq);
+	arm_dispatch_irq(sc->gic_dev, NULL, active_irq);
 
-	return active_irq;
-}
-
-void
-arm_mask_irq(uintptr_t nb)
-{
-
-	gic_d_write_4(GICD_ICENABLER(nb >> 5), (1UL << (nb & 0x1F)));
-	gic_c_write_4(GICC_EOIR, nb);
-}
-
-void
-arm_unmask_irq(uintptr_t nb)
-{
-
-	if (nb > GIC_LAST_IPI)
-		arm_irq_memory_barrier(nb);
-	gic_d_write_4(GICD_ISENABLER(nb >> 5), (1UL << (nb & 0x1F)));
+	return (FILTER_HANDLED);
 }
 
 static int
-gic_config_irq(int irq, enum intr_trigger trig,
+arm_gic_config(device_t dev, int irq, enum intr_trigger trig,
     enum intr_polarity pol)
 {
+	struct arm_gic_softc *sc = device_get_softc(dev);
 	uint32_t reg;
 	uint32_t mask;
 
 	/* Function is public-accessible, so validate input arguments */
-	if ((irq < 0) || (irq >= arm_gic_sc->nirqs))
+	if ((irq < 0) || (irq >= sc->nirqs))
 		goto invalid_args;
 	if ((trig != INTR_TRIGGER_EDGE) && (trig != INTR_TRIGGER_LEVEL) &&
 	    (trig != INTR_TRIGGER_CONFORM))
@@ -337,9 +301,9 @@ gic_config_irq(int irq, enum intr_trigge
 	    (pol != INTR_POLARITY_CONFORM))
 		goto invalid_args;
 
-	mtx_lock_spin(&arm_gic_sc->mutex);
+	mtx_lock_spin(&sc->mutex);
 
-	reg = gic_d_read_4(GICD_ICFGR(irq >> 4));
+	reg = gic_d_read_4(sc, GICD_ICFGR(irq >> 4));
 	mask = (reg >> 2*(irq % 16)) & 0x3;
 
 	if (pol == INTR_POLARITY_LOW) {
@@ -361,32 +325,64 @@ gic_config_irq(int irq, enum intr_trigge
 	/* Set mask */
 	reg = reg & ~(0x3 << 2*(irq % 16));
 	reg = reg | (mask << 2*(irq % 16));
-	gic_d_write_4(GICD_ICFGR(irq >> 4), reg);
+	gic_d_write_4(sc, GICD_ICFGR(irq >> 4), reg);
 
-	mtx_unlock_spin(&arm_gic_sc->mutex);
+	mtx_unlock_spin(&sc->mutex);
 
 	return (0);
 
 invalid_args:
-	device_printf(arm_gic_sc->dev, "gic_config_irg, invalid parameters\n");
+	device_printf(dev, "gic_config_irg, invalid parameters\n");
 	return (EINVAL);
 }
 
-#ifdef SMP
-void
-pic_ipi_send(cpuset_t cpus, u_int ipi)
+static void
+arm_gic_eoi(device_t dev, int irq)
 {
+	struct arm_gic_softc *sc = device_get_softc(dev);
+
+	if (irq > GIC_LAST_IPI)
+		arm_irq_memory_barrier(irq);
+
+	gic_c_write_4(sc, GICC_EOIR, irq);
+}
+
+
+static void
+arm_gic_mask(device_t dev, int irq)
+{
+	struct arm_gic_softc *sc = device_get_softc(dev);
+
+	gic_d_write_4(sc, GICD_ICENABLER(irq >> 5), (1UL << (irq & 0x1F)));
+	gic_c_write_4(GICC_EOIR, nb);
+}
+
+static void
+arm_gic_unmask(device_t dev, int irq)
+{
+	struct arm_gic_softc *sc = device_get_softc(dev);
+
+	if (nb > GIC_LAST_IPI)
+		arm_irq_memory_barrier(nb);
+
+	gic_d_write_4(sc, GICD_ISENABLER(irq >> 5), (1UL << (irq & 0x1F)));
+}
+
+static void
+arm_gic_ipi_send(device_t dev, cpuset_t cpus, int ipi)
+{
+	struct arm_gic_softc *sc = device_get_softc(dev);
 	uint32_t val = 0, i;
 
 	for (i = 0; i < MAXCPU; i++)
 		if (CPU_ISSET(i, &cpus))
 			val |= 1 << (16 + i);
-	gic_d_write_4(GICD_SGIR(0), val | ipi);
 
+	gic_d_write_4(sc, GICD_SGIR(0), val | ipi);
 }
 
-int
-pic_ipi_get(int i)
+static int
+arm_gic_ipi_read(device_t dev, int i)
 {
 
 	if (i != -1) {
@@ -394,16 +390,44 @@ pic_ipi_get(int i)
 		 * The intr code will automagically give the frame pointer
 		 * if the interrupt argument is 0.
 		 */
-		if ((unsigned int)i > 16)
+		if ((unsigned int)i > 16) 
 			return (0);
 		return (i);
 	}
+
 	return (0x3ff);
 }
 
-void
-pic_ipi_clear(int ipi)
+static void
+arm_gic_ipi_clear(device_t dev, int ipi)
 {
+	/* no-op */
 }
-#endif
+
+static device_method_t arm_gic_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		arm_gic_probe),
+	DEVMETHOD(device_attach,	arm_gic_attach),
+
+	/* Interrupt controller interface */
+	DEVMETHOD(pic_config,		arm_gic_config),
+	DEVMETHOD(pic_mask,		arm_gic_mask),
+	DEVMETHOD(pic_unmask,		arm_gic_unmask),
+	DEVMETHOD(pic_eoi,		arm_gic_eoi),
+	DEVMETHOD(pic_init_secondary,	arm_gic_init_secondary),
+	DEVMETHOD(pic_ipi_send,		arm_gic_ipi_send),
+	DEVMETHOD(pic_ipi_clear,	arm_gic_ipi_clear),
+	DEVMETHOD(pic_ipi_read,		arm_gic_ipi_read),
+	{ 0, 0 }
+};
+
+static driver_t arm_gic_driver = {
+	"gic",
+	arm_gic_methods,
+	sizeof(struct arm_gic_softc),
+};
+
+static devclass_t arm_gic_devclass;
+
+DRIVER_MODULE(gic, simplebus, arm_gic_driver, arm_gic_devclass, 0, 0);
 

Modified: projects/arm_intrng/sys/arm/arm/intr.c
==============================================================================
--- projects/arm_intrng/sys/arm/arm/intr.c	Mon Aug 11 16:31:28 2014	(r269816)
+++ projects/arm_intrng/sys/arm/arm/intr.c	Mon Aug 11 16:44:06 2014	(r269817)
@@ -89,6 +89,15 @@ intr_init(void *unused)
 
 SYSINIT(intr_init, SI_SUB_INTR, SI_ORDER_FIRST, intr_init, NULL);
 
+const char *
+arm_describe_irq(int irq)
+{
+	static char buffer[8];
+
+	sprintf(buffer, "%d", irq);
+	return (buffer);
+}
+
 void
 arm_setup_irqhandler(const char *name, driver_filter_t *filt,
     void (*hand)(void*), void *arg, int irq, int flags, void **cookiep)

Added: projects/arm_intrng/sys/arm/arm/intrng.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ projects/arm_intrng/sys/arm/arm/intrng.c	Mon Aug 11 16:44:06 2014	(r269817)
@@ -0,0 +1,444 @@
+/*-
+ * Copyright (c) 2012-2014 Jakub Wojciech Klama <jceel@FreeBSD.org>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by Mark Brinicombe
+ *	for the NetBSD Project.
+ * 4. The name of the company nor the name of the author may be used to
+ *    endorse or promote products derived from this software without specific
+ *    prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/syslog.h> 
+#include <sys/malloc.h>
+#include <sys/proc.h>
+#include <sys/bus.h>
+#include <sys/interrupt.h>
+#include <sys/conf.h>
+#include <machine/atomic.h>
+#include <machine/intr.h>
+#include <machine/cpu.h>
+#include <machine/smp.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include "pic_if.h"
+
+#define	INTRNAME_LEN	(MAXCOMLEN + 1)
+
+#define	IRQ_PIC_IDX(_irq)	((_irq >> 8) & 0xff)
+#define	IRQ_VECTOR_IDX(_irq)	((_irq) & 0xff)
+#define	IRQ_GEN(_pic, _irq)	(((_pic) << 8) | ((_irq) & 0xff))
+
+#ifdef DEBUG
+#define debugf(fmt, args...) do { printf("%s(): ", __func__);	\
+    printf(fmt,##args); } while (0)
+#else
+#define debugf(fmt, args...)
+#endif
+
+typedef void (*mask_fn)(void *);
+
+struct arm_intr_controller {
+	device_t		ic_dev;
+	phandle_t		ic_node;
+};
+
+struct arm_intr_handler {
+	device_t		ih_dev;
+	const char *		ih_ipi_name;
+	int			ih_intrcnt_idx;
+	int			ih_irq;
+	struct intr_event *	ih_event;
+	struct arm_intr_controller *ih_pic;
+};
+
+static void arm_mask_irq(void *);
+static void arm_unmask_irq(void *);
+static void arm_eoi(void *);
+
+static struct arm_intr_handler arm_intrs[NIRQ];
+static struct arm_intr_controller arm_pics[NPIC];
+static struct arm_intr_controller *arm_ipi_pic;
+
+static int intrcnt_index = 0;
+static int last_printed = 0;
+
+/* Data for statistics reporting. */
+u_long intrcnt[NIRQ];
+char intrnames[NIRQ * INTRNAME_LEN];
+size_t sintrcnt = sizeof(intrcnt);
+size_t sintrnames = sizeof(intrnames);
+int (*arm_config_irq)(int irq, enum intr_trigger trig,
+    enum intr_polarity pol) = NULL;
+
+void
+arm_intrnames_init(void)
+{
+	/* nothing... */
+}
+
+void
+arm_dispatch_irq(device_t dev, struct trapframe *tf, int irq)
+{
+	struct arm_intr_handler *ih = NULL;
+	int i;
+
+	debugf("pic %s, tf %p, irq %d\n", device_get_nameunit(dev), tf, irq);
+
+	/*
+	 * If we got null trapframe argument, that probably means
+	 * a call from non-root interrupt controller. In that case,
+	 * we'll just use the saved one.
+	 */
+	if (tf == NULL)
+		tf = PCPU_GET(curthread)->td_intr_frame;
+
+	for (i = 0; arm_intrs[i].ih_dev != NULL; i++) {
+		if (arm_intrs[i].ih_pic->ic_dev == dev &&
+		    arm_intrs[i].ih_irq == irq) {
+			ih = &arm_intrs[i];
+			break;
+		}
+	}
+
+	if (ih == NULL)
+		panic("arm_dispatch_irq: unknown irq");
+
+	debugf("requested by %s\n", ih->ih_ipi_name != NULL
+	    ? ih->ih_ipi_name
+	    : device_get_nameunit(ih->ih_dev));
+
+	intrcnt[ih->ih_intrcnt_idx]++;
+	if (intr_event_handle(ih->ih_event, tf) != 0) {
+		/* Stray IRQ */
+		arm_mask_irq(ih);
+	}
+
+	debugf("done\n");
+}
+
+static struct arm_intr_handler *
+arm_lookup_intr_handler(device_t pic, int irq)
+{
+	int i;
+
+	for (i = 0; i < NIRQ; i++) {
+		if (arm_intrs[i].ih_pic != NULL &&
+		    arm_intrs[i].ih_pic->ic_dev == pic &&
+		    arm_intrs[i].ih_irq == irq)
+			return (&arm_intrs[i]);
+
+		if (arm_intrs[i].ih_dev == NULL)
+			return (&arm_intrs[i]);
+	}
+
+	return NULL;
+}
+
+int
+arm_fdt_map_irq(phandle_t ic, int irq)
+{
+	int i;
+
+	ic = OF_xref_phandle(ic);
+
+	debugf("ic %08x irq %d\n", ic, irq);
+
+	if (ic == CORE_PIC_NODE)
+		return (IRQ_GEN(CORE_PIC_IDX, irq));
+
+	for (i = 0; arm_pics[i].ic_node != 0; i++) {
+		if (arm_pics[i].ic_node	== ic)
+			return (IRQ_GEN(i, irq));
+	}
+
+	/* 
+	 * Interrupt controller is not registered yet, so
+	 * we map a stub for it. 'i' is pointing to free
+	 * first slot in arm_pics table.
+	 */
+	arm_pics[i].ic_node = ic;
+	return (IRQ_GEN(i, irq));
+}
+
+const char *
+arm_describe_irq(int irq)
+{
+	struct arm_intr_controller *pic;
+	static char buffer[INTRNAME_LEN];
+	static char name[INTRNAME_LEN];
+
+	pic = &arm_pics[IRQ_PIC_IDX(irq)];
+
+	if (pic->ic_dev == NULL) {
+		/*
+		 * Interrupt controller not attached yet, so we'll use it's
+		 * FDT "name" property instead
+		 */
+		OF_getprop(pic->ic_node, "name", name, sizeof(name));
+		snprintf(buffer, sizeof(buffer), "%s.%d", name,
+		    IRQ_VECTOR_IDX(irq));
+		return (buffer);
+	}
+
+	snprintf(buffer, sizeof(buffer), "%s.%d",
+	    device_get_nameunit(pic->ic_dev), IRQ_VECTOR_IDX(irq));
+
+	return (buffer);
+}
+
+void
+arm_register_pic(device_t dev, int flags)
+{
+	struct arm_intr_controller *ic = NULL;
+	phandle_t node;
+	int i;
+
+	node = ofw_bus_get_node(dev);
+
+	/* Find room for IC */
+	for (i = 0; i < NPIC; i++) {
+		if (arm_pics[i].ic_dev != NULL)
+			continue;
+
+		if (arm_pics[i].ic_node == node) {
+			ic = &arm_pics[i];
+			break;
+		}
+
+		if (arm_pics[i].ic_node == 0) {
+			ic = &arm_pics[i];
+			break;
+		}
+	}
+
+	if (ic == NULL)
+		panic("not enough room to register interrupt controller");
+
+	ic->ic_dev = dev;
+	ic->ic_node = node;
+
+	debugf("device %s node %08x slot %d\n", device_get_nameunit(dev), ic->ic_node, i);
+
+	if (flags & PIC_FEATURE_IPI) {
+		if (arm_ipi_pic != NULL)
+			panic("there's already registered interrupt controller for serving IPIs");
+
+		arm_ipi_pic = ic;
+	}
+
+	device_printf(dev, "registered as interrupt controller\n");
+}
+
+void
+arm_setup_irqhandler(device_t dev, driver_filter_t *filt, 
+    void (*hand)(void*), void *arg, int irq, int flags, void **cookiep)
+{
+	struct arm_intr_controller *pic;
+	struct arm_intr_handler *ih;
+	const char *name;
+	int error;
+	int ipi;
+
+	if (irq < 0)
+		return;
+
+	ipi = (flags & INTR_IPI) != 0;
+	pic = ipi ? arm_ipi_pic : &arm_pics[IRQ_PIC_IDX(irq)];
+	ih = arm_lookup_intr_handler(pic->ic_dev, IRQ_VECTOR_IDX(irq));
+
+	if (ipi) {
+		name = (const char *)dev;
+		debugf("setup ipi %d\n", irq);
+	} else {
+		name = device_get_nameunit(dev);
+		debugf("setup irq %d on %s\n", IRQ_VECTOR_IDX(irq),
+		    device_get_nameunit(pic->ic_dev));
+	}
+
+	debugf("pic %p, ih %p\n", pic, ih);
+
+	if (ih->ih_event == NULL) {
+		error = intr_event_create(&ih->ih_event, (void *)ih, 0, irq,
+		    (mask_fn)arm_mask_irq, (mask_fn)arm_unmask_irq,
+		    arm_eoi, NULL, "intr%d:", irq);
+		
+		if (error)
+			return;
+
+		ih->ih_dev = dev;
+		ih->ih_ipi_name = ipi ? name : NULL;
+		ih->ih_irq = IRQ_VECTOR_IDX(irq);
+		ih->ih_pic = pic;
+
+		arm_unmask_irq(ih);
+
+		last_printed += 
+		    snprintf(intrnames + last_printed,
+		    INTRNAME_LEN, "%s:%d: %s",
+		    device_get_nameunit(pic->ic_dev),
+		    ih->ih_irq, name);
+		
+		last_printed++;
+		ih->ih_intrcnt_idx = intrcnt_index;
+		intrcnt_index++;
+		
+	}
+
+	intr_event_add_handler(ih->ih_event, name, filt, hand, arg,
+	    intr_priority(flags), flags, cookiep);
+
+	/* Unmask IPIs immediately */
+	if (ipi)
+		arm_unmask_irq(ih);
+}
+
+int
+arm_remove_irqhandler(int irq, void *cookie)
+{
+	struct arm_intr_controller *pic;
+	struct arm_intr_handler *ih;
+	int error;
+
+	if (irq < 0)
+		return (ENXIO);
+
+	pic = &arm_pics[IRQ_PIC_IDX(irq)];
+	ih = arm_lookup_intr_handler(pic->ic_dev, IRQ_VECTOR_IDX(irq));
+
+	if (ih->ih_event == NULL)
+		return (ENXIO);
+
+	arm_mask_irq(ih);
+	error = intr_event_remove_handler(cookie);
+
+	if (!TAILQ_EMPTY(&ih->ih_event->ie_handlers))
+		arm_unmask_irq(ih);
+
+	return (error);
+}
+
+static void
+arm_mask_irq(void *arg)
+{
+	struct arm_intr_handler *ih = (struct arm_intr_handler *)arg;
+
+	PIC_MASK(ih->ih_pic->ic_dev, ih->ih_irq);
+}
+
+static void
+arm_unmask_irq(void *arg)
+{
+	struct arm_intr_handler *ih = (struct arm_intr_handler *)arg;
+
+	PIC_UNMASK(ih->ih_pic->ic_dev, ih->ih_irq);
+}
+
+static void
+arm_eoi(void *arg)
+{
+	struct arm_intr_handler *ih = (struct arm_intr_handler *)arg;
+
+	PIC_EOI(ih->ih_pic->ic_dev, ih->ih_irq);
+}
+
+int
+arm_intrng_config_irq(int irq, enum intr_trigger trig, enum intr_polarity pol)
+{
+	struct arm_intr_controller *pic;
+	struct arm_intr_handler *ih;
+
+	pic = &arm_pics[IRQ_PIC_IDX(irq)];
+	ih = arm_lookup_intr_handler(pic->ic_dev, IRQ_VECTOR_IDX(irq));
+
+	if (ih == NULL)
+		return (ENXIO);
+
+	return PIC_CONFIG(pic->ic_dev, ih->ih_irq, trig, pol);
+}
+
+#ifdef SMP
+void
+arm_init_secondary_ic(void)
+{
+
+	KASSERT(arm_ipi_pic != NULL, ("no IPI PIC attached"));
+	PIC_INIT_SECONDARY(arm_ipi_pic->ic_dev);
+}
+
+void
+pic_ipi_send(cpuset_t cpus, u_int ipi)
+{
+
+	KASSERT(arm_ipi_pic != NULL, ("no IPI PIC attached"));
+	PIC_IPI_SEND(arm_ipi_pic->ic_dev, cpus, ipi);
+}
+
+void
+pic_ipi_clear(int ipi)
+{
+	
+	KASSERT(arm_ipi_pic != NULL, ("no IPI PIC attached"));
+	PIC_IPI_CLEAR(arm_ipi_pic->ic_dev, ipi);
+}
+
+int
+pic_ipi_read(int ipi)
+{
+
+	KASSERT(arm_ipi_pic != NULL, ("no IPI PIC attached"));
+	return (PIC_IPI_READ(arm_ipi_pic->ic_dev, ipi));
+}
+
+void
+arm_unmask_ipi(int ipi)
+{
+
+	KASSERT(arm_ipi_pic != NULL, ("no IPI PIC attached"));
+	PIC_UNMASK(arm_ipi_pic->ic_dev, ipi);
+}
+
+void
+arm_mask_ipi(int ipi)
+{
+
+	KASSERT(arm_ipi_pic != NULL, ("no IPI PIC attached"));
+	PIC_MASK(arm_ipi_pic->ic_dev, ipi);
+}
+#endif
+
+void dosoftints(void);
+void
+dosoftints(void)
+{
+}
+

Modified: projects/arm_intrng/sys/arm/arm/mp_machdep.c
==============================================================================
--- projects/arm_intrng/sys/arm/arm/mp_machdep.c	Mon Aug 11 16:31:28 2014	(r269816)
+++ projects/arm_intrng/sys/arm/arm/mp_machdep.c	Mon Aug 11 16:44:06 2014	(r269817)
@@ -235,7 +235,7 @@ init_secondary(int cpu)
 #endif
 				
 	for (int i = start; i <= end; i++)
-		arm_unmask_irq(i);
+		arm_unmask_ipi(i);
 	enable_interrupts(I32_bit);
 
 	loop_counter = 0;
@@ -265,7 +265,7 @@ ipi_handler(void *arg)
 
 	cpu = PCPU_GET(cpuid);
 
-	ipi = pic_ipi_get((int)arg);
+	ipi = pic_ipi_read((int)arg);
 
 	while ((ipi != 0x3ff)) {
 		switch (ipi) {
@@ -328,7 +328,7 @@ ipi_handler(void *arg)
 		}
 
 		pic_ipi_clear(ipi);
-		ipi = pic_ipi_get(-1);
+		ipi = pic_ipi_read(-1);
 	}
 
 	return (FILTER_HANDLED);
@@ -360,11 +360,10 @@ release_aps(void *dummy __unused)
 		 * if we used 0, the intr code will give the trap frame
 		 * pointer instead.
 		 */
-		arm_setup_irqhandler("ipi", ipi_handler, NULL, (void *)i, i,
-		    INTR_TYPE_MISC | INTR_EXCL, NULL);
-
-		/* Enable ipi */
-		arm_unmask_irq(i);
+		arm_setup_irqhandler((device_t)"ipi", ipi_handler, NULL, (void *)i, i,
+		    INTR_TYPE_MISC | INTR_EXCL | INTR_IPI, NULL);
+	
+		arm_unmask_ipi(i);
 	}
 	atomic_store_rel_int(&aps_ready, 1);
 

Modified: projects/arm_intrng/sys/arm/arm/nexus.c
==============================================================================
--- projects/arm_intrng/sys/arm/arm/nexus.c	Mon Aug 11 16:31:28 2014	(r269816)
+++ projects/arm_intrng/sys/arm/arm/nexus.c	Mon Aug 11 16:44:06 2014	(r269817)
@@ -68,6 +68,8 @@ __FBSDID("$FreeBSD$");
 #include "ofw_bus_if.h"
 #endif
 
+#include "pic_if.h"
+
 static MALLOC_DEFINE(M_NEXUSDEV, "nexusdev", "Nexus device");
 
 struct nexus_device {
@@ -77,6 +79,9 @@ struct nexus_device {
 #define DEVTONX(dev)	((struct nexus_device *)device_get_ivars(dev))
 
 static struct rman mem_rman;
+#if defined(ARM_INTRNG)
+static device_t nexus_dev;
+#endif
 
 static	int nexus_probe(device_t);
 static	int nexus_attach(device_t);
@@ -94,6 +99,13 @@ static	int nexus_deactivate_resource(dev
 static int nexus_setup_intr(device_t dev, device_t child, struct resource *res,
     int flags, driver_filter_t *filt, driver_intr_t *intr, void *arg, void **cookiep);
 static int nexus_teardown_intr(device_t, device_t, struct resource *, void *);
+#if defined(ARM_INTRNG)
+static int nexus_pic_config(device_t, int, enum intr_trigger, enum intr_polarity);
+static void nexus_pic_mask(device_t, int);
+static void nexus_pic_unmask(device_t, int);
+static void nexus_pic_eoi(device_t, int);
+void arm_irq_handler(struct trapframe *tf, int irqnb);
+#endif
 
 #ifdef FDT
 static int nexus_ofw_map_intr(device_t dev, device_t child, phandle_t iparent,
@@ -104,6 +116,7 @@ static device_method_t nexus_methods[] =
 	/* Device interface */
 	DEVMETHOD(device_probe,		nexus_probe),
 	DEVMETHOD(device_attach,	nexus_attach),
+

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?53e8f2d6.2f8f.71f433d6>