Author: andrew
Date: Fri Jan 31 10:30:13 2020
New Revision: 357324
URL: https://svnweb.freebsd.org/changeset/base/357324

Log:
  Only create one ITS configuration table
  
  When there are multiple ITS devices in the system we would allocate a
  configuration table for each, however only one table is needed as all the
  ITS devices share this.
  
  Allocate a table only when the global table is unset.
  
  While here fix the type of this to be a pointer to a uint8_t array as the
  entries are all 8 bits wide.
  
  MFC after:    2 weeks
  Sponsored by: DARPA, AFRL

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

Modified: head/sys/arm64/arm64/gicv3_its.c
==============================================================================
--- head/sys/arm64/arm64/gicv3_its.c    Fri Jan 31 09:51:38 2020        
(r357323)
+++ head/sys/arm64/arm64/gicv3_its.c    Fri Jan 31 10:30:13 2020        
(r357324)
@@ -224,6 +224,7 @@ struct its_col {
 struct gicv3_its_irqsrc {
        struct intr_irqsrc      gi_isrc;
        u_int                   gi_irq;
+       u_int                   gi_lpi;
        struct its_dev          *gi_its_dev;
 };
 
@@ -241,7 +242,7 @@ struct gicv3_its_softc {
         * TODO: We should get these from the parent as we only want a
         * single copy of each across the interrupt controller.
         */
-       vm_offset_t sc_conf_base;
+       uint8_t         *sc_conf_base;
        vm_offset_t sc_pend_base[MAXCPU];
 
        /* Command handling */
@@ -263,6 +264,8 @@ struct gicv3_its_softc {
        u_int sc_its_flags;
 };
 
+static void *conf_base;
+
 typedef void (its_quirk_func_t)(device_t);
 static its_quirk_func_t its_quirk_cavium_22375;
 
@@ -542,17 +545,29 @@ gicv3_its_table_init(device_t dev, struct gicv3_its_so
 static void
 gicv3_its_conftable_init(struct gicv3_its_softc *sc)
 {
+       void *conf_table;
 
-       sc->sc_conf_base = (vm_offset_t)contigmalloc(LPI_CONFTAB_SIZE,
-           M_GICV3_ITS, M_WAITOK, 0, LPI_CONFTAB_MAX_ADDR, LPI_CONFTAB_ALIGN,
-           0);
+       conf_table = (void *)atomic_load_ptr((uintptr_t *)&conf_base);
+       if (conf_table == NULL) {
+               conf_table = contigmalloc(LPI_CONFTAB_SIZE,
+                   M_GICV3_ITS, M_WAITOK, 0, LPI_CONFTAB_MAX_ADDR,
+                   LPI_CONFTAB_ALIGN, 0);
 
+               if (atomic_cmpset_ptr((uintptr_t *)&conf_base,
+                   (uintptr_t)NULL, (uintptr_t)conf_table) == 0) {
+                       contigfree(conf_table, LPI_CONFTAB_SIZE, M_GICV3_ITS);
+                       conf_table =
+                           (void *)atomic_load_ptr((uintptr_t *)&conf_base);
+               }
+       }
+       sc->sc_conf_base = conf_table;
+
        /* Set the default configuration */
-       memset((void *)sc->sc_conf_base, GIC_PRIORITY_MAX | LPI_CONF_GROUP1,
+       memset(sc->sc_conf_base, GIC_PRIORITY_MAX | LPI_CONF_GROUP1,
            LPI_CONFTAB_SIZE);
 
        /* Flush the table to memory */
-       cpu_dcache_wb_range(sc->sc_conf_base, LPI_CONFTAB_SIZE);
+       cpu_dcache_wb_range((vm_offset_t)sc->sc_conf_base, LPI_CONFTAB_SIZE);
 }
 
 static void
@@ -792,6 +807,7 @@ gicv3_its_attach(device_t dev)
        name = device_get_nameunit(dev);
        for (i = 0; i < sc->sc_irq_length; i++) {
                sc->sc_irqs[i].gi_irq = i;
+               sc->sc_irqs[i].gi_lpi = i + sc->sc_irq_base - GIC_FIRST_LPI;
                err = intr_isrc_register(&sc->sc_irqs[i].gi_isrc, dev, 0,
                    "%s,%u", name, i);
        }
@@ -824,13 +840,13 @@ gicv3_its_disable_intr(device_t dev, struct intr_irqsr
 
        sc = device_get_softc(dev);
        girq = (struct gicv3_its_irqsrc *)isrc;
-       conf = (uint8_t *)sc->sc_conf_base;
+       conf = sc->sc_conf_base;
 
-       conf[girq->gi_irq] &= ~LPI_CONF_ENABLE;
+       conf[girq->gi_lpi] &= ~LPI_CONF_ENABLE;
 
        if ((sc->sc_its_flags & ITS_FLAGS_LPI_CONF_FLUSH) != 0) {
                /* Clean D-cache under command. */
-               cpu_dcache_wb_range((vm_offset_t)&conf[girq->gi_irq], 1);
+               cpu_dcache_wb_range((vm_offset_t)&conf[girq->gi_lpi], 1);
        } else {
                /* DSB inner shareable, store */
                dsb(ishst);
@@ -848,13 +864,13 @@ gicv3_its_enable_intr(device_t dev, struct intr_irqsrc
 
        sc = device_get_softc(dev);
        girq = (struct gicv3_its_irqsrc *)isrc;
-       conf = (uint8_t *)sc->sc_conf_base;
+       conf = sc->sc_conf_base;
 
-       conf[girq->gi_irq] |= LPI_CONF_ENABLE;
+       conf[girq->gi_lpi] |= LPI_CONF_ENABLE;
 
        if ((sc->sc_its_flags & ITS_FLAGS_LPI_CONF_FLUSH) != 0) {
                /* Clean D-cache under command. */
-               cpu_dcache_wb_range((vm_offset_t)&conf[girq->gi_irq], 1);
+               cpu_dcache_wb_range((vm_offset_t)&conf[girq->gi_lpi], 1);
        } else {
                /* DSB inner shareable, store */
                dsb(ishst);
_______________________________________________
[email protected] mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "[email protected]"

Reply via email to