git: 182a69328da2 - main - Fix stream table entry (STE) initialization and removal. For PCI devices we have entire L1 descriptor for every session ID (SID), but for non-PCI (e.g. Display Processing Unit DPU), a single L1 descriptor serves multiple SIDs. So prevent re-initialization of L1 descriptor if already initialized. Don't free entire L1 descriptor on every STE removal.

From: Ruslan Bukin <br_at_FreeBSD.org>
Date: Wed, 18 May 2022 12:51:49 UTC
The branch main has been updated by br:

URL: https://cgit.FreeBSD.org/src/commit/?id=182a69328da2aa081f61369540f5d674c23e277b

commit 182a69328da2aa081f61369540f5d674c23e277b
Author:     Ruslan Bukin <br@FreeBSD.org>
AuthorDate: 2022-05-18 12:42:37 +0000
Commit:     Ruslan Bukin <br@FreeBSD.org>
CommitDate: 2022-05-18 12:42:37 +0000

    Fix stream table entry (STE) initialization and removal.
    For PCI devices we have entire L1 descriptor for every session ID (SID),
    but for non-PCI (e.g. Display Processing Unit DPU), a single L1
    descriptor serves multiple SIDs.
    So prevent re-initialization of L1 descriptor if already initialized.
    Don't free entire L1 descriptor on every STE removal.
    
    Sponsored by:   UKRI
---
 sys/arm64/iommu/smmu.c | 43 +++++++++++++++++++++++++++++++++++--------
 1 file changed, 35 insertions(+), 8 deletions(-)

diff --git a/sys/arm64/iommu/smmu.c b/sys/arm64/iommu/smmu.c
index ef1f96599789..5d4401c5cee9 100644
--- a/sys/arm64/iommu/smmu.c
+++ b/sys/arm64/iommu/smmu.c
@@ -776,8 +776,8 @@ smmu_init_ste_s1(struct smmu_softc *sc, struct smmu_cd *cd,
 	return (0);
 }
 
-static int
-smmu_init_ste(struct smmu_softc *sc, struct smmu_cd *cd, int sid, bool bypass)
+static uint64_t *
+smmu_get_ste_addr(struct smmu_softc *sc, int sid)
 {
 	struct smmu_strtab *strtab;
 	struct l1_desc *l1_desc;
@@ -794,6 +794,16 @@ smmu_init_ste(struct smmu_softc *sc, struct smmu_cd *cd, int sid, bool bypass)
 		    STRTAB_STE_DWORDS * 8 * sid);
 	};
 
+	return (addr);
+}
+
+static int
+smmu_init_ste(struct smmu_softc *sc, struct smmu_cd *cd, int sid, bool bypass)
+{
+	uint64_t *addr;
+
+	addr = smmu_get_ste_addr(sc, sid);
+
 	if (bypass)
 		smmu_init_ste_bypass(sc, sid, addr);
 	else
@@ -804,6 +814,21 @@ smmu_init_ste(struct smmu_softc *sc, struct smmu_cd *cd, int sid, bool bypass)
 	return (0);
 }
 
+static void
+smmu_deinit_ste(struct smmu_softc *sc, int sid)
+{
+	uint64_t *ste;
+
+	ste = smmu_get_ste_addr(sc, sid);
+	ste[0] = 0;
+
+	smmu_invalidate_sid(sc, sid);
+	smmu_sync_cd(sc, sid, 0, true);
+	smmu_invalidate_sid(sc, sid);
+
+	smmu_sync(sc);
+}
+
 static int
 smmu_init_cd(struct smmu_softc *sc, struct smmu_domain *domain)
 {
@@ -990,6 +1015,10 @@ smmu_init_l1_entry(struct smmu_softc *sc, int sid)
 
 	strtab = &sc->strtab;
 	l1_desc = &strtab->l1[sid >> STRTAB_SPLIT];
+	if (l1_desc->va) {
+		/* Already allocated. */
+		return (0);
+	}
 
 	size = 1 << (STRTAB_SPLIT + ilog2(STRTAB_STE_DWORDS) + 3);
 
@@ -1021,7 +1050,7 @@ smmu_init_l1_entry(struct smmu_softc *sc, int sid)
 	return (0);
 }
 
-static void
+static void __unused
 smmu_deinit_l1_entry(struct smmu_softc *sc, int sid)
 {
 	struct smmu_strtab *strtab;
@@ -1036,10 +1065,8 @@ smmu_deinit_l1_entry(struct smmu_softc *sc, int sid)
 	    STRTAB_L1_DESC_DWORDS * 8 * i);
 	*addr = 0;
 
-	if (sc->features & SMMU_FEATURE_2_LVL_STREAM_TABLE) {
-		l1_desc = &strtab->l1[sid >> STRTAB_SPLIT];
-		contigfree(l1_desc->va, l1_desc->size, M_SMMU);
-	}
+	l1_desc = &strtab->l1[sid >> STRTAB_SPLIT];
+	contigfree(l1_desc->va, l1_desc->size, M_SMMU);
 }
 
 static int
@@ -1883,7 +1910,7 @@ smmu_ctx_free(device_t dev, struct iommu_ctx *ioctx)
 	sc = device_get_softc(dev);
 	ctx = (struct smmu_ctx *)ioctx;
 
-	smmu_deinit_l1_entry(sc, ctx->sid);
+	smmu_deinit_ste(sc, ctx->sid);
 
 	LIST_REMOVE(ctx, next);