git: 50e01b6351b1 - main - arm64/smmu: Only MSI poll when cache-coherent

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

URL: https://cgit.FreeBSD.org/src/commit/?id=50e01b6351b1a4955814cce021852c65a5b5bb9f

commit 50e01b6351b1a4955814cce021852c65a5b5bb9f
Author:     Andrew Turner <andrew@FreeBSD.org>
AuthorDate: 2026-09-18 11:29:19 +0000
Commit:     Andrew Turner <andrew@FreeBSD.org>
CommitDate: 2026-09-18 11:29:19 +0000

    arm64/smmu: Only MSI poll when cache-coherent
    
    Only use the MSI polling method when we support MSIs and the SMMU is
    cache-coherent.
    
    The SMMU writes to a memory location. If it is not cache-coherent then
    the CPU may read the existing value in its cache and miss the signal
    the sync operation has completed.
    
    Sponsored by:   Arm Ltd
    Differential Revision:  https://reviews.freebsd.org/D59489
---
 sys/arm64/iommu/smmu.c     | 12 ++++++++----
 sys/arm64/iommu/smmu_fdt.c |  2 ++
 sys/arm64/iommu/smmuvar.h  |  4 ++++
 3 files changed, 14 insertions(+), 4 deletions(-)

diff --git a/sys/arm64/iommu/smmu.c b/sys/arm64/iommu/smmu.c
index 930c97a8aeb3..2b95d2f5fb3c 100644
--- a/sys/arm64/iommu/smmu.c
+++ b/sys/arm64/iommu/smmu.c
@@ -623,20 +623,23 @@ smmu_sync(struct smmu_softc *sc)
 	struct smmu_cmdq_entry cmd;
 	struct smmu_queue *q;
 	int prod;
+	bool msipoll;
 
 	q = &sc->cmdq;
 	prod = q->lc.prod;
 
+	msipoll = ((sc->options & SMMU_OPT_MSIPOLL) != 0);
+
 	/* Enqueue sync command. */
 	memset(&cmd, 0, sizeof(cmd));
 	cmd.opcode = CMD_SYNC;
-	if ((sc->features & SMMU_FEATURE_MSI) != 0) {
+	if (msipoll) {
 		cmd.sync.msiaddr = q->paddr +
 		    Q_IDX(q, prod) * CMDQ_ENTRY_DWORDS * 8;
 	}
 	smmu_cmdq_enqueue_cmd(sc, &cmd);
 
-	if ((sc->features & SMMU_FEATURE_MSI) != 0)
+	if (msipoll)
 		smmu_sync_wait_msi(sc, q);
 	else
 		smmu_sync_wait_poll(sc, q);
@@ -1356,8 +1359,6 @@ smmu_check_features(struct smmu_softc *sc)
 	uint32_t reg;
 	uint32_t val;
 
-	sc->features = 0;
-
 	reg = bus_read_4(sc->res[0], SMMU_IDR0);
 
 	if (reg & IDR0_ST_LVL_2) {
@@ -1404,6 +1405,9 @@ smmu_check_features(struct smmu_softc *sc)
 		if (bootverbose)
 			device_printf(sc->dev, "MSI feature present.\n");
 		sc->features |= SMMU_FEATURE_MSI;
+		/* Support polling if we support MSI & are cache-coherent */
+		if ((sc->features & SMMU_FEATURE_COHERENCY) != 0)
+			sc->options |= SMMU_OPT_MSIPOLL;
 	}
 
 	if (reg & IDR0_HYP) {
diff --git a/sys/arm64/iommu/smmu_fdt.c b/sys/arm64/iommu/smmu_fdt.c
index 31105054ddb2..0bd512a47d6f 100644
--- a/sys/arm64/iommu/smmu_fdt.c
+++ b/sys/arm64/iommu/smmu_fdt.c
@@ -87,6 +87,8 @@ smmu_fdt_attach(device_t dev)
 	sc->dev = dev;
 
 	node = ofw_bus_get_node(dev);
+	if (OF_hasprop(node, "dma-coherent"))
+		sc->features |= SMMU_FEATURE_COHERENCY;
 
 	rid = 0;
 	sc->res[0] = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
diff --git a/sys/arm64/iommu/smmuvar.h b/sys/arm64/iommu/smmuvar.h
index 60fad8f87531..e517e3e88ac1 100644
--- a/sys/arm64/iommu/smmuvar.h
+++ b/sys/arm64/iommu/smmuvar.h
@@ -160,6 +160,10 @@ struct smmu_softc {
 #define	SMMU_FEATURE_VAX			(1 << 13)
 #define	SMMU_FEATURE_COHERENCY			(1 << 14)
 #define	SMMU_FEATURE_RANGE_INV			(1 << 15)
+
+	uint32_t		options;
+#define	SMMU_OPT_MSIPOLL			(1 << 0)
+
 	struct smmu_queue cmdq;
 	struct smmu_queue evtq;
 	struct smmu_queue priq;