Module Name:    src
Committed By:   jmcneill
Date:           Sat Dec  7 19:53:07 UTC 2024

Modified Files:
        src/sys/arch/arm/cortex: gicv3_its.c gicv3_its.h

Log Message:
gicv3: ITS: Add support for indirect device tables.

When devbits is too large to fit into the first level of device table,
some hardware supports the concept of indirect tables. Add support for
this and use it when supported.

This is required for MSIs to work properly on Snapdragon X Elite platforms
(otherwise, MAPD command fails and stalls the ITS command queue).


To generate a diff of this commit:
cvs rdiff -u -r1.35 -r1.36 src/sys/arch/arm/cortex/gicv3_its.c
cvs rdiff -u -r1.8 -r1.9 src/sys/arch/arm/cortex/gicv3_its.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/arch/arm/cortex/gicv3_its.c
diff -u src/sys/arch/arm/cortex/gicv3_its.c:1.35 src/sys/arch/arm/cortex/gicv3_its.c:1.36
--- src/sys/arch/arm/cortex/gicv3_its.c:1.35	Sat Nov 11 17:35:45 2023
+++ src/sys/arch/arm/cortex/gicv3_its.c	Sat Dec  7 19:53:07 2024
@@ -1,4 +1,4 @@
-/* $NetBSD: gicv3_its.c,v 1.35 2023/11/11 17:35:45 tnn Exp $ */
+/* $NetBSD: gicv3_its.c,v 1.36 2024/12/07 19:53:07 jmcneill Exp $ */
 
 /*-
  * Copyright (c) 2018 The NetBSD Foundation, Inc.
@@ -32,7 +32,7 @@
 #define _INTR_PRIVATE
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: gicv3_its.c,v 1.35 2023/11/11 17:35:45 tnn Exp $");
+__KERNEL_RCSID(0, "$NetBSD: gicv3_its.c,v 1.36 2024/12/07 19:53:07 jmcneill Exp $");
 
 #include <sys/param.h>
 #include <sys/kmem.h>
@@ -45,9 +45,17 @@ __KERNEL_RCSID(0, "$NetBSD: gicv3_its.c,
 #include <dev/pci/pcireg.h>
 #include <dev/pci/pcivar.h>
 
+#include <machine/cpufunc.h>
+
 #include <arm/pic/picvar.h>
 #include <arm/cortex/gicv3_its.h>
 
+#ifdef ITS_DEBUG
+#define DPRINTF(x)	printf x
+#else
+#define DPRINTF(x)
+#endif
+
 /*
  * ITS translation table sizes
  */
@@ -56,6 +64,8 @@ __KERNEL_RCSID(0, "$NetBSD: gicv3_its.c,
 
 #define	GITS_ITT_ALIGN		0x100
 
+#define	GITS_INDIRECT_ENTRY_SIZE	8
+
 /*
  * IIDR values used for errata
  */
@@ -109,33 +119,42 @@ gits_write_8(struct gicv3_its *its, bus_
 	bus_space_write_8(its->its_bst, its->its_bsh, reg, val);
 }
 
-static inline void
+static int
 gits_command(struct gicv3_its *its, const struct gicv3_its_command *cmd)
 {
-	uint64_t cwriter;
+	uint64_t cwriter, creadr;
 	u_int woff;
 
+	creadr = gits_read_8(its, GITS_CREADR);
+	if (ISSET(creadr, GITS_CREADR_Stalled)) {
+		DPRINTF(("ITS: stalled! GITS_CREADR = 0x%lx\n", creadr));
+		return EIO;
+	}
+
 	cwriter = gits_read_8(its, GITS_CWRITER);
 	woff = cwriter & GITS_CWRITER_Offset;
-#ifdef DIAGNOSTIC
-	uint64_t creadr = gits_read_8(its, GITS_CREADR);
-	KASSERT(!ISSET(creadr, GITS_CREADR_Stalled));
-	KASSERT(((woff + sizeof(cmd->dw)) & (its->its_cmd.len - 1)) != (creadr & GITS_CREADR_Offset));
-#endif
 
 	uint64_t *dw = (uint64_t *)(its->its_cmd.base + woff);
-	for (int i = 0; i < __arraycount(cmd->dw); i++)
+	for (int i = 0; i < __arraycount(cmd->dw); i++) {
 		dw[i] = htole64(cmd->dw[i]);
-	bus_dmamap_sync(its->its_dmat, its->its_cmd.map, woff, sizeof(cmd->dw), BUS_DMASYNC_PREWRITE);
+		DPRINTF(("ITS:     dw[%u] = 0x%016lx\n", i, cmd->dw[i]));
+	}
+
+	if (its->its_cmd_flush) {
+		cpu_dcache_wb_range((vaddr_t)dw, sizeof(cmd->dw));
+	}
+	dsb(sy);
 
 	woff += sizeof(cmd->dw);
 	if (woff == its->its_cmd.len)
 		woff = 0;
 
 	gits_write_8(its, GITS_CWRITER, woff);
+
+	return 0;
 }
 
-static inline void
+static int
 gits_command_mapc(struct gicv3_its *its, uint16_t icid, uint64_t rdbase, bool v)
 {
 	struct gicv3_its_command cmd;
@@ -153,10 +172,13 @@ gits_command_mapc(struct gicv3_its *its,
 		cmd.dw[2] |= __BIT(63);
 	}
 
-	gits_command(its, &cmd);
+	DPRINTF(("ITS #%u: MAPC icid 0x%x rdbase 0x%lx valid %u\n",
+	    its->its_id, icid, rdbase, v));
+
+	return gits_command(its, &cmd);
 }
 
-static inline void
+static int
 gits_command_mapd(struct gicv3_its *its, uint32_t deviceid, uint64_t itt_addr, u_int size, bool v)
 {
 	struct gicv3_its_command cmd;
@@ -168,15 +190,18 @@ gits_command_mapd(struct gicv3_its *its,
 	 */
 	memset(&cmd, 0, sizeof(cmd));
 	cmd.dw[0] = GITS_CMD_MAPD | ((uint64_t)deviceid << 32);
-	cmd.dw[1] = size;
 	if (v) {
+		cmd.dw[1] = uimax(1, size) - 1;
 		cmd.dw[2] = itt_addr | __BIT(63);
 	}
 
-	gits_command(its, &cmd);
+	DPRINTF(("ITS #%u: MAPD deviceid 0x%x itt_addr 0x%lx size %u valid %u\n",
+	    its->its_id, deviceid, itt_addr, size, v));
+
+	return gits_command(its, &cmd);
 }
 
-static inline void
+static int
 gits_command_mapti(struct gicv3_its *its, uint32_t deviceid, uint32_t eventid, uint32_t pintid, uint16_t icid)
 {
 	struct gicv3_its_command cmd;
@@ -190,10 +215,13 @@ gits_command_mapti(struct gicv3_its *its
 	cmd.dw[1] = eventid | ((uint64_t)pintid << 32);
 	cmd.dw[2] = icid;
 
-	gits_command(its, &cmd);
+	DPRINTF(("ITS #%u: MAPTI deviceid 0x%x eventid 0x%x pintid 0x%x icid 0x%x\n",
+	    its->its_id, deviceid, eventid, pintid, icid));
+
+	return gits_command(its, &cmd);
 }
 
-static inline void
+static int
 gits_command_movi(struct gicv3_its *its, uint32_t deviceid, uint32_t eventid, uint16_t icid)
 {
 	struct gicv3_its_command cmd;
@@ -207,10 +235,13 @@ gits_command_movi(struct gicv3_its *its,
 	cmd.dw[1] = eventid;
 	cmd.dw[2] = icid;
 
-	gits_command(its, &cmd);
+	DPRINTF(("ITS #%u: MOVI deviceid 0x%x eventid 0x%x icid 0x%x\n",
+	    its->its_id, deviceid, eventid, icid));
+
+	return gits_command(its, &cmd);
 }
 
-static inline void
+static int
 gits_command_inv(struct gicv3_its *its, uint32_t deviceid, uint32_t eventid)
 {
 	struct gicv3_its_command cmd;
@@ -223,10 +254,13 @@ gits_command_inv(struct gicv3_its *its, 
 	cmd.dw[0] = GITS_CMD_INV | ((uint64_t)deviceid << 32);
 	cmd.dw[1] = eventid;
 
-	gits_command(its, &cmd);
+	DPRINTF(("ITS #%u: INV deviceid 0x%x eventid 0x%x\n",
+	    its->its_id, deviceid, eventid));
+
+	return gits_command(its, &cmd);
 }
 
-static inline void
+static int
 gits_command_invall(struct gicv3_its *its, uint16_t icid)
 {
 	struct gicv3_its_command cmd;
@@ -239,10 +273,12 @@ gits_command_invall(struct gicv3_its *it
 	cmd.dw[0] = GITS_CMD_INVALL;
 	cmd.dw[2] = icid;
 
-	gits_command(its, &cmd);
+	DPRINTF(("ITS #%u: INVALL icid 0x%x\n", its->its_id, icid));
+
+	return gits_command(its, &cmd);
 }
 
-static inline void
+static int
 gits_command_sync(struct gicv3_its *its, uint64_t rdbase)
 {
 	struct gicv3_its_command cmd;
@@ -258,11 +294,13 @@ gits_command_sync(struct gicv3_its *its,
 	cmd.dw[0] = GITS_CMD_SYNC;
 	cmd.dw[2] = rdbase;
 
-	gits_command(its, &cmd);
+	DPRINTF(("ITS #%u: SYNC rdbase 0x%lx\n", its->its_id, rdbase));
+
+	return gits_command(its, &cmd);
 }
 
 #if 0
-static inline void
+static int
 gits_command_int(struct gicv3_its *its, uint32_t deviceid, uint32_t eventid)
 {
 	struct gicv3_its_command cmd;
@@ -277,11 +315,14 @@ gits_command_int(struct gicv3_its *its, 
 	cmd.dw[0] = GITS_CMD_INT | ((uint64_t)deviceid << 32);
 	cmd.dw[1] = eventid;
 
-	gits_command(its, &cmd);
+	DPRINTF(("ITS #%u: INT deviceid 0x%x eventid 0x%x\n",
+	    its->its_id, deviceid, eventid));
+
+	return gits_command(its, &cmd);
 }
 #endif
 
-static inline int
+static int
 gits_wait(struct gicv3_its *its)
 {
 	u_int woff, roff;
@@ -299,7 +340,9 @@ gits_wait(struct gicv3_its *its)
 		delay(100);
 	}
 	if (retry == 0) {
-		device_printf(its->its_gic->sc_dev, "ITS command queue timeout\n");
+		device_printf(its->its_gic->sc_dev,
+		    "ITS command queue timeout! CREADR=0x%lx CWRITER=0x%lx\n",
+		    gits_read_8(its, GITS_CREADR), gits_read_8(its, GITS_CWRITER));
 		return ETIMEDOUT;
 	}
 
@@ -358,7 +401,9 @@ static int
 gicv3_its_device_map(struct gicv3_its *its, uint32_t devid, u_int count)
 {
 	struct gicv3_its_device *dev;
+	struct gicv3_its_table *itstab = &its->its_tab_device;
 	u_int vectors;
+	int error;
 
 	vectors = MAX(2, count);
 	while (!powerof2(vectors))
@@ -366,29 +411,62 @@ gicv3_its_device_map(struct gicv3_its *i
 
 	const uint64_t typer = gits_read_8(its, GITS_TYPER);
 	const u_int itt_entry_size = __SHIFTOUT(typer, GITS_TYPER_ITT_entry_size) + 1;
-	const u_int itt_size = roundup(vectors * itt_entry_size, GITS_ITT_ALIGN);
+	const u_int itt_size = roundup(uimax(vectors, 2) * itt_entry_size, GITS_ITT_ALIGN);
 
 	LIST_FOREACH(dev, &its->its_devices, dev_list)
 		if (dev->dev_id == devid) {
 			return itt_size <= dev->dev_size ? 0 : EEXIST;
 		}
 
+	if (itstab->tab_indirect) {
+		/* Need to allocate the L2 table. */
+		uint64_t *l1_tab = itstab->tab_l1;
+		struct gicv3_its_page_table *pt;
+		const u_int index = devid / itstab->tab_l2_num_ids;
+
+		pt = kmem_alloc(sizeof(*pt), KM_SLEEP);
+		pt->pt_dev_id = devid;
+		gicv3_dma_alloc(its->its_gic, &pt->pt_dma, itstab->tab_l2_entry_size,
+		    itstab->tab_page_size);
+		LIST_INSERT_HEAD(&itstab->tab_pt, pt, pt_list);
+
+		if (!itstab->tab_shareable) {
+			cpu_dcache_wb_range((vaddr_t)pt->pt_dma.base,
+			    itstab->tab_l2_entry_size);
+		}
+		l1_tab[index] = pt->pt_dma.segs[0].ds_addr | GITS_BASER_Valid;
+		if (!itstab->tab_shareable) {
+			cpu_dcache_wb_range((vaddr_t)&l1_tab[index],
+			    sizeof(l1_tab[index]));
+		}
+		dsb(sy);
+
+		DPRINTF(("ITS: Allocated L2 entry at index %u for devid 0x%x\n",
+		    index, devid));
+	}
+
 	dev = kmem_alloc(sizeof(*dev), KM_SLEEP);
 	dev->dev_id = devid;
 	dev->dev_size = itt_size;
 	gicv3_dma_alloc(its->its_gic, &dev->dev_itt, itt_size, GITS_ITT_ALIGN);
-	LIST_INSERT_HEAD(&its->its_devices, dev, dev_list);
+
+	if (its->its_cmd_flush) {
+		cpu_dcache_wb_range((vaddr_t)dev->dev_itt.base, itt_size);
+	}
+	dsb(sy);
 
 	/*
 	 * Map the device to the ITT
 	 */
-	const u_int id_bits = __SHIFTOUT(typer, GITS_TYPER_ID_bits) + 1;
+	const u_int size = uimax(1, fls32(vectors));
 	mutex_enter(its->its_lock);
-	gits_command_mapd(its, devid, dev->dev_itt.segs[0].ds_addr, id_bits - 1, true);
-	gits_wait(its);
+	error = gits_command_mapd(its, devid, dev->dev_itt.segs[0].ds_addr, size, true);
+	if (error == 0) {
+		error = gits_wait(its);
+	}
 	mutex_exit(its->its_lock);
 
-	return 0;
+	return error;
 }
 
 static void
@@ -497,7 +575,7 @@ gicv3_its_msi_alloc(struct arm_pci_msi *
 	struct gicv3_its * const its = msi->msi_priv;
 	struct cpu_info * const ci = cpu_lookup(0);
 	pci_intr_handle_t *vectors;
-	int n, off;
+	int n, off, error;
 
 	if (!pci_get_capability(pa->pa_pc, pa->pa_tag, PCI_CAP_MSI, &off, NULL))
 		return NULL;
@@ -537,9 +615,14 @@ gicv3_its_msi_alloc(struct arm_pci_msi *
 		gits_command_mapti(its, devid, lpi - its->its_pic->pic_irqbase, lpi, cpu_index(ci));
 		gits_command_sync(its, its->its_rdbase[cpu_index(ci)]);
 	}
-	gits_wait(its);
+	error = gits_wait(its);
 	mutex_exit(its->its_lock);
 
+	if (error != 0) {
+		kmem_free(vectors, sizeof(*vectors) * *count);
+		vectors = NULL;
+	}
+
 	return vectors;
 }
 
@@ -668,21 +751,39 @@ gicv3_its_msi_intr_release(struct arm_pc
 static void
 gicv3_its_command_init(struct gicv3_softc *sc, struct gicv3_its *its)
 {
-	uint64_t cbaser;
+	uint64_t cbaser, tmp;
 
 	gicv3_dma_alloc(sc, &its->its_cmd, GITS_COMMANDS_SIZE, GITS_COMMANDS_ALIGN);
+	if (its->its_cmd_flush) {
+		cpu_dcache_wb_range((vaddr_t)its->its_cmd.base, GITS_COMMANDS_SIZE);
+	}
+	dsb(sy);
 
 	KASSERT((gits_read_4(its, GITS_CTLR) & GITS_CTLR_Enabled) == 0);
 	KASSERT((gits_read_4(its, GITS_CTLR) & GITS_CTLR_Quiescent) != 0);
 
 	cbaser = its->its_cmd.segs[0].ds_addr;
-	cbaser |= __SHIFTIN(GITS_Cache_NORMAL_NC, GITS_CBASER_InnerCache);
-	cbaser |= __SHIFTIN(GITS_Shareability_NS, GITS_CBASER_Shareability);
 	cbaser |= __SHIFTIN((its->its_cmd.len / 4096) - 1, GITS_CBASER_Size);
 	cbaser |= GITS_CBASER_Valid;
 
-	gits_write_8(its, GITS_CWRITER, 0);
+	cbaser |= __SHIFTIN(GITS_Cache_NORMAL_WA_WB, GITS_CBASER_InnerCache);
+	cbaser |= __SHIFTIN(GITS_Shareability_IS, GITS_CBASER_Shareability);
 	gits_write_8(its, GITS_CBASER, cbaser);
+
+	tmp = gits_read_8(its, GITS_CBASER);
+	if (__SHIFTOUT(tmp, GITS_CBASER_Shareability) != GITS_Shareability_IS) {
+		if (__SHIFTOUT(tmp, GITS_CBASER_InnerCache) == GITS_Shareability_NS) {
+			cbaser &= ~GITS_CBASER_InnerCache;
+			cbaser |= __SHIFTIN(GITS_Cache_NORMAL_NC, GITS_CBASER_InnerCache);
+			cbaser &= ~GITS_CBASER_Shareability;
+			cbaser |= __SHIFTIN(GITS_Shareability_NS, GITS_CBASER_Shareability);
+			gits_write_8(its, GITS_CBASER, cbaser);
+		}
+
+		its->its_cmd_flush = true;
+	}
+
+	gits_write_8(its, GITS_CWRITER, 0);
 }
 
 static void
@@ -706,10 +807,64 @@ gicv3_its_table_params(struct gicv3_soft
 	}
 }
 
+static u_int
+gicv3_its_probe_page_size(struct gicv3_its *its, int tab)
+{
+	uint64_t baser, tmp;
+	u_int page_size = 65536;
+
+	baser = gits_read_8(its, GITS_BASERn(tab));
+	for (;;) {
+		baser &= ~GITS_BASER_Page_Size;
+		switch (page_size) {
+		case 4096:
+			baser |= __SHIFTIN(GITS_Page_Size_4KB, GITS_BASER_Page_Size);
+			break;
+		case 16384:
+			baser |= __SHIFTIN(GITS_Page_Size_16KB, GITS_BASER_Page_Size);
+			break;
+		case 65536:
+			baser |= __SHIFTIN(GITS_Page_Size_64KB, GITS_BASER_Page_Size);
+			break;
+		}
+
+		gits_write_8(its, GITS_BASERn(tab), baser);
+		tmp = gits_read_8(its, GITS_BASERn(tab));
+		if ((baser & GITS_BASER_Page_Size) == (tmp & GITS_BASER_Page_Size)) {
+			return page_size;
+		}
+
+		if (page_size == 65536) {
+			page_size = 16384;
+		} else if (page_size == 16384) {
+			page_size = 4096;
+		} else {
+			aprint_error_dev(its->its_gic->sc_dev,
+			    "WARNING: Couldn't determine ITS page size, "
+			    "defaulting to 4KB\n");
+			return page_size;
+		}
+	}
+}
+
+static bool
+gicv3_its_table_probe_indirect(struct gicv3_its *its, int tab)
+{
+	uint64_t baser;
+
+	baser = gits_read_8(its, GITS_BASERn(tab));
+	baser |= GITS_BASER_Indirect;
+	gits_write_8(its, GITS_BASERn(tab), baser);
+
+	baser = gits_read_8(its, GITS_BASERn(tab));
+
+	return (baser & GITS_BASER_Indirect) != 0;
+}
+
 static void
 gicv3_its_table_init(struct gicv3_softc *sc, struct gicv3_its *its)
 {
-	u_int table_size, page_size, table_align;
+	u_int page_size, table_align;
 	u_int devbits, innercache, share;
 	const char *table_type;
 	uint64_t baser;
@@ -717,40 +872,64 @@ gicv3_its_table_init(struct gicv3_softc 
 
 	gicv3_its_table_params(sc, its, &devbits, &innercache, &share);
 
+	DPRINTF(("ITS: devbits = %u\n", devbits));
+
 	for (tab = 0; tab < 8; tab++) {
+		struct gicv3_its_table *itstab;
+		bool indirect = false;
+		uint64_t l1_entry_size, l2_entry_size;
+		uint64_t l1_num_ids, l2_num_ids;
+		uint64_t table_size;
+
 		baser = gits_read_8(its, GITS_BASERn(tab));
 
-		const u_int entry_size = __SHIFTOUT(baser, GITS_BASER_Entry_Size) + 1;
+		l1_entry_size = __SHIFTOUT(baser, GITS_BASER_Entry_Size) + 1;
+		l2_entry_size = 0;
+		l2_num_ids = 0;
 
-		switch (__SHIFTOUT(baser, GITS_BASER_Page_Size)) {
-		case GITS_Page_Size_4KB:
-			page_size = 4096;
-			table_align = 4096;
-			break;
-		case GITS_Page_Size_16KB:
-			page_size = 16384;
-			table_align = 16384;
-			break;
-		case GITS_Page_Size_64KB:
-		default:
-			page_size = 65536;
-			table_align = 65536;
-			break;
-		}
+		page_size = gicv3_its_probe_page_size(its, tab);
+		table_align = 65536; // why not
 
 		switch (__SHIFTOUT(baser, GITS_BASER_Type)) {
 		case GITS_Type_Devices:
 			/*
 			 * Table size scales with the width of the DeviceID.
 			 */
-			table_size = roundup(entry_size * (1 << devbits), page_size);
+			l1_num_ids = 1ULL << devbits;
+			DPRINTF(("ITS: l1_num_ids = %lu\n", l1_num_ids));
+			indirect =
+			    gicv3_its_table_probe_indirect(its, tab);
+			if (indirect) {
+				DPRINTF(("ITS: indirect\n"));
+				l2_entry_size = l1_entry_size;
+				l2_num_ids = page_size / l2_entry_size;
+				l1_num_ids = l1_num_ids / l2_num_ids;
+				l1_entry_size = GITS_INDIRECT_ENTRY_SIZE;
+			}
+			table_size = roundup2(l1_entry_size * l1_num_ids, page_size);
+			if (howmany(table_size, page_size) > GITS_BASER_Size + 1) {
+				DPRINTF(("ITS: clamp table size 0x%lx -> ", table_size));
+				table_size = (GITS_BASER_Size + 1) * page_size;
+				DPRINTF(("0x%lx\n", table_size));
+			}
 			table_type = "Devices";
+
+			DPRINTF(("ITS: table_size is 0x%lx\n", table_size));
+
+			itstab = &its->its_tab_device;
+			itstab->tab_page_size = page_size;
+			itstab->tab_l1_entry_size = l1_entry_size;
+			itstab->tab_l1_num_ids = l1_num_ids;
+			itstab->tab_l2_entry_size = l2_entry_size;
+			itstab->tab_l2_num_ids = l2_num_ids;
+			itstab->tab_indirect = indirect;
+			LIST_INIT(&itstab->tab_pt);
 			break;
 		case GITS_Type_InterruptCollections:
 			/*
 			 * Allocate space for one interrupt collection per CPU.
 			 */
-			table_size = roundup(entry_size * ncpu, page_size);
+			table_size = roundup(l1_entry_size * ncpu, page_size);
 			table_type = "Collections";
 			break;
 		default:
@@ -762,9 +941,13 @@ gicv3_its_table_init(struct gicv3_softc 
 			continue;
 
 		gicv3_dma_alloc(sc, &its->its_tab[tab], table_size, table_align);
+		if (its->its_cmd_flush) {
+			cpu_dcache_wb_range((vaddr_t)its->its_tab[tab].base, table_size);
+		}
+		dsb(sy);
 
 		baser &= ~GITS_BASER_Size;
-		baser |= __SHIFTIN(table_size / page_size - 1, GITS_BASER_Size);
+		baser |= __SHIFTIN(howmany(table_size, page_size) - 1, GITS_BASER_Size);
 		baser &= ~GITS_BASER_Physical_Address;
 		baser |= its->its_tab[tab].segs[0].ds_addr;
 		baser &= ~GITS_BASER_InnerCache;
@@ -772,6 +955,11 @@ gicv3_its_table_init(struct gicv3_softc 
 		baser &= ~GITS_BASER_Shareability;
 		baser |= __SHIFTIN(share, GITS_BASER_Shareability);
 		baser |= GITS_BASER_Valid;
+		if (indirect) {
+			baser |= GITS_BASER_Indirect;
+		} else {
+			baser &= ~GITS_BASER_Indirect;
+		}
 
 		gits_write_8(its, GITS_BASERn(tab), baser);
 
@@ -784,10 +972,18 @@ gicv3_its_table_init(struct gicv3_softc 
 		}
 
 		baser = gits_read_8(its, GITS_BASERn(tab));
-		aprint_normal_dev(sc->sc_dev, "ITS [#%d] %s table @ %#lx/%#x, %s, %s\n",
+		aprint_normal_dev(sc->sc_dev, "ITS [#%d] %s table @ %#lx/%#lx, %s, %s%s\n",
 		    tab, table_type, its->its_tab[tab].segs[0].ds_addr, table_size,
 		    gits_cache_type[__SHIFTOUT(baser, GITS_BASER_InnerCache)],
-		    gits_share_type[__SHIFTOUT(baser, GITS_BASER_Shareability)]);
+		    gits_share_type[__SHIFTOUT(baser, GITS_BASER_Shareability)],
+		    indirect ? ", indirect" : "");
+
+		if (__SHIFTOUT(baser, GITS_BASER_Type) == GITS_Type_Devices) {
+			its->its_tab_device.tab_l1 = its->its_tab[tab].base;
+			its->its_tab_device.tab_shareable =
+			    __SHIFTOUT(baser, GITS_BASER_Shareability) != GITS_Shareability_NS;
+		}
+
 	}
 }
 

Index: src/sys/arch/arm/cortex/gicv3_its.h
diff -u src/sys/arch/arm/cortex/gicv3_its.h:1.8 src/sys/arch/arm/cortex/gicv3_its.h:1.9
--- src/sys/arch/arm/cortex/gicv3_its.h:1.8	Sun Oct 31 16:23:47 2021
+++ src/sys/arch/arm/cortex/gicv3_its.h	Sat Dec  7 19:53:07 2024
@@ -1,4 +1,4 @@
-/* $NetBSD: gicv3_its.h,v 1.8 2021/10/31 16:23:47 skrll Exp $ */
+/* $NetBSD: gicv3_its.h,v 1.9 2024/12/07 19:53:07 jmcneill Exp $ */
 
 /*-
  * Copyright (c) 2018 The NetBSD Foundation, Inc.
@@ -46,6 +46,25 @@ struct gicv3_its_device {
 	LIST_ENTRY(gicv3_its_device) dev_list;
 };
 
+struct gicv3_its_page_table {
+	uint32_t		pt_dev_id;
+	struct gicv3_dma	pt_dma;
+	LIST_ENTRY(gicv3_its_page_table) pt_list;
+};
+
+struct gicv3_its_table {
+	void			*tab_l1;
+	uint32_t		tab_page_size;
+	uint64_t		tab_l1_entry_size;
+	uint64_t		tab_l1_num_ids;
+	uint64_t		tab_l2_entry_size;
+	uint64_t		tab_l2_num_ids;
+	bool			tab_indirect;
+	bool			tab_shareable;
+
+	LIST_HEAD(, gicv3_its_page_table) tab_pt;
+};
+
 struct gicv3_its {
 	bus_space_tag_t		its_bst;
 	bus_space_handle_t	its_bsh;
@@ -68,6 +87,10 @@ struct gicv3_its {
 	struct gicv3_dma	its_cmd;		/* Command queue */
 	struct gicv3_dma	its_tab[8];		/* ITS tables */
 
+	struct gicv3_its_table	its_tab_device;
+
+	bool			its_cmd_flush;
+
 	struct arm_pci_msi	its_msi;
 
 	kmutex_t		*its_lock;

Reply via email to