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

Reply via email to