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);
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to