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
This commit is contained in:
Ruslan Bukin 2022-05-18 13:42:37 +01:00
parent ed87ff4e95
commit 182a69328d

View File

@ -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);