git: 3fc4f7c88085 - main - gicv3: Split out finding the page size

From: Andrew Turner <andrew_at_FreeBSD.org>
Date: Wed, 23 Aug 2023 14:53:51 UTC
The branch main has been updated by andrew:

URL: https://cgit.FreeBSD.org/src/commit/?id=3fc4f7c88085dc94c88348839074b8db6f19fae1

commit 3fc4f7c88085dc94c88348839074b8db6f19fae1
Author:     Andrew Turner <andrew@FreeBSD.org>
AuthorDate: 2023-08-22 10:51:26 +0000
Commit:     Andrew Turner <andrew@FreeBSD.org>
CommitDate: 2023-08-23 14:29:34 +0000

    gicv3: Split out finding the page size
    
    When adding indirect (2 level) tabled we will need to know the page
    size to calculate the size of the level 1 table. To allow for this find
    the page size before entering the loop to calculate the final register
    value.
    
    Reviewed by:    gallatin, imp
    Sponsored by:   Arm Ltd
    Differential Revision:  https://reviews.freebsd.org/D41551
---
 sys/arm64/arm64/gicv3_its.c | 72 ++++++++++++++++++++++++++++++++++++---------
 1 file changed, 58 insertions(+), 14 deletions(-)

diff --git a/sys/arm64/arm64/gicv3_its.c b/sys/arm64/arm64/gicv3_its.c
index 0e2ccb5037ce..d67b19e7d345 100644
--- a/sys/arm64/arm64/gicv3_its.c
+++ b/sys/arm64/arm64/gicv3_its.c
@@ -424,6 +424,52 @@ gicv3_its_cmdq_init(struct gicv3_its_softc *sc)
 	gic_its_write_8(sc, GITS_CWRITER, 0x0);
 }
 
+static int
+gicv3_its_table_page_size(struct gicv3_its_softc *sc, int table)
+{
+	uint64_t reg, tmp;
+	int page_size;
+
+	page_size = PAGE_SIZE_64K;
+	reg = gic_its_read_8(sc, GITS_BASER(table));
+
+	while (1) {
+		reg &= GITS_BASER_PSZ_MASK;
+		switch (page_size) {
+		case PAGE_SIZE_4K:	/* 4KB */
+			reg |= GITS_BASER_PSZ_4K << GITS_BASER_PSZ_SHIFT;
+			break;
+		case PAGE_SIZE_16K:	/* 16KB */
+			reg |= GITS_BASER_PSZ_16K << GITS_BASER_PSZ_SHIFT;
+			break;
+		case PAGE_SIZE_64K:	/* 64KB */
+			reg |= GITS_BASER_PSZ_64K << GITS_BASER_PSZ_SHIFT;
+			break;
+		}
+
+		/* Write the new page size */
+		gic_its_write_8(sc, GITS_BASER(table), reg);
+
+		/* Read back to check */
+		tmp = gic_its_read_8(sc, GITS_BASER(table));
+
+		/* The page size is correct */
+		if ((tmp & GITS_BASER_PSZ_MASK) == (reg & GITS_BASER_PSZ_MASK))
+			return (page_size);
+
+		switch (page_size) {
+		default:
+			return (-1);
+		case PAGE_SIZE_16K:
+			page_size = PAGE_SIZE_4K;
+			break;
+		case PAGE_SIZE_64K:
+			page_size = PAGE_SIZE_16K;
+			break;
+		}
+	}
+}
+
 static int
 gicv3_its_table_init(device_t dev, struct gicv3_its_softc *sc)
 {
@@ -460,20 +506,30 @@ gicv3_its_table_init(device_t dev, struct gicv3_its_softc *sc)
 		cache = GITS_BASER_CACHE_WAWB;
 	}
 	share = GITS_BASER_SHARE_IS;
-	page_size = PAGE_SIZE_64K;
 
 	for (i = 0; i < GITS_BASER_NUM; i++) {
 		reg = gic_its_read_8(sc, GITS_BASER(i));
 		/* The type of table */
 		type = GITS_BASER_TYPE(reg);
+		if (type == GITS_BASER_TYPE_UNIMPL)
+			continue;
+
 		/* The table entry size */
 		esize = GITS_BASER_ESIZE(reg);
 
+		/* Find the tables page size */
+		page_size = gicv3_its_table_page_size(sc, i);
+		if (page_size == -1) {
+			device_printf(dev, "No valid page size for table %d\n",
+			    i);
+			return (EINVAL);
+		}
+
 		switch(type) {
 		case GITS_BASER_TYPE_DEV:
 			nidents = (1 << devbits);
 			its_tbl_size = esize * nidents;
-			its_tbl_size = roundup2(its_tbl_size, PAGE_SIZE_64K);
+			its_tbl_size = roundup2(its_tbl_size, page_size);
 			break;
 		case GITS_BASER_TYPE_VP:
 		case GITS_BASER_TYPE_PP: /* Undocumented? */
@@ -540,18 +596,6 @@ gicv3_its_table_init(device_t dev, struct gicv3_its_softc *sc)
 				continue;
 			}
 
-			if ((tmp & GITS_BASER_PSZ_MASK) !=
-			    (reg & GITS_BASER_PSZ_MASK)) {
-				switch (page_size) {
-				case PAGE_SIZE_16K:
-					page_size = PAGE_SIZE_4K;
-					continue;
-				case PAGE_SIZE_64K:
-					page_size = PAGE_SIZE_16K;
-					continue;
-				}
-			}
-
 			if (tmp != reg) {
 				device_printf(dev, "GITS_BASER%d: "
 				    "unable to be updated: %lx != %lx\n",