Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 31 Jan 2020 10:30:13 +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: r357324 - head/sys/arm64/arm64
Message-ID:  <202001311030.00VAUDTU024205@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
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);



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