linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2] CHROMIUM: iommu: rockchip: Make sure that page table state is coherent
@ 2015-04-20 11:43 Tomasz Figa
  2015-04-23  9:09 ` Daniel Kurtz
  0 siblings, 1 reply; 3+ messages in thread
From: Tomasz Figa @ 2015-04-20 11:43 UTC (permalink / raw)
  To: linux-arm-kernel

To flush created mappings, current mapping code relies on the fact that
during unmap the driver zaps every IOVA being unmapped and that it is
enough to zap a single IOVA of page table to remove the entire page
table from IOMMU cache. Based on these assumptions the driver was made to
simply zap the first IOVA of the mapping being created. This is enough
to invalidate first page table, which could be shared with another
mapping (and thus could be already present in IOMMU cache), but
unfortunately it does not do anything about the last page table that
could be shared with other mappings as well.

Moreover, the flushing is performed before page table contents are
actually modified, so there is a race between the CPU updating the page
tables and hardware that could be possibly running at the same time and
triggering IOMMU look-ups, which could bring back the page tables back
to the cache.

To fix both issues, this patch makes the mapping code zap first and last
(if they are different) IOVAs of new mapping after the page table is
updated.

Signed-off-by: Tomasz Figa <tfiga@chromium.org>
Reviewed-by: Daniel Kurtz <djkurtz@chromium.org>
Tested-by: Heiko Stuebner <heiko@sntech.de>
---
 drivers/iommu/rockchip-iommu.c | 23 +++++++++++++++++------
 1 file changed, 17 insertions(+), 6 deletions(-)

diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c
index 4015560..31004c0 100644
--- a/drivers/iommu/rockchip-iommu.c
+++ b/drivers/iommu/rockchip-iommu.c
@@ -551,6 +551,15 @@ static void rk_iommu_zap_iova(struct rk_iommu_domain *rk_domain,
 	spin_unlock_irqrestore(&rk_domain->iommus_lock, flags);
 }
 
+static void rk_iommu_zap_iova_first_last(struct rk_iommu_domain *rk_domain,
+					 dma_addr_t iova, size_t size)
+{
+	rk_iommu_zap_iova(rk_domain, iova, SPAGE_SIZE);
+	if (size > SPAGE_SIZE)
+		rk_iommu_zap_iova(rk_domain, iova + size - SPAGE_SIZE,
+					SPAGE_SIZE);
+}
+
 static u32 *rk_dte_get_page_table(struct rk_iommu_domain *rk_domain,
 				  dma_addr_t iova)
 {
@@ -575,12 +584,6 @@ static u32 *rk_dte_get_page_table(struct rk_iommu_domain *rk_domain,
 	rk_table_flush(page_table, NUM_PT_ENTRIES);
 	rk_table_flush(dte_addr, 1);
 
-	/*
-	 * Zap the first iova of newly allocated page table so iommu evicts
-	 * old cached value of new dte from the iotlb.
-	 */
-	rk_iommu_zap_iova(rk_domain, iova, SPAGE_SIZE);
-
 done:
 	pt_phys = rk_dte_pt_address(dte);
 	return (u32 *)phys_to_virt(pt_phys);
@@ -630,6 +633,14 @@ static int rk_iommu_map_iova(struct rk_iommu_domain *rk_domain, u32 *pte_addr,
 
 	rk_table_flush(pte_addr, pte_count);
 
+	/*
+	 * Zap the first and last iova to evict from iotlb any previously
+	 * mapped cachelines holding stale values for its dte and pte.
+	 * We only zap the first and last iova, since only they could have
+	 * dte or pte shared with an existing mapping.
+	 */
+	rk_iommu_zap_iova_first_last(rk_domain, iova, size);
+
 	return 0;
 unwind:
 	/* Unmap the range of iovas that we just mapped */
-- 
2.2.0.rc0.207.ga3a616c

^ permalink raw reply related	[flat|nested] 3+ messages in thread

* [PATCH v2] CHROMIUM: iommu: rockchip: Make sure that page table state is coherent
  2015-04-20 11:43 [PATCH v2] CHROMIUM: iommu: rockchip: Make sure that page table state is coherent Tomasz Figa
@ 2015-04-23  9:09 ` Daniel Kurtz
  2015-05-08  8:22   ` Tomasz Figa
  0 siblings, 1 reply; 3+ messages in thread
From: Daniel Kurtz @ 2015-04-23  9:09 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Apr 20, 2015 at 7:43 PM, Tomasz Figa <tfiga@chromium.org> wrote:
> To flush created mappings, current mapping code relies on the fact that
> during unmap the driver zaps every IOVA being unmapped and that it is
> enough to zap a single IOVA of page table to remove the entire page
> table from IOMMU cache. Based on these assumptions the driver was made to
> simply zap the first IOVA of the mapping being created. This is enough
> to invalidate first page table, which could be shared with another
> mapping (and thus could be already present in IOMMU cache), but
> unfortunately it does not do anything about the last page table that
> could be shared with other mappings as well.
>
> Moreover, the flushing is performed before page table contents are
> actually modified, so there is a race between the CPU updating the page
> tables and hardware that could be possibly running at the same time and
> triggering IOMMU look-ups, which could bring back the page tables back
> to the cache.
>
> To fix both issues, this patch makes the mapping code zap first and last
> (if they are different) IOVAs of new mapping after the page table is
> updated.
>
> Signed-off-by: Tomasz Figa <tfiga@chromium.org>
> Reviewed-by: Daniel Kurtz <djkurtz@chromium.org>
> Tested-by: Heiko Stuebner <heiko@sntech.de>

You probably want to remove the "CHROMIUM: " label in the subject.
Other than that, this is still:
Reviewed-by: Daniel Kurtz <djkurtz@chromium.org>

> ---
>  drivers/iommu/rockchip-iommu.c | 23 +++++++++++++++++------
>  1 file changed, 17 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c
> index 4015560..31004c0 100644
> --- a/drivers/iommu/rockchip-iommu.c
> +++ b/drivers/iommu/rockchip-iommu.c
> @@ -551,6 +551,15 @@ static void rk_iommu_zap_iova(struct rk_iommu_domain *rk_domain,
>         spin_unlock_irqrestore(&rk_domain->iommus_lock, flags);
>  }
>
> +static void rk_iommu_zap_iova_first_last(struct rk_iommu_domain *rk_domain,
> +                                        dma_addr_t iova, size_t size)
> +{
> +       rk_iommu_zap_iova(rk_domain, iova, SPAGE_SIZE);
> +       if (size > SPAGE_SIZE)
> +               rk_iommu_zap_iova(rk_domain, iova + size - SPAGE_SIZE,
> +                                       SPAGE_SIZE);
> +}
> +
>  static u32 *rk_dte_get_page_table(struct rk_iommu_domain *rk_domain,
>                                   dma_addr_t iova)
>  {
> @@ -575,12 +584,6 @@ static u32 *rk_dte_get_page_table(struct rk_iommu_domain *rk_domain,
>         rk_table_flush(page_table, NUM_PT_ENTRIES);
>         rk_table_flush(dte_addr, 1);
>
> -       /*
> -        * Zap the first iova of newly allocated page table so iommu evicts
> -        * old cached value of new dte from the iotlb.
> -        */
> -       rk_iommu_zap_iova(rk_domain, iova, SPAGE_SIZE);
> -
>  done:
>         pt_phys = rk_dte_pt_address(dte);
>         return (u32 *)phys_to_virt(pt_phys);
> @@ -630,6 +633,14 @@ static int rk_iommu_map_iova(struct rk_iommu_domain *rk_domain, u32 *pte_addr,
>
>         rk_table_flush(pte_addr, pte_count);
>
> +       /*
> +        * Zap the first and last iova to evict from iotlb any previously
> +        * mapped cachelines holding stale values for its dte and pte.
> +        * We only zap the first and last iova, since only they could have
> +        * dte or pte shared with an existing mapping.
> +        */
> +       rk_iommu_zap_iova_first_last(rk_domain, iova, size);
> +
>         return 0;
>  unwind:
>         /* Unmap the range of iovas that we just mapped */
> --
> 2.2.0.rc0.207.ga3a616c
>

^ permalink raw reply	[flat|nested] 3+ messages in thread

* [PATCH v2] CHROMIUM: iommu: rockchip: Make sure that page table state is coherent
  2015-04-23  9:09 ` Daniel Kurtz
@ 2015-05-08  8:22   ` Tomasz Figa
  0 siblings, 0 replies; 3+ messages in thread
From: Tomasz Figa @ 2015-05-08  8:22 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Apr 23, 2015 at 6:09 PM, Daniel Kurtz <djkurtz@chromium.org> wrote:
> On Mon, Apr 20, 2015 at 7:43 PM, Tomasz Figa <tfiga@chromium.org> wrote:
>> To flush created mappings, current mapping code relies on the fact that
>> during unmap the driver zaps every IOVA being unmapped and that it is
>> enough to zap a single IOVA of page table to remove the entire page
>> table from IOMMU cache. Based on these assumptions the driver was made to
>> simply zap the first IOVA of the mapping being created. This is enough
>> to invalidate first page table, which could be shared with another
>> mapping (and thus could be already present in IOMMU cache), but
>> unfortunately it does not do anything about the last page table that
>> could be shared with other mappings as well.
>>
>> Moreover, the flushing is performed before page table contents are
>> actually modified, so there is a race between the CPU updating the page
>> tables and hardware that could be possibly running at the same time and
>> triggering IOMMU look-ups, which could bring back the page tables back
>> to the cache.
>>
>> To fix both issues, this patch makes the mapping code zap first and last
>> (if they are different) IOVAs of new mapping after the page table is
>> updated.
>>
>> Signed-off-by: Tomasz Figa <tfiga@chromium.org>
>> Reviewed-by: Daniel Kurtz <djkurtz@chromium.org>
>> Tested-by: Heiko Stuebner <heiko@sntech.de>
>
> You probably want to remove the "CHROMIUM: " label in the subject.

Sorry, I removed gerrit tags, but hurrying up too much, I missed the
label. I see, though, that Joerg has applied this patch already with
this fixed up. Thanks.

Best regards,
Tomasz

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2015-05-08  8:22 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-04-20 11:43 [PATCH v2] CHROMIUM: iommu: rockchip: Make sure that page table state is coherent Tomasz Figa
2015-04-23  9:09 ` Daniel Kurtz
2015-05-08  8:22   ` Tomasz Figa

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).