On Thu, 2017-07-06 at 17:55 +0100, Robin Murphy wrote: > Under certain circumstances, the io-pgtable code may end up issuing two > TLB sync operations without any intervening invalidations. This goes > badly for the M4U hardware, since it means the second sync ends up > polling for a non-existent operation to finish, and as a result times > out and warns. The io_pgtable_tlb_* helpers implement a high-level > optimisation to avoid issuing the second sync at all in such cases, but > in order to work correctly that requires all pagetable operations to be > serialised under a lock, thus is no longer applicable to all io-pgtable > users. > > Since we're the only user actually relying on this flag for correctness, > let's reimplement it locally to avoid the headache of trying to make the > high-level version concurrency-safe for other users. > > CC: Yong Wu <[email protected]> > CC: Matthias Brugger <[email protected]> > Signed-off-by: Robin Murphy <[email protected]>
Thanks Robin. Tested-by: Yong Wu <[email protected]> > --- > drivers/iommu/mtk_iommu.c | 6 ++++++ > drivers/iommu/mtk_iommu.h | 1 + > 2 files changed, 7 insertions(+) > > diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c > index 5d14cd15198d..91c6d367ab35 100644 > --- a/drivers/iommu/mtk_iommu.c > +++ b/drivers/iommu/mtk_iommu.c > @@ -129,6 +129,7 @@ static void mtk_iommu_tlb_add_flush_nosync(unsigned long > iova, size_t size, > writel_relaxed(iova, data->base + REG_MMU_INVLD_START_A); > writel_relaxed(iova + size - 1, data->base + REG_MMU_INVLD_END_A); > writel_relaxed(F_MMU_INV_RANGE, data->base + REG_MMU_INVALIDATE); > + data->tlb_flush_active = true; > } > > static void mtk_iommu_tlb_sync(void *cookie) > @@ -137,6 +138,10 @@ static void mtk_iommu_tlb_sync(void *cookie) > int ret; > u32 tmp; > > + /* Avoid timing out if there's nothing to wait for */ > + if (!data->tlb_flush_active) > + return; > + > ret = readl_poll_timeout_atomic(data->base + REG_MMU_CPE_DONE, tmp, > tmp != 0, 10, 100000); > if (ret) { > @@ -146,6 +151,7 @@ static void mtk_iommu_tlb_sync(void *cookie) > } > /* Clear the CPE status */ > writel_relaxed(0, data->base + REG_MMU_CPE_DONE); > + data->tlb_flush_active = false; > } > > static const struct iommu_gather_ops mtk_iommu_gather_ops = { > diff --git a/drivers/iommu/mtk_iommu.h b/drivers/iommu/mtk_iommu.h > index 2a28eadeea0e..c06cc91b5d9a 100644 > --- a/drivers/iommu/mtk_iommu.h > +++ b/drivers/iommu/mtk_iommu.h > @@ -47,6 +47,7 @@ struct mtk_iommu_data { > struct iommu_group *m4u_group; > struct mtk_smi_iommu smi_imu; /* SMI larb iommu info */ > bool enable_4GB; > + bool tlb_flush_active; > > struct iommu_device iommu; > }; _______________________________________________ iommu mailing list [email protected] https://lists.linuxfoundation.org/mailman/listinfo/iommu
