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.
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
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);