Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 14 May 2014 18:25:13 +0000 (UTC)
From:      Ian Lepore <ian@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-10@freebsd.org
Subject:   svn commit: r266070 - in stable/10/sys: arm/arm arm/include arm/versatile dev/ahci
Message-ID:  <201405141825.s4EIPDFb075319@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: ian
Date: Wed May 14 18:25:13 2014
New Revision: 266070
URL: http://svnweb.freebsd.org/changeset/base/266070

Log:
  MFC r260161, r260163, r260165, r260166, r260189
  
    Add polarity and level support to ARM GIC
  
    Do not attach to PCI bridges in AHCI driver
  
    Use only mapped BIOs on ARM
  
    Fix race condition in DELAY for SP804 timer.

Modified:
  stable/10/sys/arm/arm/gic.c
  stable/10/sys/arm/arm/intr.c
  stable/10/sys/arm/arm/nexus.c
  stable/10/sys/arm/include/intr.h
  stable/10/sys/arm/versatile/sp804.c
  stable/10/sys/dev/ahci/ahci.c
Directory Properties:
  stable/10/   (props changed)

Modified: stable/10/sys/arm/arm/gic.c
==============================================================================
--- stable/10/sys/arm/arm/gic.c	Wed May 14 18:23:57 2014	(r266069)
+++ stable/10/sys/arm/arm/gic.c	Wed May 14 18:25:13 2014	(r266070)
@@ -83,6 +83,15 @@ __FBSDID("$FreeBSD$");
 #define GICC_ABPR		0x001C			/* v1 ICCABPR */
 #define GICC_IIDR		0x00FC			/* v1 ICCIIDR*/
 
+/* First bit is a polarity bit (0 - low, 1 - high) */
+#define GICD_ICFGR_POL_LOW	(0 << 0)
+#define GICD_ICFGR_POL_HIGH	(1 << 0)
+#define GICD_ICFGR_POL_MASK	0x1
+/* Second bit is a trigger bit (0 - level, 1 - edge) */
+#define GICD_ICFGR_TRIG_LVL	(0 << 1)
+#define GICD_ICFGR_TRIG_EDGE	(1 << 1)
+#define GICD_ICFGR_TRIG_MASK	0x2
+
 struct arm_gic_softc {
 	struct resource *	gic_res[3];
 	bus_space_tag_t		gic_c_bst;
@@ -90,6 +99,9 @@ struct arm_gic_softc {
 	bus_space_handle_t	gic_c_bsh;
 	bus_space_handle_t	gic_d_bsh;
 	uint8_t			ver;
+	device_t		dev;
+	struct mtx		mutex;
+	uint32_t		nirqs;
 };
 
 static struct resource_spec arm_gic_spec[] = {
@@ -109,6 +121,8 @@ static struct arm_gic_softc *arm_gic_sc 
 #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
@@ -157,19 +171,20 @@ arm_gic_attach(device_t dev)
 	struct		arm_gic_softc *sc;
 	int		i;
 	uint32_t	icciidr;
-	uint32_t	nirqs;
 
 	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);
 	}
 
-	arm_post_filter = gic_post_filter;
+	/* Initialize mutex */
+	mtx_init(&sc->mutex, "GIC lock", "", MTX_SPIN);
 
 	/* Distributor Interface */
 	sc->gic_d_bst = rman_get_bustag(sc->gic_res[0]);
@@ -185,31 +200,35 @@ arm_gic_attach(device_t dev)
 	gic_d_write_4(GICD_CTLR, 0x00);
 
 	/* Get the number of interrupts */
-	nirqs = gic_d_read_4(GICD_TYPER);
-	nirqs = 32 * ((nirqs & 0x1f) + 1);
+	sc->nirqs = gic_d_read_4(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 nirqs %u\n",
+	device_printf(dev,"pn 0x%x, arch 0x%x, rev 0x%x, implementer 0x%x sc->nirqs %u\n",
 			icciidr>>20, (icciidr>>16) & 0xF, (icciidr>>12) & 0xf,
-			(icciidr & 0xfff), nirqs);
+			(icciidr & 0xfff), sc->nirqs);
 
 	/* Set all global interrupts to be level triggered, active low. */
-	for (i = 32; i < nirqs; i += 32) {
-		gic_d_write_4(GICD_ICFGR(i >> 5), 0x00000000);
+	for (i = 32; i < sc->nirqs; i += 16) {
+		gic_d_write_4(GICD_ICFGR(i >> 4), 0x00000000);
 	}
 
 	/* Disable all interrupts. */
-	for (i = 32; i < nirqs; i += 32) {
+	for (i = 32; i < sc->nirqs; i += 32) {
 		gic_d_write_4(GICD_ICENABLER(i >> 5), 0xFFFFFFFF);
 	}
 
-	for (i = 0; i < nirqs; i += 4) {
+	for (i = 0; i < sc->nirqs; i += 4) {
 		gic_d_write_4(GICD_IPRIORITYR(i >> 2), 0);
 		gic_d_write_4(GICD_ITARGETSR(i >> 2), 1 << 0 | 1 << 8 | 1 << 16 | 1 << 24);
 	}
 
 	/* Set all the interrupts to be in Group 0 (secure) */
-	for (i = 0; i < nirqs; i += 32) {
+	for (i = 0; i < sc->nirqs; i += 32) {
 		gic_d_write_4(GICD_IGROUPR(i >> 5), 0);
 	}
 
@@ -290,6 +309,58 @@ arm_unmask_irq(uintptr_t nb)
 	gic_d_write_4(GICD_ISENABLER(nb >> 5), (1UL << (nb & 0x1F)));
 }
 
+static int
+gic_config_irq(int irq, enum intr_trigger trig,
+    enum intr_polarity pol)
+{
+	uint32_t reg;
+	uint32_t mask;
+
+	/* Function is public-accessible, so validate input arguments */
+	if ((irq < 0) || (irq >= arm_gic_sc->nirqs))
+		goto invalid_args;
+	if ((trig != INTR_TRIGGER_EDGE) && (trig != INTR_TRIGGER_LEVEL) &&
+	    (trig != INTR_TRIGGER_CONFORM))
+		goto invalid_args;
+	if ((pol != INTR_POLARITY_HIGH) && (pol != INTR_POLARITY_LOW) &&
+	    (pol != INTR_POLARITY_CONFORM))
+		goto invalid_args;
+
+	mtx_lock_spin(&arm_gic_sc->mutex);
+
+	reg = gic_d_read_4(GICD_ICFGR(irq >> 4));
+	mask = (reg >> 2*(irq % 16)) & 0x3;
+
+	if (pol == INTR_POLARITY_LOW) {
+		mask &= ~GICD_ICFGR_POL_MASK;
+		mask |= GICD_ICFGR_POL_LOW;
+	} else if (pol == INTR_POLARITY_HIGH) {
+		mask &= ~GICD_ICFGR_POL_MASK;
+		mask |= GICD_ICFGR_POL_HIGH;
+	}
+
+	if (trig == INTR_TRIGGER_LEVEL) {
+		mask &= ~GICD_ICFGR_TRIG_MASK;
+		mask |= GICD_ICFGR_TRIG_LVL;
+	} else if (trig == INTR_TRIGGER_EDGE) {
+		mask &= ~GICD_ICFGR_TRIG_MASK;
+		mask |= GICD_ICFGR_TRIG_EDGE;
+	}
+
+	/* Set mask */
+	reg = reg & ~(0x3 << 2*(irq % 16));
+	reg = reg | (mask << 2*(irq % 16));
+	gic_d_write_4(GICD_ICFGR(irq >> 4), reg);
+
+	mtx_unlock_spin(&arm_gic_sc->mutex);
+
+	return (0);
+
+invalid_args:
+	device_printf(arm_gic_sc->dev, "gic_config_irg, invalid parameters\n");
+	return (EINVAL);
+}
+
 #ifdef SMP
 void
 pic_ipi_send(cpuset_t cpus, u_int ipi)

Modified: stable/10/sys/arm/arm/intr.c
==============================================================================
--- stable/10/sys/arm/arm/intr.c	Wed May 14 18:23:57 2014	(r266069)
+++ stable/10/sys/arm/arm/intr.c	Wed May 14 18:25:13 2014	(r266070)
@@ -59,6 +59,8 @@ static struct intr_event *intr_events[NI
 void	arm_handler_execute(struct trapframe *, int);
 
 void (*arm_post_filter)(void *) = NULL;
+int (*arm_config_irq)(int irq, enum intr_trigger trig,
+    enum intr_polarity pol) = NULL;
 
 /*
  * Pre-format intrnames into an array of fixed-size strings containing spaces.

Modified: stable/10/sys/arm/arm/nexus.c
==============================================================================
--- stable/10/sys/arm/arm/nexus.c	Wed May 14 18:23:57 2014	(r266069)
+++ stable/10/sys/arm/arm/nexus.c	Wed May 14 18:25:13 2014	(r266070)
@@ -85,6 +85,8 @@ static	struct resource *nexus_alloc_reso
 #endif
 static	int nexus_activate_resource(device_t, device_t, int, int,
     struct resource *);
+static int nexus_config_intr(device_t dev, int irq, enum intr_trigger trig,
+    enum intr_polarity pol);
 static	int nexus_deactivate_resource(device_t, device_t, int, int,
     struct resource *);
 
@@ -103,6 +105,7 @@ static device_method_t nexus_methods[] =
 	DEVMETHOD(bus_alloc_resource,	nexus_alloc_resource),
 #endif
 	DEVMETHOD(bus_activate_resource,	nexus_activate_resource),
+	DEVMETHOD(bus_config_intr,	nexus_config_intr),
 	DEVMETHOD(bus_deactivate_resource,	nexus_deactivate_resource),
 	DEVMETHOD(bus_setup_intr,	nexus_setup_intr),
 	DEVMETHOD(bus_teardown_intr,	nexus_teardown_intr),
@@ -225,6 +228,18 @@ nexus_alloc_resource(device_t bus, devic
 #endif
 
 static int
+nexus_config_intr(device_t dev, int irq, enum intr_trigger trig,
+    enum intr_polarity pol)
+{
+	int ret = ENODEV;
+
+	if (arm_config_irq)
+		ret = (*arm_config_irq)(irq, trig, pol);
+
+	return (ret);
+}
+
+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)
 {

Modified: stable/10/sys/arm/include/intr.h
==============================================================================
--- stable/10/sys/arm/include/intr.h	Wed May 14 18:23:57 2014	(r266069)
+++ stable/10/sys/arm/include/intr.h	Wed May 14 18:25:13 2014	(r266070)
@@ -68,6 +68,7 @@
 #endif
 
 #include <machine/psl.h>
+#include <sys/bus.h>
 
 int arm_get_next_irq(int);
 void arm_mask_irq(uintptr_t);
@@ -77,6 +78,8 @@ void arm_setup_irqhandler(const char *, 
     void *, int, int, void **);
 int arm_remove_irqhandler(int, void *);
 extern void (*arm_post_filter)(void *);
+extern int (*arm_config_irq)(int irq, enum intr_trigger trig,
+    enum intr_polarity pol);
 
 void gic_init_secondary(void);
 

Modified: stable/10/sys/arm/versatile/sp804.c
==============================================================================
--- stable/10/sys/arm/versatile/sp804.c	Wed May 14 18:23:57 2014	(r266069)
+++ stable/10/sys/arm/versatile/sp804.c	Wed May 14 18:25:13 2014	(r266070)
@@ -100,6 +100,7 @@ struct sp804_timer_softc {
 	struct timecounter	tc;
 	bool			et_enabled;
 	struct eventtimer	et;
+	int			timer_initialized;
 };
 
 /* Read/Write macros for Timer used as timecounter */
@@ -198,6 +199,8 @@ sp804_timer_attach(device_t dev)
 	int rid = 0;
 	int i;
 	uint32_t id, reg;
+	phandle_t node;
+	pcell_t clock;
 
 	sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
 	if (sc->mem_res == NULL) {
@@ -215,8 +218,12 @@ sp804_timer_attach(device_t dev)
 		return (ENXIO);
 	}
 
-	/* TODO: get frequency from FDT */
 	sc->sysclk_freq = DEFAULT_FREQUENCY;
+	/* Get the base clock frequency */
+	node = ofw_bus_get_node(dev);
+	if ((OF_getprop(node, "clock-frequency", &clock, sizeof(clock))) > 0) {
+		sc->sysclk_freq = fdt32_to_cpu(clock);
+	}
 
 	/* Setup and enable the timer */
 	if (bus_setup_intr(dev, sc->irq_res, INTR_TYPE_CLK,
@@ -234,8 +241,8 @@ sp804_timer_attach(device_t dev)
 	/*
 	 * Timer 1, timecounter
 	 */
-	sc->tc.tc_frequency = DEFAULT_FREQUENCY;
-	sc->tc.tc_name = "SP804 Timecouter";
+	sc->tc.tc_frequency = sc->sysclk_freq;
+	sc->tc.tc_name = "SP804 Time Counter";
 	sc->tc.tc_get_timecount = sp804_timer_tc_get_timecount;
 	sc->tc.tc_poll_pps = NULL;
 	sc->tc.tc_counter_mask = ~0u;
@@ -283,6 +290,8 @@ sp804_timer_attach(device_t dev)
 
 	device_printf(dev, "PrimeCell ID: %08x\n", id);
 
+	sc->timer_initialized = 1;
+
 	return (0);
 }
 
@@ -309,10 +318,18 @@ DELAY(int usec)
 	uint32_t first, last;
 	device_t timer_dev;
 	struct sp804_timer_softc *sc;
+	int timer_initialized = 0;
 
 	timer_dev = devclass_get_device(sp804_timer_devclass, 0);
 
-	if (timer_dev == NULL) {
+	if (timer_dev) {
+		sc = device_get_softc(timer_dev);
+
+		if (sc)
+			timer_initialized = sc->timer_initialized;
+	}
+
+	if (!timer_initialized) {
 		/*
 		 * Timer is not initialized yet
 		 */
@@ -323,8 +340,6 @@ DELAY(int usec)
 		return;
 	}
 
-       	sc = device_get_softc(timer_dev);
-
 	/* Get the number of times to count */
 	counts = usec * ((sc->tc.tc_frequency / 1000000) + 1);
 

Modified: stable/10/sys/dev/ahci/ahci.c
==============================================================================
--- stable/10/sys/dev/ahci/ahci.c	Wed May 14 18:23:57 2014	(r266069)
+++ stable/10/sys/dev/ahci/ahci.c	Wed May 14 18:25:13 2014	(r266070)
@@ -376,6 +376,13 @@ ahci_probe(device_t dev)
 	uint32_t devid = pci_get_devid(dev);
 	uint8_t revid = pci_get_revid(dev);
 
+	/*
+	 * Ensure it is not a PCI bridge (some vendors use
+	 * the same PID and VID in PCI bridge and AHCI cards).
+	 */
+	if (pci_get_class(dev) == PCIC_BRIDGE)
+		return (ENXIO);
+
 	/* Is this a possible AHCI candidate? */
 	if (pci_get_class(dev) == PCIC_STORAGE &&
 	    pci_get_subclass(dev) == PCIS_STORAGE_SATA &&



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