Hi Will,

On 7/4/17 10:31 AM, Will Deacon wrote:
> Ray,
> 
> On Wed, Jun 28, 2017 at 10:02:35AM -0700, Ray Jui wrote:
>> On 6/28/17 4:46 AM, Will Deacon wrote:
>>> Robin and I have been bashing our heads against the tlb_sync_pending flag
>>> this morning, and we reckon it could have something to do with your timeouts
>>> on MMU-500.
>>>
>>> On Tue, Jun 27, 2017 at 09:43:19AM -0700, Ray Jui wrote:
>>>>>> Also, in a few occasions, I observed the following message during the
>>>>>> test, when multiple cores are involved:
>>>>>>
>>>>>> arm-smmu 64000000.mmu: TLB sync timed out -- SMMU may be deadlocked
>>>
>>> The tlb_sync_pending logic was written under the assumption of a global
>>> page-table lock, so it assumes that it only has to care about syncing
>>> flushes from the current CPU/context. That's not true anymore, and the
>>> current code can accidentally skip syncs and (what I think is happening in
>>> your case) allow concurrent syncs, which will potentially lead to timeouts
>>> if a CPU is unlucky enough to keep missing the Ack.
>>>
>>> Please can you try the diff below and see if it fixes things for you?
>>> This applies on top of my for-joerg/arm-smmu/updates branch, but note
>>> that I've only shown it to the compiler. Not tested at all.
>>>
>>> Will
>>>
>>
>> Thanks for looking into this. I'm a bit busy at work but will certainly
>> find time to test the diff below. I hopefully will get to it later this
>> week.
> 
> It would be really handy if you could test this, since I think it could
> cause some nasty problems if we don't get it fixed. Updated patch (with
> commit message) below.
> 
> Will

Yes I understand. Sorry I was way too busy last week and could not get
to it. Will definitely find time to test this ASAP.

Regards,

Ray

> 
> --->8
> 
> From eeb11dab63fcdd698b671a3a8c63516005caa9ec Mon Sep 17 00:00:00 2001
> From: Will Deacon <will.dea...@arm.com>
> Date: Thu, 29 Jun 2017 15:08:09 +0100
> Subject: [PATCH] iommu/io-pgtable: Fix tlb_sync_pending flag access from
>  concurrent CPUs
> 
> The tlb_sync_pending flag is used to elide back-to-back TLB sync operations
> for two reasons:
> 
>   1. TLB sync operations can be expensive, and so avoiding them where we
>      can is a good idea.
> 
>   2. Some hardware (mtk_iommu) locks up if it sees a TLB sync without an
>      unsync'd TLB flush preceding it
> 
> The flag is set on an ->add_flush callback and cleared on a ->sync callback,
> which worked nicely when all map/unmap operations where protected by a
> global lock.
> 
> Unfortunately, moving to a lockless implementation means that we suddenly
> have races on the flag: updates can go missing and we can end up with
> back-to-back syncs once again.
> 
> This patch resolves the problem by making the tlb_sync_pending flag an
> atomic_t and sorts out the ordering with respect to TLB callbacks.
> Now, the flag is set with release semantics after adding a flush and
> checked with an xchg operation (and subsequent control dependency) when
> performing the sync. We could consider using a cmpxchg here, but we'll
> likely just hit our local update to the flag anyway.
> 
> Cc: Ray Jui <ray....@broadcom.com>
> Cc: Robin Murphy <robin.mur...@arm.com>
> Fixes: 2c3d273eabe8 ("iommu/io-pgtable-arm: Support lockless operation")
> Signed-off-by: Will Deacon <will.dea...@arm.com>
> ---
>  drivers/iommu/io-pgtable.c |  1 +
>  drivers/iommu/io-pgtable.h | 12 ++++++------
>  2 files changed, 7 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/iommu/io-pgtable.c b/drivers/iommu/io-pgtable.c
> index 127558d83667..cd8d7aaec161 100644
> --- a/drivers/iommu/io-pgtable.c
> +++ b/drivers/iommu/io-pgtable.c
> @@ -59,6 +59,7 @@ struct io_pgtable_ops *alloc_io_pgtable_ops(enum 
> io_pgtable_fmt fmt,
>       iop->cookie     = cookie;
>       iop->cfg        = *cfg;
>  
> +     atomic_set(&iop->tlb_sync_pending, 0);
>       return &iop->ops;
>  }
>  
> diff --git a/drivers/iommu/io-pgtable.h b/drivers/iommu/io-pgtable.h
> index 524263a7ae6f..b64580c9d03d 100644
> --- a/drivers/iommu/io-pgtable.h
> +++ b/drivers/iommu/io-pgtable.h
> @@ -1,5 +1,7 @@
>  #ifndef __IO_PGTABLE_H
>  #define __IO_PGTABLE_H
> +
> +#include <linux/atomic.h>
>  #include <linux/bitops.h>
>  
>  /*
> @@ -165,7 +167,7 @@ void free_io_pgtable_ops(struct io_pgtable_ops *ops);
>  struct io_pgtable {
>       enum io_pgtable_fmt     fmt;
>       void                    *cookie;
> -     bool                    tlb_sync_pending;
> +     atomic_t                tlb_sync_pending;
>       struct io_pgtable_cfg   cfg;
>       struct io_pgtable_ops   ops;
>  };
> @@ -175,22 +177,20 @@ struct io_pgtable {
>  static inline void io_pgtable_tlb_flush_all(struct io_pgtable *iop)
>  {
>       iop->cfg.tlb->tlb_flush_all(iop->cookie);
> -     iop->tlb_sync_pending = true;
> +     atomic_set_release(&iop->tlb_sync_pending, 1);
>  }
>  
>  static inline void io_pgtable_tlb_add_flush(struct io_pgtable *iop,
>               unsigned long iova, size_t size, size_t granule, bool leaf)
>  {
>       iop->cfg.tlb->tlb_add_flush(iova, size, granule, leaf, iop->cookie);
> -     iop->tlb_sync_pending = true;
> +     atomic_set_release(&iop->tlb_sync_pending, 1);
>  }
>  
>  static inline void io_pgtable_tlb_sync(struct io_pgtable *iop)
>  {
> -     if (iop->tlb_sync_pending) {
> +     if (atomic_xchg_relaxed(&iop->tlb_sync_pending, 0))
>               iop->cfg.tlb->tlb_sync(iop->cookie);
> -             iop->tlb_sync_pending = false;
> -     }
>  }
>  
>  /**
> 
_______________________________________________
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

Reply via email to