From owner-svn-src-all@freebsd.org Sun Aug 13 18:54:52 2017 Return-Path: Delivered-To: svn-src-all@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 9A869DD298A; Sun, 13 Aug 2017 18:54:52 +0000 (UTC) (envelope-from andrew@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 7469A7E9CC; Sun, 13 Aug 2017 18:54:52 +0000 (UTC) (envelope-from andrew@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id v7DIspA3014934; Sun, 13 Aug 2017 18:54:51 GMT (envelope-from andrew@FreeBSD.org) Received: (from andrew@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id v7DIspAC014931; Sun, 13 Aug 2017 18:54:51 GMT (envelope-from andrew@FreeBSD.org) Message-Id: <201708131854.v7DIspAC014931@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: andrew set sender to andrew@FreeBSD.org using -f From: Andrew Turner Date: Sun, 13 Aug 2017 18:54:51 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r322470 - head/sys/arm64/arm64 X-SVN-Group: head X-SVN-Commit-Author: andrew X-SVN-Commit-Paths: head/sys/arm64/arm64 X-SVN-Commit-Revision: 322470 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 13 Aug 2017 18:54:52 -0000 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);