git: 0689a5ea451b - main - arm64/smmu: Support polling for sync completion

From: Andrew Turner <andrew_at_FreeBSD.org>
Date: Mon, 21 Sep 2026 15:26:10 UTC
The branch main has been updated by andrew:

URL: https://cgit.FreeBSD.org/src/commit/?id=0689a5ea451bdef62f7e81ffb3e5f580c5c99b2b

commit 0689a5ea451bdef62f7e81ffb3e5f580c5c99b2b
Author:     Andrew Turner <andrew@FreeBSD.org>
AuthorDate: 2026-09-18 11:29:02 +0000
Commit:     Andrew Turner <andrew@FreeBSD.org>
CommitDate: 2026-09-18 11:29:02 +0000

    arm64/smmu: Support polling for sync completion
    
    When the hardware doesn't support MSIs we need to poll to wait for
    sync operations to complete. Add support for this to support booting
    on this hardware.
    
    Sponsored by:   Arm Ltd
    Differential Revision:  https://reviews.freebsd.org/D59488
---
 sys/arm64/iommu/smmu.c | 39 +++++++++++++++++++++++++++++++++++----
 1 file changed, 35 insertions(+), 4 deletions(-)

diff --git a/sys/arm64/iommu/smmu.c b/sys/arm64/iommu/smmu.c
index d5f79c9a2801..930c97a8aeb3 100644
--- a/sys/arm64/iommu/smmu.c
+++ b/sys/arm64/iommu/smmu.c
@@ -245,7 +245,7 @@ smmu_q_empty(struct smmu_queue *q)
 	return (0);
 }
 
-static int __unused
+static int
 smmu_q_consumed(struct smmu_queue *q, uint32_t prod)
 {
 
@@ -254,7 +254,7 @@ smmu_q_consumed(struct smmu_queue *q, uint32_t prod)
 		return (1);
 
 	if ((Q_WRP(q, q->lc.cons) != Q_WRP(q, prod)) &&
-	    (Q_IDX(q, q->lc.cons) <= Q_IDX(q, prod)))
+	    (Q_IDX(q, q->lc.cons) < Q_IDX(q, prod)))
 		return (1);
 
 	return (0);
@@ -567,6 +567,30 @@ smmu_poll_until_consumed(struct smmu_softc *sc, struct smmu_queue *q)
 	}
 }
 
+static void
+smmu_sync_wait_poll(struct smmu_softc *sc, struct smmu_queue *q)
+{
+	sbintime_t start;
+	int prod;
+
+	prod = q->lc.prod;
+
+	start = getsbinuptime();
+	do {
+		if (smmu_q_consumed(q, prod))
+			return;
+		if ((sc->features & SMMU_FEATURE_SEV) != 0)
+			wfe();
+		else
+			DELAY(100);
+
+		q->lc.cons = bus_read_4(sc->res[0], q->cons_off);
+	} while ((getsbinuptime() - start) < SBT_1S);
+
+	if (!smmu_q_consumed(q, prod))
+		device_printf(sc->dev, "Failed to sync\n");
+}
+
 static void
 smmu_sync_wait_msi(struct smmu_softc *sc, struct smmu_queue *q)
 {
@@ -604,11 +628,18 @@ smmu_sync(struct smmu_softc *sc)
 	prod = q->lc.prod;
 
 	/* Enqueue sync command. */
+	memset(&cmd, 0, sizeof(cmd));
 	cmd.opcode = CMD_SYNC;
-	cmd.sync.msiaddr = q->paddr + Q_IDX(q, prod) * CMDQ_ENTRY_DWORDS * 8;
+	if ((sc->features & SMMU_FEATURE_MSI) != 0) {
+		cmd.sync.msiaddr = q->paddr +
+		    Q_IDX(q, prod) * CMDQ_ENTRY_DWORDS * 8;
+	}
 	smmu_cmdq_enqueue_cmd(sc, &cmd);
 
-	smmu_sync_wait_msi(sc, q);
+	if ((sc->features & SMMU_FEATURE_MSI) != 0)
+		smmu_sync_wait_msi(sc, q);
+	else
+		smmu_sync_wait_poll(sc, q);
 
 	return (0);
 }