aboutsummaryrefslogtreecommitdiff
path: root/sys/arm64
diff options
context:
space:
mode:
authorAndrew Turner <andrew@FreeBSD.org>2020-01-31 10:30:13 +0000
committerAndrew Turner <andrew@FreeBSD.org>2020-01-31 10:30:13 +0000
commite93448dd69855d6f3d072091676809e882be25a7 (patch)
treeb5b7b9ff4d6663c70779b706edc626e173bbb9a3 /sys/arm64
parent45951bf0a941ff2dcb072dd55a71bd8a6dfe890d (diff)
downloadsrc-e93448dd69855d6f3d072091676809e882be25a7.tar.gz
src-e93448dd69855d6f3d072091676809e882be25a7.zip
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
Notes
Notes: svn path=/head/; revision=357324
Diffstat (limited to 'sys/arm64')
-rw-r--r--sys/arm64/arm64/gicv3_its.c42
1 files changed, 29 insertions, 13 deletions
diff --git a/sys/arm64/arm64/gicv3_its.c b/sys/arm64/arm64/gicv3_its.c
index ec5c0ebab34a..dcc0fdf160a7 100644
--- a/sys/arm64/arm64/gicv3_its.c
+++ b/sys/arm64/arm64/gicv3_its.c
@@ -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_softc *sc)
static void
gicv3_its_conftable_init(struct gicv3_its_softc *sc)
{
-
- 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);
+ void *conf_table;
+
+ 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_irqsrc *isrc)
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 *isrc)
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);