[PATCH 1/2] iommu/mtk: Avoid redundant TLB syncs locally
Yong Wu
yong.wu at mediatek.com
Thu Jul 6 20:06:13 PDT 2017
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 <yong.wu at mediatek.com>
> CC: Matthias Brugger <matthias.bgg at gmail.com>
> Signed-off-by: Robin Murphy <robin.murphy at arm.com>
Thanks Robin.
Tested-by: Yong Wu <yong.wu at mediatek.com>
> ---
> 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;
> };
More information about the linux-arm-kernel
mailing list