Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 13 Aug 2017 18:54:51 +0000 (UTC)
From:      Andrew Turner <andrew@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r322470 - head/sys/arm64/arm64
Message-ID:  <201708131854.v7DIspAC014931@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: andrew
Date: Sun Aug 13 18:54:51 2017
New Revision: 322470
URL: https://svnweb.freebsd.org/changeset/base/322470

Log:
  Add support for multiple GICv3 ITS devices. For this we add sc_irq_base
  and sc_irq_length to the softc to handle the base number of IRQs available,
  make gicv3_get_nirqs return the number of available interrupt IDs, and
  limit which CPUs we send interrupts to based on the numa domain.
  
  The last point is only strictly needed on a dual socket ThunderX where we
  are unable to send MSI/MSI-X interrupts between sockets.
  
  Sponsored by:	DARPA, AFRL

Modified:
  head/sys/arm64/arm64/gic_v3.c
  head/sys/arm64/arm64/gic_v3_fdt.c
  head/sys/arm64/arm64/gicv3_its.c

Modified: head/sys/arm64/arm64/gic_v3.c
==============================================================================
--- head/sys/arm64/arm64/gic_v3.c	Sun Aug 13 18:41:37 2017	(r322469)
+++ head/sys/arm64/arm64/gic_v3.c	Sun Aug 13 18:54:51 2017	(r322470)
@@ -374,7 +374,7 @@ gic_v3_read_ivar(device_t dev, device_t child, int whi
 
 	switch (which) {
 	case GICV3_IVAR_NIRQS:
-		*result = sc->gic_nirqs;
+		*result = (NIRQ - sc->gic_nirqs) / sc->gic_nchildren;
 		return (0);
 	case GICV3_IVAR_REDIST_VADDR:
 		*result = (uintptr_t)rman_get_virtual(

Modified: head/sys/arm64/arm64/gic_v3_fdt.c
==============================================================================
--- head/sys/arm64/arm64/gic_v3_fdt.c	Sun Aug 13 18:41:37 2017	(r322469)
+++ head/sys/arm64/arm64/gic_v3_fdt.c	Sun Aug 13 18:54:51 2017	(r322470)
@@ -266,10 +266,12 @@ static int
 gic_v3_ofw_bus_attach(device_t dev)
 {
 	struct gic_v3_ofw_devinfo *di;
+	struct gic_v3_softc *sc;
 	device_t child;
 	phandle_t parent, node;
 	pcell_t addr_cells, size_cells;
 
+	sc = device_get_softc(dev);
 	parent = ofw_bus_get_node(dev);
 	if (parent > 0) {
 		addr_cells = 2;
@@ -320,6 +322,7 @@ gic_v3_ofw_bus_attach(device_t dev)
 				continue;
 			}
 
+			sc->gic_nchildren++;
 			device_set_ivars(child, di);
 		}
 	}

Modified: head/sys/arm64/arm64/gicv3_its.c
==============================================================================
--- head/sys/arm64/arm64/gicv3_its.c	Sun Aug 13 18:41:37 2017	(r322469)
+++ head/sys/arm64/arm64/gicv3_its.c	Sun Aug 13 18:54:51 2017	(r322470)
@@ -228,6 +228,9 @@ struct gicv3_its_softc {
 	struct intr_pic *sc_pic;
 	struct resource *sc_its_res;
 
+	cpuset_t	sc_cpus;
+	u_int		gic_irq_cpu;
+
 	struct its_ptable sc_its_ptab[GITS_BASER_NUM];
 	struct its_col *sc_its_cols[MAXCPU];	/* Per-CPU collections */
 
@@ -245,6 +248,8 @@ struct gicv3_its_softc {
 
 	vmem_t *sc_irq_alloc;
 	struct gicv3_its_irqsrc	*sc_irqs;
+	u_int	sc_irq_base;
+	u_int	sc_irq_length;
 
 	struct mtx sc_its_dev_lock;
 	TAILQ_HEAD(its_dev_list, its_dev) sc_its_dev_list;
@@ -274,8 +279,6 @@ static const struct {
 	},
 };
 
-static u_int gic_irq_cpu;
-
 #define	gic_its_read_4(sc, reg)			\
     bus_read_4((sc)->sc_its_res, (reg))
 #define	gic_its_read_8(sc, reg)			\
@@ -555,7 +558,7 @@ gicv3_its_pendtables_init(struct gicv3_its_softc *sc)
 	int i;
 
 	for (i = 0; i < mp_ncpus; i++) {
-		if (CPU_ISSET(i, &all_cpus) == 0)
+		if (CPU_ISSET(i, &sc->sc_cpus) == 0)
 			continue;
 
 		sc->sc_pend_base[i] = (vm_offset_t)contigmalloc(
@@ -578,6 +581,9 @@ its_init_cpu(device_t dev, struct gicv3_its_softc *sc)
 	u_int cpuid;
 	int domain;
 
+	if (!CPU_ISSET(PCPU_GET(cpuid), &sc->sc_cpus))
+		return (0);
+
 	if (bus_get_domain(dev, &domain) == 0) {
 		if (PCPU_GET(domain) != domain)
 			return (0);
@@ -683,7 +689,7 @@ gicv3_its_attach(device_t dev)
 	struct gicv3_its_softc *sc;
 	const char *name;
 	uint32_t iidr;
-	int err, i, rid;
+	int domain, err, i, rid;
 
 	sc = device_get_softc(dev);
 
@@ -718,12 +724,20 @@ gicv3_its_attach(device_t dev)
 	/* Protects access to the ITS command circular buffer. */
 	mtx_init(&sc->sc_its_cmd_lock, "ITS cmd lock", NULL, MTX_SPIN);
 
+	if (bus_get_domain(dev, &domain) == 0) {
+		CPU_ZERO(&sc->sc_cpus);
+		if (domain < MAXMEMDOM)
+			CPU_COPY(&cpuset_domain[domain], &sc->sc_cpus);
+	} else {
+		CPU_COPY(&all_cpus, &sc->sc_cpus);
+	}
+
 	/* Allocate the command circular buffer */
 	gicv3_its_cmdq_init(sc);
 
 	/* Allocate the per-CPU collections */
 	for (int cpu = 0; cpu < mp_ncpus; cpu++)
-		if (CPU_ISSET(cpu, &all_cpus) != 0)
+		if (CPU_ISSET(cpu, &sc->sc_cpus) != 0)
 			sc->sc_its_cols[cpu] = malloc(
 			    sizeof(*sc->sc_its_cols[0]), M_GICV3_ITS,
 			    M_WAITOK | M_ZERO);
@@ -746,18 +760,18 @@ gicv3_its_attach(device_t dev)
 	TAILQ_INIT(&sc->sc_its_dev_list);
 
 	/*
-	 * Create the vmem object to allocate IRQs from. We try to use all
-	 * IRQs not already used by the GICv3.
+	 * Create the vmem object to allocate INTRNG IRQs from. We try to
+	 * use all IRQs not already used by the GICv3.
 	 * XXX: This assumes there are no other interrupt controllers in the
 	 * system.
 	 */
 	sc->sc_irq_alloc = vmem_create("GICv3 ITS IRQs", 0,
-	    NIRQ - gicv3_get_nirqs(dev), 1, 1, M_FIRSTFIT | M_WAITOK);
+	    gicv3_get_nirqs(dev), 1, 1, M_FIRSTFIT | M_WAITOK);
 
-	sc->sc_irqs = malloc(sizeof(*sc->sc_irqs) * LPI_NIRQS, M_GICV3_ITS,
-	    M_WAITOK | M_ZERO);
+	sc->sc_irqs = malloc(sizeof(*sc->sc_irqs) * sc->sc_irq_length,
+	    M_GICV3_ITS, M_WAITOK | M_ZERO);
 	name = device_get_nameunit(dev);
-	for (i = 0; i < LPI_NIRQS; i++) {
+	for (i = 0; i < sc->sc_irq_length; i++) {
 		sc->sc_irqs[i].gi_irq = i;
 		err = intr_isrc_register(&sc->sc_irqs[i].gi_isrc, dev, 0,
 		    "%s,%u", name, i);
@@ -837,11 +851,11 @@ gicv3_its_intr(void *arg, uintptr_t irq)
 	struct gicv3_its_irqsrc *girq;
 	struct trapframe *tf;
 
-	irq -= GIC_FIRST_LPI;
+	irq -= sc->sc_irq_base;
 	girq = &sc->sc_irqs[irq];
 	if (girq == NULL)
 		panic("gicv3_its_intr: Invalid interrupt %ld",
-		    irq + GIC_FIRST_LPI);
+		    irq + sc->sc_irq_base);
 
 	tf = curthread->td_intr_frame;
 	intr_isrc_dispatch(&girq->gi_isrc, tf);
@@ -852,10 +866,12 @@ static void
 gicv3_its_pre_ithread(device_t dev, struct intr_irqsrc *isrc)
 {
 	struct gicv3_its_irqsrc *girq;
+	struct gicv3_its_softc *sc;
 
+	sc = device_get_softc(dev);
 	girq = (struct gicv3_its_irqsrc *)isrc;
 	gicv3_its_disable_intr(dev, isrc);
-	gic_icc_write(EOIR1, girq->gi_irq + GIC_FIRST_LPI);
+	gic_icc_write(EOIR1, girq->gi_irq + sc->sc_irq_base);
 }
 
 static void
@@ -869,20 +885,25 @@ static void
 gicv3_its_post_filter(device_t dev, struct intr_irqsrc *isrc)
 {
 	struct gicv3_its_irqsrc *girq;
+	struct gicv3_its_softc *sc;
 
+	sc = device_get_softc(dev);
 	girq = (struct gicv3_its_irqsrc *)isrc;
-	gic_icc_write(EOIR1, girq->gi_irq + GIC_FIRST_LPI);
+	gic_icc_write(EOIR1, girq->gi_irq + sc->sc_irq_base);
 }
 
 static int
 gicv3_its_bind_intr(device_t dev, struct intr_irqsrc *isrc)
 {
 	struct gicv3_its_irqsrc *girq;
+	struct gicv3_its_softc *sc;
 
+	sc = device_get_softc(dev);
 	girq = (struct gicv3_its_irqsrc *)isrc;
 	if (CPU_EMPTY(&isrc->isrc_cpu)) {
-		gic_irq_cpu = intr_irq_next_cpu(gic_irq_cpu, &all_cpus);
-		CPU_SETOF(gic_irq_cpu, &isrc->isrc_cpu);
+		sc->gic_irq_cpu = intr_irq_next_cpu(sc->gic_irq_cpu,
+		    &sc->sc_cpus);
+		CPU_SETOF(sc->gic_irq_cpu, &isrc->isrc_cpu);
 	}
 
 	its_cmd_movi(dev, girq);
@@ -1558,7 +1579,7 @@ its_cmd_mapti(device_t dev, struct gicv3_its_irqsrc *g
 	/* The EventID sent to the device */
 	desc.cmd_desc_mapvi.id = girq->gi_irq - girq->gi_its_dev->lpis.lpi_base;
 	/* The physical interrupt presented to softeware */
-	desc.cmd_desc_mapvi.pid = girq->gi_irq + GIC_FIRST_LPI;
+	desc.cmd_desc_mapvi.pid = girq->gi_irq + sc->sc_irq_base;
 
 	its_cmd_send(dev, &desc);
 }
@@ -1649,17 +1670,21 @@ gicv3_its_fdt_attach(device_t dev)
 	phandle_t xref;
 	int err;
 
+	sc = device_get_softc(dev);
+
+	sc->sc_irq_length = gicv3_get_nirqs(dev);
+	sc->sc_irq_base = GIC_FIRST_LPI;
+	sc->sc_irq_base += device_get_unit(dev) * sc->sc_irq_length;
+
 	err = gicv3_its_attach(dev);
 	if (err != 0)
 		return (err);
 
-	sc = device_get_softc(dev);
-
 	/* Register this device as a interrupt controller */
 	xref = OF_xref_from_node(ofw_bus_get_node(dev));
 	sc->sc_pic = intr_pic_register(dev, xref);
 	intr_pic_add_handler(device_get_parent(dev), sc->sc_pic,
-	    gicv3_its_intr, sc, GIC_FIRST_LPI, LPI_NIRQS);
+	    gicv3_its_intr, sc, sc->sc_irq_base, sc->sc_irq_length);
 
 	/* Register this device to handle MSI interrupts */
 	intr_msi_register(dev, xref);



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