Re: [PATCH] iommu/vt-d: Force to flush iotlb before creating superpage

2021-04-01 Thread Lu Baolu
On 4/2/21 11:41 AM, Longpeng (Mike, Cloud Infrastructure Service Product 
Dept.) wrote:

Hi Baolu,

在 2021/4/2 11:06, Lu Baolu 写道:

Hi Longpeng,

On 4/1/21 3:18 PM, Longpeng(Mike) wrote:

The translation caches may preserve obsolete data when the
mapping size is changed, suppose the following sequence which
can reveal the problem with high probability.

1.mmap(4GB,MAP_HUGETLB)
2.
    while (1) {
     (a)    DMA MAP   0,0xa
     (b)    DMA UNMAP 0,0xa
     (c)    DMA MAP   0,0xc000
   * DMA read IOVA 0 may failure here (Not present)
   * if the problem occurs.
     (d)    DMA UNMAP 0,0xc000
    }

The page table(only focus on IOVA 0) after (a) is:
   PML4: 0x19db5c1003   entry:0x899bdcd2f000
    PDPE: 0x1a1cacb003  entry:0x89b35b5c1000
     PDE: 0x1a30a72003  entry:0x89b39cacb000
  PTE: 0x21d200803  entry:0x89b3b0a72000

The page table after (b) is:
   PML4: 0x19db5c1003   entry:0x899bdcd2f000
    PDPE: 0x1a1cacb003  entry:0x89b35b5c1000
     PDE: 0x1a30a72003  entry:0x89b39cacb000
  PTE: 0x0  entry:0x89b3b0a72000

The page table after (c) is:
   PML4: 0x19db5c1003   entry:0x899bdcd2f000
    PDPE: 0x1a1cacb003  entry:0x89b35b5c1000
     PDE: 0x21d200883   entry:0x89b39cacb000 (*)

Because the PDE entry after (b) is present, it won't be
flushed even if the iommu driver flush cache when unmap,
so the obsolete data may be preserved in cache, which
would cause the wrong translation at end.

However, we can see the PDE entry is finally switch to
2M-superpage mapping, but it does not transform
to 0x21d200883 directly:

1. PDE: 0x1a30a72003
2. __domain_mapping
   dma_pte_free_pagetable
     Set the PDE entry to ZERO
   Set the PDE entry to 0x21d200883

So we must flush the cache after the entry switch to ZERO
to avoid the obsolete info be preserved.

Cc: David Woodhouse 
Cc: Lu Baolu 
Cc: Nadav Amit 
Cc: Alex Williamson 
Cc: Kevin Tian 
Cc: Gonglei (Arei) 

Fixes: 6491d4d02893 ("intel-iommu: Free old page tables before creating
superpage")
Cc:  # v3.0+
Link:
https://lore.kernel.org/linux-iommu/670baaf8-4ff8-4e84-4be3-030b95ab5...@huawei.com/

Suggested-by: Lu Baolu 
Signed-off-by: Longpeng(Mike) 
---
   drivers/iommu/intel/iommu.c | 15 +--
   1 file changed, 13 insertions(+), 2 deletions(-)

diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
index ee09323..cbcb434 100644
--- a/drivers/iommu/intel/iommu.c
+++ b/drivers/iommu/intel/iommu.c
@@ -2342,9 +2342,20 @@ static inline int hardware_largepage_caps(struct
dmar_domain *domain,
    * removed to make room for superpage(s).
    * We're adding new large pages, so make sure
    * we don't remove their parent tables.
+ *
+ * We also need to flush the iotlb before creating
+ * superpage to ensure it does not perserves any
+ * obsolete info.
    */
-    dma_pte_free_pagetable(domain, iov_pfn, end_pfn,
-   largepage_lvl + 1);
+    if (dma_pte_present(pte)) {
+    int i;
+
+    dma_pte_free_pagetable(domain, iov_pfn, end_pfn,
+   largepage_lvl + 1);
+    for_each_domain_iommu(i, domain)
+    iommu_flush_iotlb_psi(g_iommus[i], domain,
+  iov_pfn, nr_pages, 0, 0);


Thanks for patch!

How about making the flushed page size accurate? For example,

@@ -2365,8 +2365,8 @@ __domain_mapping(struct dmar_domain *domain, unsigned long
iov_pfn,
     dma_pte_free_pagetable(domain, iov_pfn,
end_pfn,

largepage_lvl + 1);
     for_each_domain_iommu(i, domain)
- iommu_flush_iotlb_psi(g_iommus[i], domain,
- iov_pfn, nr_pages, 0, 0);
+ iommu_flush_iotlb_psi(g_iommus[i], domain, iov_pfn,
+ ALIGN_DOWN(nr_pages, lvl_pages), 0, 0);


Yes, make sense.

Maybe another alternative is 'end_pfn - iova_pfn + 1', it's readable because we
free pagetable with (iova_pfn, end_pfn) above. Which one do you prefer?


Yours looks better.

By the way, if you are willing to prepare a v2, please make sure to add
Joerg (IOMMU subsystem maintainer) to the list.

Best regards,
baolu
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

Re: [PATCH] iommu/vt-d: Force to flush iotlb before creating superpage

2021-04-01 Thread Lu Baolu

Hi Longpeng,

On 4/1/21 3:18 PM, Longpeng(Mike) wrote:

diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
index ee09323..cbcb434 100644
--- a/drivers/iommu/intel/iommu.c
+++ b/drivers/iommu/intel/iommu.c
@@ -2342,9 +2342,20 @@ static inline int hardware_largepage_caps(struct 
dmar_domain *domain,
 * removed to make room for superpage(s).
 * We're adding new large pages, so make sure
 * we don't remove their parent tables.
+*
+* We also need to flush the iotlb before 
creating
+* superpage to ensure it does not perserves any
+* obsolete info.
 */
-   dma_pte_free_pagetable(domain, iov_pfn, end_pfn,
-  largepage_lvl + 1);
+   if (dma_pte_present(pte)) {


The dma_pte_free_pagetable() clears a batch of PTEs. So checking current
PTE is insufficient. How about removing this check and always performing
cache invalidation?


+   int i;
+
+   dma_pte_free_pagetable(domain, iov_pfn, 
end_pfn,
+  largepage_lvl + 
1);
+   for_each_domain_iommu(i, domain)
+   
iommu_flush_iotlb_psi(g_iommus[i], domain,
+ iov_pfn, 
nr_pages, 0, 0);
+   


Best regards,
baolu
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH v5] iommu/tegra-smmu: Add pagetable mappings to debugfs

2021-04-01 Thread Nicolin Chen
On Tue, Mar 16, 2021 at 12:16:43PM +0100, Thierry Reding wrote:

> > +struct tegra_smmu_group_debug {
> > +   const struct tegra_smmu_swgroup *group;
> > +   void *priv;
> 
> This always stores the address space, so why not make this:
> 
>   struct tegra_smmu_as *as;
> 
> ? While at it, perhaps throw in a const to make sure we don't modify
> this structure in the debugfs code.

OK. I will try to change that.

> > @@ -334,7 +350,7 @@ static void tegra_smmu_domain_free(struct iommu_domain 
> > *domain)
> >  }
> >  
> >  static const struct tegra_smmu_swgroup *
> > -tegra_smmu_find_swgroup(struct tegra_smmu *smmu, unsigned int swgroup)
> > +tegra_smmu_find_swgroup(struct tegra_smmu *smmu, unsigned int swgroup, int 
> > *index)
> >  {
> > const struct tegra_smmu_swgroup *group = NULL;
> > unsigned int i;
> > @@ -342,6 +358,8 @@ tegra_smmu_find_swgroup(struct tegra_smmu *smmu, 
> > unsigned int swgroup)
> > for (i = 0; i < smmu->soc->num_swgroups; i++) {
> > if (smmu->soc->swgroups[i].swgroup == swgroup) {
> > group = &smmu->soc->swgroups[i];
> > +   if (index)
> > +   *index = i;
> 
> This doesn't look like the right place for this. And this also makes
> things hard to follow because it passes out-of-band data in the index
> parameter.
> 
> I'm thinking that this could benefit from a bit of refactoring where
> we could for example embed struct tegra_smmu_group_debug into struct
> tegra_smmu_group and then reference that when necessary instead of
> carrying all that data in an orthogonal array. That should also make
> it easier to track this.
> 
> Come to think of it, everything that's currently in your new struct
> tegra_smmu_group_debug would be useful in struct tegra_smmu_group,
> irrespective of debugfs support.

Will try to embed it or see what I can do following the suggestion.

> > +static int tegra_smmu_mappings_show(struct seq_file *s, void *data)
> > +{

> > +   seq_printf(s, "\nSWGROUP: %s\nASID: %d\nreg: 0x%x\n",
> > +  group->name, as->id, group->reg);
> 
> Is group->reg really that useful here?

Can drop it.

> > +
> > +   smmu_writel(smmu, as->id & 0x7f, SMMU_PTB_ASID);
> > +   ptb_reg = smmu_readl(smmu, SMMU_PTB_DATA);
> > +
> > +   seq_printf(s, "PTB_ASID: 0x%x\nas->pd_dma: %pad\n",
> > +  ptb_reg, &as->pd_dma);
> 
> This looks somewhat redundant because as->pd_dma is already part of the
> PTB_ASID register value. Instead, perhaps decode the upper bits of that
> register and simply output as->pdma so that we don't duplicate the base
> address of the page table?

That's a good idea. Will change that too.
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH] iommu/vt-d: Force to flush iotlb before creating superpage

2021-04-01 Thread Longpeng (Mike, Cloud Infrastructure Service Product Dept.)
Hi Baolu,

在 2021/4/2 11:06, Lu Baolu 写道:
> Hi Longpeng,
> 
> On 4/1/21 3:18 PM, Longpeng(Mike) wrote:
>> The translation caches may preserve obsolete data when the
>> mapping size is changed, suppose the following sequence which
>> can reveal the problem with high probability.
>>
>> 1.mmap(4GB,MAP_HUGETLB)
>> 2.
>>    while (1) {
>>     (a)    DMA MAP   0,0xa
>>     (b)    DMA UNMAP 0,0xa
>>     (c)    DMA MAP   0,0xc000
>>   * DMA read IOVA 0 may failure here (Not present)
>>   * if the problem occurs.
>>     (d)    DMA UNMAP 0,0xc000
>>    }
>>
>> The page table(only focus on IOVA 0) after (a) is:
>>   PML4: 0x19db5c1003   entry:0x899bdcd2f000
>>    PDPE: 0x1a1cacb003  entry:0x89b35b5c1000
>>     PDE: 0x1a30a72003  entry:0x89b39cacb000
>>  PTE: 0x21d200803  entry:0x89b3b0a72000
>>
>> The page table after (b) is:
>>   PML4: 0x19db5c1003   entry:0x899bdcd2f000
>>    PDPE: 0x1a1cacb003  entry:0x89b35b5c1000
>>     PDE: 0x1a30a72003  entry:0x89b39cacb000
>>  PTE: 0x0  entry:0x89b3b0a72000
>>
>> The page table after (c) is:
>>   PML4: 0x19db5c1003   entry:0x899bdcd2f000
>>    PDPE: 0x1a1cacb003  entry:0x89b35b5c1000
>>     PDE: 0x21d200883   entry:0x89b39cacb000 (*)
>>
>> Because the PDE entry after (b) is present, it won't be
>> flushed even if the iommu driver flush cache when unmap,
>> so the obsolete data may be preserved in cache, which
>> would cause the wrong translation at end.
>>
>> However, we can see the PDE entry is finally switch to
>> 2M-superpage mapping, but it does not transform
>> to 0x21d200883 directly:
>>
>> 1. PDE: 0x1a30a72003
>> 2. __domain_mapping
>>   dma_pte_free_pagetable
>>     Set the PDE entry to ZERO
>>   Set the PDE entry to 0x21d200883
>>
>> So we must flush the cache after the entry switch to ZERO
>> to avoid the obsolete info be preserved.
>>
>> Cc: David Woodhouse 
>> Cc: Lu Baolu 
>> Cc: Nadav Amit 
>> Cc: Alex Williamson 
>> Cc: Kevin Tian 
>> Cc: Gonglei (Arei) 
>>
>> Fixes: 6491d4d02893 ("intel-iommu: Free old page tables before creating
>> superpage")
>> Cc:  # v3.0+
>> Link:
>> https://lore.kernel.org/linux-iommu/670baaf8-4ff8-4e84-4be3-030b95ab5...@huawei.com/
>>
>> Suggested-by: Lu Baolu 
>> Signed-off-by: Longpeng(Mike) 
>> ---
>>   drivers/iommu/intel/iommu.c | 15 +--
>>   1 file changed, 13 insertions(+), 2 deletions(-)
>>
>> diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
>> index ee09323..cbcb434 100644
>> --- a/drivers/iommu/intel/iommu.c
>> +++ b/drivers/iommu/intel/iommu.c
>> @@ -2342,9 +2342,20 @@ static inline int hardware_largepage_caps(struct
>> dmar_domain *domain,
>>    * removed to make room for superpage(s).
>>    * We're adding new large pages, so make sure
>>    * we don't remove their parent tables.
>> + *
>> + * We also need to flush the iotlb before creating
>> + * superpage to ensure it does not perserves any
>> + * obsolete info.
>>    */
>> -    dma_pte_free_pagetable(domain, iov_pfn, end_pfn,
>> -   largepage_lvl + 1);
>> +    if (dma_pte_present(pte)) {
>> +    int i;
>> +
>> +    dma_pte_free_pagetable(domain, iov_pfn, end_pfn,
>> +   largepage_lvl + 1);
>> +    for_each_domain_iommu(i, domain)
>> +    iommu_flush_iotlb_psi(g_iommus[i], domain,
>> +  iov_pfn, nr_pages, 0, 0);
> 
> Thanks for patch!
> 
> How about making the flushed page size accurate? For example,
> 
> @@ -2365,8 +2365,8 @@ __domain_mapping(struct dmar_domain *domain, unsigned 
> long
> iov_pfn,
>     dma_pte_free_pagetable(domain, 
> iov_pfn,
> end_pfn,
> 
> largepage_lvl + 1);
>     for_each_domain_iommu(i, domain)
> - iommu_flush_iotlb_psi(g_iommus[i], domain,
> - iov_pfn, nr_pages, 0, 0);
> + iommu_flush_iotlb_psi(g_iommus[i], domain, iov_pfn,
> + ALIGN_DOWN(nr_pages, lvl_pages), 0, 0);
> 
Yes, make sense.

Maybe another alternative is 'end_pfn - iova_pfn + 1', it's readable because we
free pagetable with (iova_pfn, end_pfn) above. Which one do you prefer?

> 
>> +    }
>>   } else {
>>   pteval &= ~(uint64_t)DMA_PTE_LARGE_PAGE;
>>   }
>>
> 
> Best regards,
> baolu
> .
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

Re: [PATCH] iommu/vt-d: Force to flush iotlb before creating superpage

2021-04-01 Thread Lu Baolu

Hi Longpeng,

On 4/1/21 3:18 PM, Longpeng(Mike) wrote:

The translation caches may preserve obsolete data when the
mapping size is changed, suppose the following sequence which
can reveal the problem with high probability.

1.mmap(4GB,MAP_HUGETLB)
2.
   while (1) {
(a)DMA MAP   0,0xa
(b)DMA UNMAP 0,0xa
(c)DMA MAP   0,0xc000
  * DMA read IOVA 0 may failure here (Not present)
  * if the problem occurs.
(d)DMA UNMAP 0,0xc000
   }

The page table(only focus on IOVA 0) after (a) is:
  PML4: 0x19db5c1003   entry:0x899bdcd2f000
   PDPE: 0x1a1cacb003  entry:0x89b35b5c1000
PDE: 0x1a30a72003  entry:0x89b39cacb000
 PTE: 0x21d200803  entry:0x89b3b0a72000

The page table after (b) is:
  PML4: 0x19db5c1003   entry:0x899bdcd2f000
   PDPE: 0x1a1cacb003  entry:0x89b35b5c1000
PDE: 0x1a30a72003  entry:0x89b39cacb000
 PTE: 0x0  entry:0x89b3b0a72000

The page table after (c) is:
  PML4: 0x19db5c1003   entry:0x899bdcd2f000
   PDPE: 0x1a1cacb003  entry:0x89b35b5c1000
PDE: 0x21d200883   entry:0x89b39cacb000 (*)

Because the PDE entry after (b) is present, it won't be
flushed even if the iommu driver flush cache when unmap,
so the obsolete data may be preserved in cache, which
would cause the wrong translation at end.

However, we can see the PDE entry is finally switch to
2M-superpage mapping, but it does not transform
to 0x21d200883 directly:

1. PDE: 0x1a30a72003
2. __domain_mapping
  dma_pte_free_pagetable
Set the PDE entry to ZERO
  Set the PDE entry to 0x21d200883

So we must flush the cache after the entry switch to ZERO
to avoid the obsolete info be preserved.

Cc: David Woodhouse 
Cc: Lu Baolu 
Cc: Nadav Amit 
Cc: Alex Williamson 
Cc: Kevin Tian 
Cc: Gonglei (Arei) 

Fixes: 6491d4d02893 ("intel-iommu: Free old page tables before creating 
superpage")
Cc:  # v3.0+
Link: 
https://lore.kernel.org/linux-iommu/670baaf8-4ff8-4e84-4be3-030b95ab5...@huawei.com/
Suggested-by: Lu Baolu 
Signed-off-by: Longpeng(Mike) 
---
  drivers/iommu/intel/iommu.c | 15 +--
  1 file changed, 13 insertions(+), 2 deletions(-)

diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
index ee09323..cbcb434 100644
--- a/drivers/iommu/intel/iommu.c
+++ b/drivers/iommu/intel/iommu.c
@@ -2342,9 +2342,20 @@ static inline int hardware_largepage_caps(struct 
dmar_domain *domain,
 * removed to make room for superpage(s).
 * We're adding new large pages, so make sure
 * we don't remove their parent tables.
+*
+* We also need to flush the iotlb before 
creating
+* superpage to ensure it does not perserves any
+* obsolete info.
 */
-   dma_pte_free_pagetable(domain, iov_pfn, end_pfn,
-  largepage_lvl + 1);
+   if (dma_pte_present(pte)) {
+   int i;
+
+   dma_pte_free_pagetable(domain, iov_pfn, 
end_pfn,
+  largepage_lvl + 
1);
+   for_each_domain_iommu(i, domain)
+   
iommu_flush_iotlb_psi(g_iommus[i], domain,
+ iov_pfn, 
nr_pages, 0, 0);


Thanks for patch!

How about making the flushed page size accurate? For example,

@@ -2365,8 +2365,8 @@ __domain_mapping(struct dmar_domain *domain, 
unsigned long iov_pfn,
dma_pte_free_pagetable(domain, 
iov_pfn, end_pfn,


largepage_lvl + 1);
for_each_domain_iommu(i, domain)
- 
iommu_flush_iotlb_psi(g_iommus[i], domain,
- 
iov_pfn, nr_pages, 0, 0);
+ 
iommu_flush_iotlb_psi(g_iommus[i], domain, iov_pfn,
+ 
ALIGN_DOWN(nr_pages, lvl_pages), 0, 0);




+   }
} else {
pteval &= ~(uint64_t)DMA_PTE_LARGE_PAGE;
}



Best regards,
baolu
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH v14 10/10] iommu/arm-smmu-v3: Add stall support for platform devices

2021-04-01 Thread Zhou Wang
On 2021/4/2 1:11, Will Deacon wrote:
> On Thu, Apr 01, 2021 at 05:47:19PM +0200, Jean-Philippe Brucker wrote:
>> The SMMU provides a Stall model for handling page faults in platform
>> devices. It is similar to PCIe PRI, but doesn't require devices to have
>> their own translation cache. Instead, faulting transactions are parked
>> and the OS is given a chance to fix the page tables and retry the
>> transaction.
>>
>> Enable stall for devices that support it (opt-in by firmware). When an
>> event corresponds to a translation error, call the IOMMU fault handler.
>> If the fault is recoverable, it will call us back to terminate or
>> continue the stall.
> 
> Which hardware is this useful for? Stalling adds a fair amount of complexity
> to the driver, so I don't think we should support it unless we're likely to
> see platforms that both implement it and do something useful with it.

Hi Will,

HiSilicon Kunpeng920's ZIP/SEC/HPRE engines(drivers/crypto/hisilicon/) are using
stall mode.

UACCE driver(drivers/misc/uacce/) is used to export these engines to user space.
A user space library: https://github.com/Linaro/uadk offers APIs to help users
to use these engines.

In fact, we only need a quirk(https://lkml.org/lkml/2021/3/8/1506) based on this
IOPF series to make whole solution mainline ready. So please also take this
patch, we need it! :)

Best,
Zhou

> 
> Will
> 
> .
> 

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

Re: [RFC PATCH 3/6] iommu: Use bitmap to calculate page size in iommu_pgsize()

2021-04-01 Thread isaacm

On 2021-04-01 09:47, Will Deacon wrote:

Avoid the potential for shifting values by amounts greater than the
width of their type by using a bitmap to compute page size in
iommu_pgsize().

Signed-off-by: Will Deacon 
---
 drivers/iommu/iommu.c | 31 ---
 1 file changed, 12 insertions(+), 19 deletions(-)

diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index d0b0a15dba84..bcd623862bf9 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -8,6 +8,7 @@

 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -2360,30 +2361,22 @@ static size_t iommu_pgsize(struct iommu_domain 
*domain,

   unsigned long addr_merge, size_t size)
 {
unsigned int pgsize_idx;
+   unsigned long pgsizes;
size_t pgsize;

-   /* Max page size that still fits into 'size' */
-   pgsize_idx = __fls(size);
+   /* Page sizes supported by the hardware and small enough for @size */
+   pgsizes = domain->pgsize_bitmap & GENMASK(__fls(size), 0);
I've fixed this in the latest RFC for the iommu_map/unmap optimization 
patches,
but for the sake of completeness: I think this should be GENMASK_ULL, in 
case

__fls(size) >= 32.

Thank you for these patches, by the way. I've looked through them and 
they
make sense/seem correct. I've integrated them into the latest RFC: 
https://lore.kernel.org/linux-iommu/20210402013452.4013-1-isa...@codeaurora.org/T/#t.


Thanks,
Isaac


-   /* need to consider alignment requirements ? */
-   if (likely(addr_merge)) {
-   /* Max page size allowed by address */
-   unsigned int align_pgsize_idx = __ffs(addr_merge);
-   pgsize_idx = min(pgsize_idx, align_pgsize_idx);
-   }
-
-   /* build a mask of acceptable page sizes */
-   pgsize = (1UL << (pgsize_idx + 1)) - 1;
-
-   /* throw away page sizes not supported by the hardware */
-   pgsize &= domain->pgsize_bitmap;
+   /* Constrain the page sizes further based on the maximum alignment */
+   if (likely(addr_merge))
+   pgsizes &= GENMASK(__ffs(addr_merge), 0);

-   /* make sure we're still sane */
-   BUG_ON(!pgsize);
+   /* Make sure we have at least one suitable page size */
+   BUG_ON(!pgsizes);

-   /* pick the biggest page */
-   pgsize_idx = __fls(pgsize);
-   pgsize = 1UL << pgsize_idx;
+   /* Pick the biggest page size remaining */
+   pgsize_idx = __fls(pgsizes);
+   pgsize = BIT(pgsize_idx);

return pgsize;
 }

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v2 01/12] iommu/io-pgtable: Introduce unmap_pages() as a page table op

2021-04-01 Thread Isaac J. Manjarres
The io-pgtable code expects to operate on a single block or
granule of memory that is supported by the IOMMU hardware when
unmapping memory.

This means that when a large buffer that consists of multiple
such blocks is unmapped, the io-pgtable code will walk the page
tables to the correct level to unmap each block, even for blocks
that are virtually contiguous and at the same level, which can
incur an overhead in performance.

Introduce the unmap_pages() page table op to express to the
io-pgtable code that it should unmap a number of blocks of
the same size, instead of a single block. Doing so allows
multiple blocks to be unmapped in one call to the io-pgtable
code, reducing the number of page table walks, and indirect
calls.

Signed-off-by: Isaac J. Manjarres 
Suggested-by: Will Deacon 
Signed-off-by: Will Deacon 
---
 include/linux/io-pgtable.h | 4 
 1 file changed, 4 insertions(+)

diff --git a/include/linux/io-pgtable.h b/include/linux/io-pgtable.h
index a4c9ca2c31f1..2ed0c057d9e7 100644
--- a/include/linux/io-pgtable.h
+++ b/include/linux/io-pgtable.h
@@ -144,6 +144,7 @@ struct io_pgtable_cfg {
  *
  * @map:  Map a physically contiguous memory region.
  * @unmap:Unmap a physically contiguous memory region.
+ * @unmap_pages:  Unmap a range of virtually contiguous pages of the same size.
  * @iova_to_phys: Translate iova to physical address.
  *
  * These functions map directly onto the iommu_ops member functions with
@@ -154,6 +155,9 @@ struct io_pgtable_ops {
   phys_addr_t paddr, size_t size, int prot, gfp_t gfp);
size_t (*unmap)(struct io_pgtable_ops *ops, unsigned long iova,
size_t size, struct iommu_iotlb_gather *gather);
+   size_t (*unmap_pages)(struct io_pgtable_ops *ops, unsigned long iova,
+ size_t pgsize, size_t pgcount,
+ struct iommu_iotlb_gather *gather);
phys_addr_t (*iova_to_phys)(struct io_pgtable_ops *ops,
unsigned long iova);
 };
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v2 10/12] iommu/io-pgtable-arm: Implement arm_lpae_map_pages()

2021-04-01 Thread Isaac J. Manjarres
Implement the map_pages() callback for the ARM LPAE io-pgtable
format.

Signed-off-by: Isaac J. Manjarres 
Suggested-by: Will Deacon 
---
 drivers/iommu/io-pgtable-arm.c | 95 +++---
 1 file changed, 88 insertions(+), 7 deletions(-)

diff --git a/drivers/iommu/io-pgtable-arm.c b/drivers/iommu/io-pgtable-arm.c
index fc63d57b8037..b8464305f1c2 100644
--- a/drivers/iommu/io-pgtable-arm.c
+++ b/drivers/iommu/io-pgtable-arm.c
@@ -355,20 +355,35 @@ static arm_lpae_iopte 
arm_lpae_install_table(arm_lpae_iopte *table,
 }
 
 static int __arm_lpae_map(struct arm_lpae_io_pgtable *data, unsigned long iova,
- phys_addr_t paddr, size_t size, arm_lpae_iopte prot,
- int lvl, arm_lpae_iopte *ptep, gfp_t gfp)
+ phys_addr_t paddr, size_t size, size_t pgcount,
+ arm_lpae_iopte prot, int lvl, arm_lpae_iopte *ptep,
+ gfp_t gfp, size_t *mapped)
 {
arm_lpae_iopte *cptep, pte;
size_t block_size = ARM_LPAE_BLOCK_SIZE(lvl, data);
size_t tblsz = ARM_LPAE_GRANULE(data);
struct io_pgtable_cfg *cfg = &data->iop.cfg;
+   int ret = 0;
 
/* Find our entry at the current level */
ptep += ARM_LPAE_LVL_IDX(iova, lvl, data);
 
-   /* If we can install a leaf entry at this level, then do so */
-   if (size == block_size)
-   return arm_lpae_init_pte(data, iova, paddr, prot, lvl, ptep);
+   /* If we can install leaf entries at this level, then do so */
+   if (size == block_size) {
+   while (pgcount--) {
+   ret = arm_lpae_init_pte(data, iova, paddr, prot, lvl, 
ptep);
+   if (ret)
+   return ret;
+
+   iova += size;
+   paddr += size;
+   ptep++;
+   if (mapped)
+   *mapped += size;
+   }
+
+   return ret;
+   }
 
/* We can't allocate tables at the final level */
if (WARN_ON(lvl >= ARM_LPAE_MAX_LEVELS - 1))
@@ -397,7 +412,8 @@ static int __arm_lpae_map(struct arm_lpae_io_pgtable *data, 
unsigned long iova,
}
 
/* Rinse, repeat */
-   return __arm_lpae_map(data, iova, paddr, size, prot, lvl + 1, cptep, 
gfp);
+   return __arm_lpae_map(data, iova, paddr, size, pgcount, prot, lvl + 1, 
cptep,
+ gfp, mapped);
 }
 
 static arm_lpae_iopte arm_lpae_prot_to_pte(struct arm_lpae_io_pgtable *data,
@@ -487,7 +503,71 @@ static int arm_lpae_map(struct io_pgtable_ops *ops, 
unsigned long iova,
return 0;
 
prot = arm_lpae_prot_to_pte(data, iommu_prot);
-   ret = __arm_lpae_map(data, iova, paddr, size, prot, lvl, ptep, gfp);
+   ret = __arm_lpae_map(data, iova, paddr, size, 1, prot, lvl, ptep, gfp,
+NULL);
+   /*
+* Synchronise all PTE updates for the new mapping before there's
+* a chance for anything to kick off a table walk for the new iova.
+*/
+   wmb();
+
+   return ret;
+}
+
+static int arm_lpae_map_pages(struct io_pgtable_ops *ops, unsigned long iova,
+ phys_addr_t paddr, size_t pgsize, size_t pgcount,
+ int iommu_prot, gfp_t gfp, size_t *mapped)
+{
+   struct arm_lpae_io_pgtable *data = io_pgtable_ops_to_data(ops);
+   struct io_pgtable_cfg *cfg = &data->iop.cfg;
+   arm_lpae_iopte *ptep = data->pgd;
+   int ret, lvl = data->start_level, last_lvl;
+   arm_lpae_iopte prot;
+   long iaext = (s64)iova >> cfg->ias;
+   size_t table_size, pages, tbl_offset, max_entries;
+
+   /* If no access, then nothing to do */
+   if (!(iommu_prot & (IOMMU_READ | IOMMU_WRITE)))
+   return 0;
+
+   if (WARN_ON(!pgsize || (pgsize & cfg->pgsize_bitmap) != pgsize))
+   return -EINVAL;
+
+   if (cfg->quirks & IO_PGTABLE_QUIRK_ARM_TTBR1)
+   iaext = ~iaext;
+   if (WARN_ON(iaext || paddr >> cfg->oas))
+   return -ERANGE;
+
+   prot = arm_lpae_prot_to_pte(data, iommu_prot);
+
+   /*
+* Calculating the page table size here helps avoid situations where
+* a page range that is being mapped may be mapped at the same level
+* but not mapped by the same tables. Allowing such a scenario to
+* occur can complicate the logic in __arm_lpae_map().
+*/
+   last_lvl = ARM_LPAE_BLOCK_SIZE_LVL(pgsize, data);
+
+   if (last_lvl == data->start_level)
+   table_size = ARM_LPAE_PGD_SIZE(data);
+   else
+   table_size = ARM_LPAE_GRANULE(data);
+
+   max_entries = table_size / sizeof(*ptep);
+
+   while (pgcount) {
+   tbl_offset = ARM_LPAE_LVL_IDX(iova, last_lvl, data);
+   pages = min_t(size_t, pgcount, max_entries - tbl_offset);
+ 

[PATCH v2 09/12] iommu/io-pgtable-arm: Implement arm_lpae_unmap_pages()

2021-04-01 Thread Isaac J. Manjarres
Implement the unmap_pages() callback for the ARM LPAE io-pgtable
format.

Signed-off-by: Isaac J. Manjarres 
Suggested-by: Will Deacon 
---
 drivers/iommu/io-pgtable-arm.c | 124 +++--
 1 file changed, 104 insertions(+), 20 deletions(-)

diff --git a/drivers/iommu/io-pgtable-arm.c b/drivers/iommu/io-pgtable-arm.c
index 87def58e79b5..fc63d57b8037 100644
--- a/drivers/iommu/io-pgtable-arm.c
+++ b/drivers/iommu/io-pgtable-arm.c
@@ -60,6 +60,14 @@
 /* Calculate the block/page mapping size at level l for pagetable in d. */
 #define ARM_LPAE_BLOCK_SIZE(l,d)   (1ULL << ARM_LPAE_LVL_SHIFT(l,d))
 
+/*
+ * Calculate the level that corresponds to the block/page mapping for pagetable
+ * in d.
+ */
+#define ARM_LPAE_BLOCK_SIZE_LVL(s, d)  \
+   ((ARM_LPAE_MAX_LEVELS - \
+ ((ilog2((s)) - ilog2(sizeof(arm_lpae_iopte))) / (d)->bits_per_level)))
+
 /* Page table bits */
 #define ARM_LPAE_PTE_TYPE_SHIFT0
 #define ARM_LPAE_PTE_TYPE_MASK 0x3
@@ -248,10 +256,26 @@ static void __arm_lpae_set_pte(arm_lpae_iopte *ptep, 
arm_lpae_iopte pte,
__arm_lpae_sync_pte(ptep, cfg);
 }
 
+static void __arm_lpae_sync_ptes(arm_lpae_iopte *ptep, size_t num_ptes,
+struct io_pgtable_cfg *cfg)
+{
+   dma_sync_single_for_device(cfg->iommu_dev, __arm_lpae_dma_addr(ptep),
+  sizeof(*ptep) * num_ptes, DMA_TO_DEVICE);
+}
+
+static void __arm_lpae_clear_ptes(arm_lpae_iopte *ptep, size_t num_ptes,
+ struct io_pgtable_cfg *cfg)
+{
+   memset(ptep, 0, sizeof(*ptep) * num_ptes);
+
+   if (!cfg->coherent_walk)
+   __arm_lpae_sync_ptes(ptep, num_ptes, cfg);
+}
+
 static size_t __arm_lpae_unmap(struct arm_lpae_io_pgtable *data,
   struct iommu_iotlb_gather *gather,
-  unsigned long iova, size_t size, int lvl,
-  arm_lpae_iopte *ptep);
+  unsigned long iova, size_t size, size_t pgcount,
+  int lvl, arm_lpae_iopte *ptep);
 
 static void __arm_lpae_init_pte(struct arm_lpae_io_pgtable *data,
phys_addr_t paddr, arm_lpae_iopte prot,
@@ -289,7 +313,7 @@ static int arm_lpae_init_pte(struct arm_lpae_io_pgtable 
*data,
size_t sz = ARM_LPAE_BLOCK_SIZE(lvl, data);
 
tblp = ptep - ARM_LPAE_LVL_IDX(iova, lvl, data);
-   if (__arm_lpae_unmap(data, NULL, iova, sz, lvl, tblp) != sz) {
+   if (__arm_lpae_unmap(data, NULL, iova, sz, 1, lvl, tblp) != sz) 
{
WARN_ON(1);
return -EINVAL;
}
@@ -516,14 +540,14 @@ static size_t arm_lpae_split_blk_unmap(struct 
arm_lpae_io_pgtable *data,
   struct iommu_iotlb_gather *gather,
   unsigned long iova, size_t size,
   arm_lpae_iopte blk_pte, int lvl,
-  arm_lpae_iopte *ptep)
+  arm_lpae_iopte *ptep, size_t pgcount)
 {
struct io_pgtable_cfg *cfg = &data->iop.cfg;
arm_lpae_iopte pte, *tablep;
phys_addr_t blk_paddr;
size_t tablesz = ARM_LPAE_GRANULE(data);
size_t split_sz = ARM_LPAE_BLOCK_SIZE(lvl, data);
-   int i, unmap_idx = -1;
+   int i, unmap_idx_start = -1;
 
if (WARN_ON(lvl == ARM_LPAE_MAX_LEVELS))
return 0;
@@ -533,14 +557,14 @@ static size_t arm_lpae_split_blk_unmap(struct 
arm_lpae_io_pgtable *data,
return 0; /* Bytes unmapped */
 
if (size == split_sz)
-   unmap_idx = ARM_LPAE_LVL_IDX(iova, lvl, data);
+   unmap_idx_start = ARM_LPAE_LVL_IDX(iova, lvl, data);
 
blk_paddr = iopte_to_paddr(blk_pte, data);
pte = iopte_prot(blk_pte);
 
for (i = 0; i < tablesz / sizeof(pte); i++, blk_paddr += split_sz) {
/* Unmap! */
-   if (i == unmap_idx)
+   if (i >= unmap_idx_start && i < (unmap_idx_start + pgcount))
continue;
 
__arm_lpae_init_pte(data, blk_paddr, pte, lvl, &tablep[i]);
@@ -558,20 +582,24 @@ static size_t arm_lpae_split_blk_unmap(struct 
arm_lpae_io_pgtable *data,
return 0;
 
tablep = iopte_deref(pte, data);
-   } else if (unmap_idx >= 0) {
-   io_pgtable_tlb_add_page(&data->iop, gather, iova, size);
-   return size;
+   } else if (unmap_idx_start >= 0) {
+   for (i = 0; i < pgcount; i++) {
+   io_pgtable_tlb_add_page(&data->iop, gather, iova, size);
+   iova += size;
+   }
+   return pgcount * size;
}
 
-   return __arm_lpa

[PATCH v2 07/12] iommu: Hook up '->unmap_pages' driver callback

2021-04-01 Thread Isaac J. Manjarres
From: Will Deacon 

Extend iommu_pgsize() to populate an optional 'count' paramater so that
we can direct unmapping operation to the ->unmap_pages callback if it
has been provided by the driver.

Signed-off-by: Will Deacon 
Signed-off-by: Isaac J. Manjarres 
---
 drivers/iommu/iommu.c | 60 ---
 1 file changed, 51 insertions(+), 9 deletions(-)

diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index a3bbf7e310b0..5cae2a29fdc9 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -2358,11 +2358,11 @@ phys_addr_t iommu_iova_to_phys(struct iommu_domain 
*domain, dma_addr_t iova)
 EXPORT_SYMBOL_GPL(iommu_iova_to_phys);
 
 static size_t iommu_pgsize(struct iommu_domain *domain, unsigned long iova,
-  phys_addr_t paddr, size_t size)
+  phys_addr_t paddr, size_t size, size_t *count)
 {
-   unsigned int pgsize_idx;
+   unsigned int pgsize_idx, pgsize_idx_next;
unsigned long pgsizes;
-   size_t pgsize;
+   size_t offset, pgsize, pgsize_next;
phys_addr_t addr_merge = paddr | iova;
 
/* Page sizes supported by the hardware and small enough for @size */
@@ -2378,7 +2378,37 @@ static size_t iommu_pgsize(struct iommu_domain *domain, 
unsigned long iova,
/* Pick the biggest page size remaining */
pgsize_idx = __fls(pgsizes);
pgsize = BIT_ULL(pgsize_idx);
+   if (!count)
+   return pgsize;
 
+
+   /* Find the next biggest support page size, if it exists */
+   pgsizes = domain->pgsize_bitmap & ~GENMASK(pgsize_idx, 0);
+   if (!pgsizes)
+   goto out_set_count;
+
+   pgsize_idx_next = __ffs(pgsizes);
+   pgsize_next = BIT(pgsize_idx_next);
+
+   /*
+* There's no point trying a bigger page size unless the virtual
+* and physical addresses are similarly offset within the larger page.
+*/
+   if ((iova ^ paddr) & (pgsize_next - 1))
+   goto out_set_count;
+
+   /* Calculate the offset to the next page size alignment boundary */
+   offset = pgsize_next - (addr_merge & (pgsize_next - 1));
+
+   /*
+* If size is big enough to accomodate the larger page, reduce
+* the number of smaller pages.
+*/
+   if (offset + pgsize_next <= size)
+   size = offset;
+
+out_set_count:
+   *count = size >> pgsize_idx;
return pgsize;
 }
 
@@ -2416,7 +2446,7 @@ static int __iommu_map(struct iommu_domain *domain, 
unsigned long iova,
pr_debug("map: iova 0x%lx pa %pa size 0x%zx\n", iova, &paddr, size);
 
while (size) {
-   size_t pgsize = iommu_pgsize(domain, iova, paddr, size);
+   size_t pgsize = iommu_pgsize(domain, iova, paddr, size, NULL);
 
pr_debug("mapping: iova 0x%lx pa %pa pgsize 0x%zx\n",
 iova, &paddr, pgsize);
@@ -2467,6 +2497,19 @@ int iommu_map_atomic(struct iommu_domain *domain, 
unsigned long iova,
 }
 EXPORT_SYMBOL_GPL(iommu_map_atomic);
 
+static size_t __iommu_unmap_pages(struct iommu_domain *domain,
+ unsigned long iova, size_t size,
+ struct iommu_iotlb_gather *iotlb_gather)
+{
+   const struct iommu_ops *ops = domain->ops;
+   size_t pgsize, count;
+
+   pgsize = iommu_pgsize(domain, iova, iova, size, &count);
+   return ops->unmap_pages ?
+  ops->unmap_pages(domain, iova, pgsize, count, iotlb_gather) :
+  ops->unmap(domain, iova, pgsize, iotlb_gather);
+}
+
 static size_t __iommu_unmap(struct iommu_domain *domain,
unsigned long iova, size_t size,
struct iommu_iotlb_gather *iotlb_gather)
@@ -2476,7 +2519,7 @@ static size_t __iommu_unmap(struct iommu_domain *domain,
unsigned long orig_iova = iova;
unsigned int min_pagesz;
 
-   if (unlikely(ops->unmap == NULL ||
+   if (unlikely((ops->unmap == NULL && ops->unmap_pages == NULL) ||
 domain->pgsize_bitmap == 0UL))
return 0;
 
@@ -2504,10 +2547,9 @@ static size_t __iommu_unmap(struct iommu_domain *domain,
 * or we hit an area that isn't mapped.
 */
while (unmapped < size) {
-   size_t pgsize;
-
-   pgsize = iommu_pgsize(domain, iova, iova, size - unmapped);
-   unmapped_page = ops->unmap(domain, iova, pgsize, iotlb_gather);
+   unmapped_page = __iommu_unmap_pages(domain, iova,
+   size - unmapped,
+   iotlb_gather);
if (!unmapped_page)
break;
 
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project

___
iommu mailing list
iommu@lists.linux-foundation.org

[PATCH v2 12/12] iommu/arm-smmu: Implement the map_pages() IOMMU driver callback

2021-04-01 Thread Isaac J. Manjarres
Implement the unmap_pages() callback for the ARM SMMU driver
to allow calls from iommu_unmap to unmap multiple pages of
the same size in one call.

Signed-off-by: Isaac J. Manjarres 
Suggested-by: Will Deacon 
---
 drivers/iommu/arm/arm-smmu/arm-smmu.c | 19 +++
 1 file changed, 19 insertions(+)

diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu.c 
b/drivers/iommu/arm/arm-smmu/arm-smmu.c
index f29f1fb109f8..fe7a452ce24e 100644
--- a/drivers/iommu/arm/arm-smmu/arm-smmu.c
+++ b/drivers/iommu/arm/arm-smmu/arm-smmu.c
@@ -1208,6 +1208,24 @@ static int arm_smmu_map(struct iommu_domain *domain, 
unsigned long iova,
return ret;
 }
 
+static int arm_smmu_map_pages(struct iommu_domain *domain, unsigned long iova,
+ phys_addr_t paddr, size_t pgsize, size_t pgcount,
+ int prot, gfp_t gfp, size_t *mapped)
+{
+   struct io_pgtable_ops *ops = to_smmu_domain(domain)->pgtbl_ops;
+   struct arm_smmu_device *smmu = to_smmu_domain(domain)->smmu;
+   int ret;
+
+   if (!ops)
+   return -ENODEV;
+
+   arm_smmu_rpm_get(smmu);
+   ret = ops->map_pages(ops, iova, paddr, pgsize, pgcount, prot, gfp, 
mapped);
+   arm_smmu_rpm_put(smmu);
+
+   return ret;
+}
+
 static size_t arm_smmu_unmap(struct iommu_domain *domain, unsigned long iova,
 size_t size, struct iommu_iotlb_gather *gather)
 {
@@ -1642,6 +1660,7 @@ static struct iommu_ops arm_smmu_ops = {
.domain_free= arm_smmu_domain_free,
.attach_dev = arm_smmu_attach_dev,
.map= arm_smmu_map,
+   .map_pages  = arm_smmu_map_pages,
.unmap  = arm_smmu_unmap,
.unmap_pages= arm_smmu_unmap_pages,
.flush_iotlb_all= arm_smmu_flush_iotlb_all,
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v2 06/12] iommu: Split 'addr_merge' argument to iommu_pgsize() into separate parts

2021-04-01 Thread Isaac J. Manjarres
From: Will Deacon 

The 'addr_merge' parameter to iommu_pgsize() is a fabricated address
intended to describe the alignment requirements to consider when
choosing an appropriate page size. On the iommu_map() path, this address
is the logical OR of the virtual and physical addresses.

Subsequent improvements to iommu_pgsize() will need to check the
alignment of the virtual and physical components of 'addr_merge'
independently, so pass them in as separate parameters and reconstruct
'addr_merge' locally.

No functional change.

Signed-off-by: Will Deacon 
Signed-off-by: Isaac J. Manjarres 
---
 drivers/iommu/iommu.c | 10 ++
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 9006397b6604..a3bbf7e310b0 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -2357,12 +2357,13 @@ phys_addr_t iommu_iova_to_phys(struct iommu_domain 
*domain, dma_addr_t iova)
 }
 EXPORT_SYMBOL_GPL(iommu_iova_to_phys);
 
-static size_t iommu_pgsize(struct iommu_domain *domain,
-  unsigned long addr_merge, size_t size)
+static size_t iommu_pgsize(struct iommu_domain *domain, unsigned long iova,
+  phys_addr_t paddr, size_t size)
 {
unsigned int pgsize_idx;
unsigned long pgsizes;
size_t pgsize;
+   phys_addr_t addr_merge = paddr | iova;
 
/* Page sizes supported by the hardware and small enough for @size */
pgsizes = domain->pgsize_bitmap & GENMASK_ULL(__fls(size), 0);
@@ -2415,7 +2416,7 @@ static int __iommu_map(struct iommu_domain *domain, 
unsigned long iova,
pr_debug("map: iova 0x%lx pa %pa size 0x%zx\n", iova, &paddr, size);
 
while (size) {
-   size_t pgsize = iommu_pgsize(domain, iova | paddr, size);
+   size_t pgsize = iommu_pgsize(domain, iova, paddr, size);
 
pr_debug("mapping: iova 0x%lx pa %pa pgsize 0x%zx\n",
 iova, &paddr, pgsize);
@@ -2503,8 +2504,9 @@ static size_t __iommu_unmap(struct iommu_domain *domain,
 * or we hit an area that isn't mapped.
 */
while (unmapped < size) {
-   size_t pgsize = iommu_pgsize(domain, iova, size - unmapped);
+   size_t pgsize;
 
+   pgsize = iommu_pgsize(domain, iova, iova, size - unmapped);
unmapped_page = ops->unmap(domain, iova, pgsize, iotlb_gather);
if (!unmapped_page)
break;
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[RFC PATCH v2 00/12] Optimizing iommu_[map/unmap] performance

2021-04-01 Thread Isaac J. Manjarres
When unmapping a buffer from an IOMMU domain, the IOMMU framework unmaps
the buffer at a granule of the largest page size that is supported by
the IOMMU hardware and fits within the buffer. For every block that
is unmapped, the IOMMU framework will call into the IOMMU driver, and
then the io-pgtable framework to walk the page tables to find the entry
that corresponds to the IOVA, and then unmaps the entry.

This can be suboptimal in scenarios where a buffer or a piece of a
buffer can be split into several contiguous page blocks of the same size.
For example, consider an IOMMU that supports 4 KB page blocks, 2 MB page
blocks, and 1 GB page blocks, and a buffer that is 4 MB in size is being
unmapped at IOVA 0. The current call-flow will result in 4 indirect calls,
and 2 page table walks, to unmap 2 entries that are next to each other in
the page-tables, when both entries could have been unmapped in one shot
by clearing both page table entries in the same call.

The same optimization is applicable to mapping buffers as well, so
these patches implement a set of callbacks called unmap_pages and
map_pages to the io-pgtable code and IOMMU drivers which unmaps or maps
an IOVA range that consists of a number of pages of the same
page size that is supported by the IOMMU hardware, and allows for
manipulating multiple page table entries in the same set of indirect
calls. The reason for introducing these callbacks is to give other IOMMU
drivers/io-pgtable formats time to change to using the new callbacks, so
that the transition to using this approach can be done piecemeal.

Changes since V1:

* Implemented the map_pages() callbacks
* Integrated Will's patches into this series which
  address several concerns about how iommu_pgsize() partitioned a
  buffer (I made a minor change to the patch which changes
  iommu_pgsize() to use bitmaps by using the ULL variants of
  the bitops)

Any feedback is very much appreciated.

Isaac J. Manjarres (9):
  iommu/io-pgtable: Introduce unmap_pages() as a page table op
  iommu: Add an unmap_pages() op for IOMMU drivers
  iommu/io-pgtable: Introduce map_pages() as a page table op
  iommu: Add a map_pages() op for IOMMU drivers
  iommu: Add support for the map_pages() callback
  iommu/io-pgtable-arm: Implement arm_lpae_unmap_pages()
  iommu/io-pgtable-arm: Implement arm_lpae_map_pages()
  iommu/arm-smmu: Implement the unmap_pages() IOMMU driver callback
  iommu/arm-smmu: Implement the map_pages() IOMMU driver callback

Will Deacon (3):
  iommu: Use bitmap to calculate page size in iommu_pgsize()
  iommu: Split 'addr_merge' argument to iommu_pgsize() into separate
parts
  iommu: Hook up '->unmap_pages' driver callback

 drivers/iommu/arm/arm-smmu/arm-smmu.c |  38 +
 drivers/iommu/io-pgtable-arm.c| 219 ++
 drivers/iommu/iommu.c | 128 +++
 include/linux/io-pgtable.h|   8 +
 include/linux/iommu.h |   9 ++
 5 files changed, 343 insertions(+), 59 deletions(-)

-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v2 08/12] iommu: Add support for the map_pages() callback

2021-04-01 Thread Isaac J. Manjarres
Since iommu_pgsize can calculate how many pages of the
same size can be mapped/unmapped before the next largest
page size boundary, add support for invoking an IOMMU
driver's map_pages() callback, if it provides one.

Signed-off-by: Isaac J. Manjarres 
Suggested-by: Will Deacon 
---
 drivers/iommu/iommu.c | 41 ++---
 1 file changed, 34 insertions(+), 7 deletions(-)

diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 5cae2a29fdc9..167983195858 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -2412,6 +2412,30 @@ static size_t iommu_pgsize(struct iommu_domain *domain, 
unsigned long iova,
return pgsize;
 }
 
+static int __iommu_map_pages(struct iommu_domain *domain, unsigned long iova,
+phys_addr_t paddr, size_t size, int prot,
+gfp_t gfp, size_t *mapped)
+{
+   const struct iommu_ops *ops = domain->ops;
+   size_t pgsize, count;
+   int ret;
+
+   pgsize = iommu_pgsize(domain, iova, paddr, size, &count);
+
+   pr_debug("mapping: iova 0x%lx pa %pa pgsize 0x%zx count %ld\n",
+iova, &paddr, pgsize, count);
+
+   if (ops->map_pages) {
+   ret = ops->map_pages(domain, iova, paddr, pgsize, count, prot,
+gfp, mapped);
+   } else {
+   ret = ops->map(domain, iova, paddr, pgsize, prot, gfp);
+   *mapped = ret ? 0 : pgsize;
+   }
+
+   return ret;
+}
+
 static int __iommu_map(struct iommu_domain *domain, unsigned long iova,
   phys_addr_t paddr, size_t size, int prot, gfp_t gfp)
 {
@@ -2446,18 +2470,21 @@ static int __iommu_map(struct iommu_domain *domain, 
unsigned long iova,
pr_debug("map: iova 0x%lx pa %pa size 0x%zx\n", iova, &paddr, size);
 
while (size) {
-   size_t pgsize = iommu_pgsize(domain, iova, paddr, size, NULL);
+   size_t mapped = 0;
 
-   pr_debug("mapping: iova 0x%lx pa %pa pgsize 0x%zx\n",
-iova, &paddr, pgsize);
-   ret = ops->map(domain, iova, paddr, pgsize, prot, gfp);
+   ret = __iommu_map_pages(domain, iova, paddr, size, prot, gfp,
+   &mapped);
+   /*
+* Some pages may have been mapped, even if an error occurred,
+* so we should account for those so they can be unmapped.
+*/
+   size -= mapped;
 
if (ret)
break;
 
-   iova += pgsize;
-   paddr += pgsize;
-   size -= pgsize;
+   iova += mapped;
+   paddr += mapped;
}
 
/* unroll mapping in case something went wrong */
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v2 11/12] iommu/arm-smmu: Implement the unmap_pages() IOMMU driver callback

2021-04-01 Thread Isaac J. Manjarres
Implement the unmap_pages() callback for the ARM SMMU driver
to allow calls from iommu_unmap to unmap multiple pages of
the same size in one call.

Signed-off-by: Isaac J. Manjarres 
Suggested-by: Will Deacon 
---
 drivers/iommu/arm/arm-smmu/arm-smmu.c | 19 +++
 1 file changed, 19 insertions(+)

diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu.c 
b/drivers/iommu/arm/arm-smmu/arm-smmu.c
index d8c6bfde6a61..f29f1fb109f8 100644
--- a/drivers/iommu/arm/arm-smmu/arm-smmu.c
+++ b/drivers/iommu/arm/arm-smmu/arm-smmu.c
@@ -1225,6 +1225,24 @@ static size_t arm_smmu_unmap(struct iommu_domain 
*domain, unsigned long iova,
return ret;
 }
 
+static size_t arm_smmu_unmap_pages(struct iommu_domain *domain, unsigned long 
iova,
+  size_t pgsize, size_t pgcount,
+  struct iommu_iotlb_gather *iotlb_gather)
+{
+   struct io_pgtable_ops *ops = to_smmu_domain(domain)->pgtbl_ops;
+   struct arm_smmu_device *smmu = to_smmu_domain(domain)->smmu;
+   size_t ret;
+
+   if (!ops)
+   return 0;
+
+   arm_smmu_rpm_get(smmu);
+   ret = ops->unmap_pages(ops, iova, pgsize, pgcount, iotlb_gather);
+   arm_smmu_rpm_put(smmu);
+
+   return ret;
+}
+
 static void arm_smmu_flush_iotlb_all(struct iommu_domain *domain)
 {
struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
@@ -1625,6 +1643,7 @@ static struct iommu_ops arm_smmu_ops = {
.attach_dev = arm_smmu_attach_dev,
.map= arm_smmu_map,
.unmap  = arm_smmu_unmap,
+   .unmap_pages= arm_smmu_unmap_pages,
.flush_iotlb_all= arm_smmu_flush_iotlb_all,
.iotlb_sync = arm_smmu_iotlb_sync,
.iova_to_phys   = arm_smmu_iova_to_phys,
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v2 03/12] iommu/io-pgtable: Introduce map_pages() as a page table op

2021-04-01 Thread Isaac J. Manjarres
Mapping memory into io-pgtables follows the same semantics
that unmapping memory used to follow (i.e. a buffer will be
mapped one page block per call to the io-pgtable code). This
means that it can be optimized in the same way that unmapping
memory was, so add a map_pages() callback to the io-pgtable
ops structure, so that a range of pages of the same size
can be mapped within the same call.

Signed-off-by: Isaac J. Manjarres 
Suggested-by: Will Deacon 
---
 include/linux/io-pgtable.h | 4 
 1 file changed, 4 insertions(+)

diff --git a/include/linux/io-pgtable.h b/include/linux/io-pgtable.h
index 2ed0c057d9e7..019149b204b8 100644
--- a/include/linux/io-pgtable.h
+++ b/include/linux/io-pgtable.h
@@ -143,6 +143,7 @@ struct io_pgtable_cfg {
  * struct io_pgtable_ops - Page table manipulation API for IOMMU drivers.
  *
  * @map:  Map a physically contiguous memory region.
+ * @map_pages:Map a physically contiguous range of pages of the same size.
  * @unmap:Unmap a physically contiguous memory region.
  * @unmap_pages:  Unmap a range of virtually contiguous pages of the same size.
  * @iova_to_phys: Translate iova to physical address.
@@ -153,6 +154,9 @@ struct io_pgtable_cfg {
 struct io_pgtable_ops {
int (*map)(struct io_pgtable_ops *ops, unsigned long iova,
   phys_addr_t paddr, size_t size, int prot, gfp_t gfp);
+   int (*map_pages)(struct io_pgtable_ops *ops, unsigned long iova,
+phys_addr_t paddr, size_t pgsize, size_t pgcount,
+int prot, gfp_t gfp, size_t *mapped);
size_t (*unmap)(struct io_pgtable_ops *ops, unsigned long iova,
size_t size, struct iommu_iotlb_gather *gather);
size_t (*unmap_pages)(struct io_pgtable_ops *ops, unsigned long iova,
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v2 05/12] iommu: Use bitmap to calculate page size in iommu_pgsize()

2021-04-01 Thread Isaac J. Manjarres
From: Will Deacon 

Avoid the potential for shifting values by amounts greater than the
width of their type by using a bitmap to compute page size in
iommu_pgsize().

Signed-off-by: Will Deacon 
Signed-off-by: Isaac J. Manjarres 
---
 drivers/iommu/iommu.c | 31 ---
 1 file changed, 12 insertions(+), 19 deletions(-)

diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index d0b0a15dba84..9006397b6604 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -8,6 +8,7 @@
 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -2360,30 +2361,22 @@ static size_t iommu_pgsize(struct iommu_domain *domain,
   unsigned long addr_merge, size_t size)
 {
unsigned int pgsize_idx;
+   unsigned long pgsizes;
size_t pgsize;
 
-   /* Max page size that still fits into 'size' */
-   pgsize_idx = __fls(size);
+   /* Page sizes supported by the hardware and small enough for @size */
+   pgsizes = domain->pgsize_bitmap & GENMASK_ULL(__fls(size), 0);
 
-   /* need to consider alignment requirements ? */
-   if (likely(addr_merge)) {
-   /* Max page size allowed by address */
-   unsigned int align_pgsize_idx = __ffs(addr_merge);
-   pgsize_idx = min(pgsize_idx, align_pgsize_idx);
-   }
-
-   /* build a mask of acceptable page sizes */
-   pgsize = (1UL << (pgsize_idx + 1)) - 1;
-
-   /* throw away page sizes not supported by the hardware */
-   pgsize &= domain->pgsize_bitmap;
+   /* Constrain the page sizes further based on the maximum alignment */
+   if (likely(addr_merge))
+   pgsizes &= GENMASK_ULL(__ffs(addr_merge), 0);
 
-   /* make sure we're still sane */
-   BUG_ON(!pgsize);
+   /* Make sure we have at least one suitable page size */
+   BUG_ON(!pgsizes);
 
-   /* pick the biggest page */
-   pgsize_idx = __fls(pgsize);
-   pgsize = 1UL << pgsize_idx;
+   /* Pick the biggest page size remaining */
+   pgsize_idx = __fls(pgsizes);
+   pgsize = BIT_ULL(pgsize_idx);
 
return pgsize;
 }
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v2 04/12] iommu: Add a map_pages() op for IOMMU drivers

2021-04-01 Thread Isaac J. Manjarres
Add a callback for IOMMU drivers to provide a path for the
IOMMU framework to call into an IOMMU driver, which can
call into the io-pgtable code, to map a physically contiguous
rnage of pages of the same size.

For IOMMU drivers that do not specify a map_pages() callback,
the existing logic of mapping memory one page block at a time
will be used.

Signed-off-by: Isaac J. Manjarres 
Suggested-by: Will Deacon 
---
 include/linux/iommu.h | 5 +
 1 file changed, 5 insertions(+)

diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index 9cf81242581a..528d6a58479e 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -192,6 +192,8 @@ struct iommu_iotlb_gather {
  * @attach_dev: attach device to an iommu domain
  * @detach_dev: detach device from an iommu domain
  * @map: map a physically contiguous memory region to an iommu domain
+ * @map_pages: map a physically contiguous set of pages of the same size to
+ * an iommu domain.
  * @unmap: unmap a physically contiguous memory region from an iommu domain
  * @unmap_pages: unmap a number of pages of the same size from an iommu domain
  * @flush_iotlb_all: Synchronously flush all hardware TLBs for this domain
@@ -244,6 +246,9 @@ struct iommu_ops {
void (*detach_dev)(struct iommu_domain *domain, struct device *dev);
int (*map)(struct iommu_domain *domain, unsigned long iova,
   phys_addr_t paddr, size_t size, int prot, gfp_t gfp);
+   int (*map_pages)(struct iommu_domain *domain, unsigned long iova,
+phys_addr_t paddr, size_t pgsize, size_t pgcount,
+int prot, gfp_t gfp, size_t *mapped);
size_t (*unmap)(struct iommu_domain *domain, unsigned long iova,
 size_t size, struct iommu_iotlb_gather *iotlb_gather);
size_t (*unmap_pages)(struct iommu_domain *domain, unsigned long iova,
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v2 02/12] iommu: Add an unmap_pages() op for IOMMU drivers

2021-04-01 Thread Isaac J. Manjarres
Add a callback for IOMMU drivers to provide a path for the
IOMMU framework to call into an IOMMU driver, which can call
into the io-pgtable code, to unmap a virtually contiguous
range of pages of the same size.

For IOMMU drivers that do not specify an unmap_pages() callback,
the existing logic of unmapping memory one page block at a time
will be used.

Signed-off-by: Isaac J. Manjarres 
Suggested-by: Will Deacon 
Signed-off-by: Will Deacon 
---
 include/linux/iommu.h | 4 
 1 file changed, 4 insertions(+)

diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index 5e7fe519430a..9cf81242581a 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -193,6 +193,7 @@ struct iommu_iotlb_gather {
  * @detach_dev: detach device from an iommu domain
  * @map: map a physically contiguous memory region to an iommu domain
  * @unmap: unmap a physically contiguous memory region from an iommu domain
+ * @unmap_pages: unmap a number of pages of the same size from an iommu domain
  * @flush_iotlb_all: Synchronously flush all hardware TLBs for this domain
  * @iotlb_sync_map: Sync mappings created recently using @map to the hardware
  * @iotlb_sync: Flush all queued ranges from the hardware TLBs and empty flush
@@ -245,6 +246,9 @@ struct iommu_ops {
   phys_addr_t paddr, size_t size, int prot, gfp_t gfp);
size_t (*unmap)(struct iommu_domain *domain, unsigned long iova,
 size_t size, struct iommu_iotlb_gather *iotlb_gather);
+   size_t (*unmap_pages)(struct iommu_domain *domain, unsigned long iova,
+ size_t pgsize, size_t pgcount,
+ struct iommu_iotlb_gather *iotlb_gather);
void (*flush_iotlb_all)(struct iommu_domain *domain);
void (*iotlb_sync_map)(struct iommu_domain *domain, unsigned long iova,
   size_t size);
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH v14 10/10] iommu/arm-smmu-v3: Add stall support for platform devices

2021-04-01 Thread Zhangfei Gao

Hi, Will

On 2021/4/2 上午1:11, Will Deacon wrote:

On Thu, Apr 01, 2021 at 05:47:19PM +0200, Jean-Philippe Brucker wrote:

The SMMU provides a Stall model for handling page faults in platform
devices. It is similar to PCIe PRI, but doesn't require devices to have
their own translation cache. Instead, faulting transactions are parked
and the OS is given a chance to fix the page tables and retry the
transaction.

Enable stall for devices that support it (opt-in by firmware). When an
event corresponds to a translation error, call the IOMMU fault handler.
If the fault is recoverable, it will call us back to terminate or
continue the stall.

Which hardware is this useful for? Stalling adds a fair amount of complexity
to the driver, so I don't think we should support it unless we're likely to
see platforms that both implement it and do something useful with it.
I have tested the stall mode on Hisilicon Kunpeng920 board, as well as 
using drivers/misc/uacce/uacce.c.


Thanks
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

Re: [PATCH v14 09/10] ACPI/IORT: Enable stall support for platform devices

2021-04-01 Thread Hanjun Guo

On 2021/4/1 23:47, Jean-Philippe Brucker wrote:

Copy the "Stall supported" bit, that tells whether a named component
supports stall, into the dma-can-stall device property.

Acked-by: Jonathan Cameron 
Signed-off-by: Jean-Philippe Brucker 
---
  drivers/acpi/arm64/iort.c | 4 +++-
  1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index 3912a1f6058e..0828f70cb782 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -968,13 +968,15 @@ static int iort_pci_iommu_init(struct pci_dev *pdev, u16 
alias, void *data)
  static void iort_named_component_init(struct device *dev,
  struct acpi_iort_node *node)
  {
-   struct property_entry props[2] = {};
+   struct property_entry props[3] = {};
struct acpi_iort_named_component *nc;
  
  	nc = (struct acpi_iort_named_component *)node->node_data;

props[0] = PROPERTY_ENTRY_U32("pasid-num-bits",
  FIELD_GET(ACPI_IORT_NC_PASID_BITS,
nc->node_flags));
+   if (nc->node_flags & ACPI_IORT_NC_STALL_SUPPORTED)
+   props[1] = PROPERTY_ENTRY_BOOL("dma-can-stall");
  
  	if (device_add_properties(dev, props))

dev_warn(dev, "Could not add device properties\n");


Acked-by: Hanjun Guo 
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH v14 02/10] iommu/arm-smmu-v3: Use device properties for pasid-num-bits

2021-04-01 Thread Hanjun Guo

On 2021/4/1 23:47, Jean-Philippe Brucker wrote:

The pasid-num-bits property shouldn't need a dedicated fwspec field,
it's a job for device properties. Add properties for IORT, and access
the number of PASID bits using device_property_read_u32().

Suggested-by: Robin Murphy
Acked-by: Jonathan Cameron
Acked-by: Will Deacon
Reviewed-by: Eric Auger
Signed-off-by: Jean-Philippe Brucker
---
  include/linux/iommu.h   |  2 --
  drivers/acpi/arm64/iort.c   | 13 +++--


Acked-by: Hanjun Guo 
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH] ARM: Qualify enabling of swiotlb_init()

2021-04-01 Thread Florian Fainelli
On 4/1/21 10:33 AM, Konrad Rzeszutek Wilk wrote:
> On Tue, Mar 30, 2021 at 07:36:07AM +0200, Christoph Hellwig wrote:
>> On Mon, Mar 29, 2021 at 12:30:42PM -0700, Florian Fainelli wrote:
>>> Should I toss this in Russell's patch tracker or do you need me to make
>>> some changes to the patch?
>>
>> Due to all the other changes in this area I don't think anything but
>> the swiotlb tree makes much sense here.
> 
> I've put them all on 
> 
> git://git.kernel.org/pub/scm/linux/kernel/git/konrad/swiotlb.git
> devel/for-linus-5.13

Thanks! Did you also want to queue up this one:

https://lore.kernel.org/lkml/20210323015350.399493-1-f.faine...@gmail.com/
-- 
Florian
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH] ARM: Qualify enabling of swiotlb_init()

2021-04-01 Thread Konrad Rzeszutek Wilk
On Tue, Mar 30, 2021 at 07:36:07AM +0200, Christoph Hellwig wrote:
> On Mon, Mar 29, 2021 at 12:30:42PM -0700, Florian Fainelli wrote:
> > Should I toss this in Russell's patch tracker or do you need me to make
> > some changes to the patch?
> 
> Due to all the other changes in this area I don't think anything but
> the swiotlb tree makes much sense here.

I've put them all on 

git://git.kernel.org/pub/scm/linux/kernel/git/konrad/swiotlb.git
devel/for-linus-5.13


___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH V4 05/18] iommu/ioasid: Redefine IOASID set and allocation APIs

2021-04-01 Thread Jason Gunthorpe
On Thu, Apr 01, 2021 at 10:23:55AM -0700, Jacob Pan wrote:
> Hi Jason,
> 
> On Wed, 31 Mar 2021 21:37:05 -0300, Jason Gunthorpe  wrote:
> 
> > On Wed, Mar 31, 2021 at 04:46:21PM -0700, Jacob Pan wrote:
> > > Hi Jason,
> > > 
> > > On Wed, 31 Mar 2021 09:38:01 -0300, Jason Gunthorpe 
> > > wrote: 
> > > > > > Get rid of the ioasid set.
> > > > > >
> > > > > > Each driver has its own list of allowed ioasids.
> > > >  [...]  
> > > > 
> > > > The /dev/ioasid FD replaces this security check. By becoming FD
> > > > centric you don't need additional kernel security objects.
> > > > 
> > > > Any process with access to the /dev/ioasid FD is allowed to control
> > > > those PASID. The seperation between VMs falls naturally from the
> > > > seperation of FDs without creating additional, complicated, security
> > > > infrastrucure in the kernel.
> > > > 
> > > > This is why all APIs must be FD focused, and you need to have a
> > > > logical layering of responsibility.
> > > > 
> > > >  Allocate a /dev/ioasid FD
> > > >  Allocate PASIDs inside the FD
> Just to be super clear. Do we allocate a FD for each PASID and return the
> FD to the user? Or return the plain PASID number back to the user space?

I would do multiple PASID's per /dev/ioasid FD because we expect alot
of PASIDs to be in use and we'd run into FDno limits.

> > > >  Assign memory to the PASIDS
> > > > 
> > > >  Open a device FD, eg from VFIO or VDP
> > > >  Instruct the device FD to authorize the device to access PASID A in
> > > >  an ioasid FD  
> > > How do we know user provided PASID A was allocated by the ioasid FD?  
> > 
> > You pass in the ioasid FD and use a 'get pasid from fdno' API to
> > extract the required kernel structure.
> > 
> Seems you are talking about two FDs:
> - /dev/ioasid FD

No, just this one.

> - per IOASID FD
> This API ioasid = get_pasid_from_fd(dev_ioasid_fd, ioasid_fd);
> dev_ioasid_fd will find the xarray for all the PASIDs allocated under it,
> ioasid_fd wil be the index into the xarray to retrieve the actual ioasid.
> Correct?

'ioasid_fd' is just the ioasid number in whatever numberspace the
/dev/ioasid FD's use.

> > Why only one?  Each interaction with the other FDs should include the
> > PASID/FD pair. There is no restriction to just one.

> OK, one per subsystem-VM. For example, if a VM has a VFIO and a VDPA
> device, it should only two /dev/ioasid FDs respectively. Correct?

No, only one.

For something like qemu's use case I mostly expect the vIOMMU driver
will open /dev/ioasid for each vIOMMU instance it creates (basically
only one)

> > The act of programming the page tables and the act of authorizing a
> > PCI BDF to use a PASID are distinct things with two different IOCTLs.
> > 
> Why separate? 

Because they have different owners and different layers in the
software.

It is not about use case, it is about putting the control points where
they naturally belong.

> For a complex stack like vSVA, I feel we have to reduce moving parts and do
> some divide and conquer.

uAPI should have all come together with a user and user application.

uAPI is hardest and most important part.

Jason
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH V4 05/18] iommu/ioasid: Redefine IOASID set and allocation APIs

2021-04-01 Thread Jacob Pan
Hi Jason,

On Wed, 31 Mar 2021 21:37:05 -0300, Jason Gunthorpe  wrote:

> On Wed, Mar 31, 2021 at 04:46:21PM -0700, Jacob Pan wrote:
> > Hi Jason,
> > 
> > On Wed, 31 Mar 2021 09:38:01 -0300, Jason Gunthorpe 
> > wrote: 
> > > > > Get rid of the ioasid set.
> > > > >
> > > > > Each driver has its own list of allowed ioasids.
> > >  [...]  
> > > 
> > > The /dev/ioasid FD replaces this security check. By becoming FD
> > > centric you don't need additional kernel security objects.
> > > 
> > > Any process with access to the /dev/ioasid FD is allowed to control
> > > those PASID. The seperation between VMs falls naturally from the
> > > seperation of FDs without creating additional, complicated, security
> > > infrastrucure in the kernel.
> > > 
> > > This is why all APIs must be FD focused, and you need to have a
> > > logical layering of responsibility.
> > > 
> > >  Allocate a /dev/ioasid FD
> > >  Allocate PASIDs inside the FD
Just to be super clear. Do we allocate a FD for each PASID and return the
FD to the user? Or return the plain PASID number back to the user space?

> > >  Assign memory to the PASIDS
> > > 
> > >  Open a device FD, eg from VFIO or VDP
> > >  Instruct the device FD to authorize the device to access PASID A in
> > >  an ioasid FD  
> > How do we know user provided PASID A was allocated by the ioasid FD?  
> 
> You pass in the ioasid FD and use a 'get pasid from fdno' API to
> extract the required kernel structure.
> 
Seems you are talking about two FDs:
- /dev/ioasid FD
- per IOASID FD
This API ioasid = get_pasid_from_fd(dev_ioasid_fd, ioasid_fd);
dev_ioasid_fd will find the xarray for all the PASIDs allocated under it,
ioasid_fd wil be the index into the xarray to retrieve the actual ioasid.
Correct?

> > Shouldn't we validate user input by tracking which PASIDs are
> > allocated by which ioasid FD?  
> 
> Yes, but it is integral to the ioasid FD, not something separated.
> 
OK, if we have per IOASID FD in addition to the /dev/ioasid FD we can
validate user input.

> > > VFIO extracts some kernel representation of the ioasid from the ioasid
> > > fd using an API
> > >   
> > This lookup API seems to be asking for per ioasid FD storage array.
> > Today, the ioasid_set is per mm and contains a Xarray.   
> 
> Right, put the xarray per FD. A set per mm is fairly nonsensical, we
> don't use the mm as that kind of security key.
> 
Sounds good, one xarray per /dev/ioasid FD.

> > Since each VM, KVM can only open one ioasid FD, this per FD array
> > would be equivalent to the per mm ioasid_set, right?  
> 
> Why only one?  Each interaction with the other FDs should include the
> PASID/FD pair. There is no restriction to just one.
> 
OK, one per subsystem-VM. For example, if a VM has a VFIO and a VDPA
device, it should only two /dev/ioasid FDs respectively. Correct?

> > > VFIO does some kernel call to IOMMU/IOASID layer that says 'tell the
> > > IOMMU that this PCI device is allowed to use this PASID'  
> >
> > Would it be redundant to what iommu_uapi_sva_bind_gpasid() does? I
> > thought the idea is to use ioasid FD IOCTL to issue IOMMU uAPI calls.
> > Or we can skip this step for now and wait for the user to do SVA bind.  
> 
> I'm not sure what you are asking.
> 
> Possibly some of the IOMMU API will need a bit adjusting to make
> things split.
> 
> The act of programming the page tables and the act of authorizing a
> PCI BDF to use a PASID are distinct things with two different IOCTLs.
> 
Why separate? I don't see a use case to just authorize a PASID but don't
bind it with a page table. The very act of bind page table *is* the
authorization.

> iommu_uapi_sva_bind_gpasid() is never called by anything, and it's
> uAPI is never implemented.
> 
Just a little background here. We have been working on the vSVA stack
since 2017. At the time, VFIO was the de facto interface for IOMMU-aware
driver framework. These uAPIs were always developed alone side with the
accompanying VFIO patches served as consumers. By the time these IOMMU uAPIs
were merged after reviews from most vendors, the VFIO patchset was
approaching maturity in around v7. This is when we suddenly saw a new
request to support VDPA, which attempted VFIO earlier but ultimately moved
away.

For a complex stack like vSVA, I feel we have to reduce moving parts and do
some divide and conquer.

> Joerg? Why did you merge dead uapi and dead code?
> 
> Jason


Thanks,

Jacob
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [RFC PATCH 4/5] iommu/io-pgtable-arm: Implement arm_lpae_unmap_pages()

2021-04-01 Thread Robin Murphy

On 2021-03-31 04:00, Isaac J. Manjarres wrote:

Implement the unmap_pages() callback for the ARM LPAE io-pgtable
format.

Signed-off-by: Isaac J. Manjarres 
Suggested-by: Will Deacon 
---
  drivers/iommu/io-pgtable-arm.c | 114 +++--
  1 file changed, 94 insertions(+), 20 deletions(-)

diff --git a/drivers/iommu/io-pgtable-arm.c b/drivers/iommu/io-pgtable-arm.c
index 87def58e79b5..6eccebf1744d 100644
--- a/drivers/iommu/io-pgtable-arm.c
+++ b/drivers/iommu/io-pgtable-arm.c
@@ -248,10 +248,26 @@ static void __arm_lpae_set_pte(arm_lpae_iopte *ptep, 
arm_lpae_iopte pte,
__arm_lpae_sync_pte(ptep, cfg);
  }
  
+static void __arm_lpae_sync_ptes(arm_lpae_iopte *ptep, size_t num_ptes,

+struct io_pgtable_cfg *cfg)
+{
+   dma_sync_single_for_device(cfg->iommu_dev, __arm_lpae_dma_addr(ptep),
+  sizeof(*ptep) * num_ptes, DMA_TO_DEVICE);
+}
+
+static void __arm_lpae_clear_ptes(arm_lpae_iopte *ptep, size_t num_ptes,
+ struct io_pgtable_cfg *cfg)
+{
+   memset(ptep, 0, sizeof(*ptep) * num_ptes);
+
+   if (!cfg->coherent_walk)
+   __arm_lpae_sync_ptes(ptep, num_ptes, cfg);
+}
+


It seesm like overkill to add separate functions - the existing ones 
could easily just take an extra argument, like we do for the v7s format.



  static size_t __arm_lpae_unmap(struct arm_lpae_io_pgtable *data,
   struct iommu_iotlb_gather *gather,
-  unsigned long iova, size_t size, int lvl,
-  arm_lpae_iopte *ptep);
+  unsigned long iova, size_t size, size_t pgcount,
+  int lvl, arm_lpae_iopte *ptep);
  
  static void __arm_lpae_init_pte(struct arm_lpae_io_pgtable *data,

phys_addr_t paddr, arm_lpae_iopte prot,
@@ -289,7 +305,7 @@ static int arm_lpae_init_pte(struct arm_lpae_io_pgtable 
*data,
size_t sz = ARM_LPAE_BLOCK_SIZE(lvl, data);
  
  		tblp = ptep - ARM_LPAE_LVL_IDX(iova, lvl, data);

-   if (__arm_lpae_unmap(data, NULL, iova, sz, lvl, tblp) != sz) {
+   if (__arm_lpae_unmap(data, NULL, iova, sz, 1, lvl, tblp) != sz) 
{
WARN_ON(1);
return -EINVAL;
}
@@ -516,14 +532,14 @@ static size_t arm_lpae_split_blk_unmap(struct 
arm_lpae_io_pgtable *data,
   struct iommu_iotlb_gather *gather,
   unsigned long iova, size_t size,
   arm_lpae_iopte blk_pte, int lvl,
-  arm_lpae_iopte *ptep)
+  arm_lpae_iopte *ptep, size_t pgcount)
  {
struct io_pgtable_cfg *cfg = &data->iop.cfg;
arm_lpae_iopte pte, *tablep;
phys_addr_t blk_paddr;
size_t tablesz = ARM_LPAE_GRANULE(data);
size_t split_sz = ARM_LPAE_BLOCK_SIZE(lvl, data);
-   int i, unmap_idx = -1;
+   int i, unmap_idx_start = -1;
  
  	if (WARN_ON(lvl == ARM_LPAE_MAX_LEVELS))

return 0;
@@ -533,14 +549,14 @@ static size_t arm_lpae_split_blk_unmap(struct 
arm_lpae_io_pgtable *data,
return 0; /* Bytes unmapped */
  
  	if (size == split_sz)

-   unmap_idx = ARM_LPAE_LVL_IDX(iova, lvl, data);
+   unmap_idx_start = ARM_LPAE_LVL_IDX(iova, lvl, data);
  
  	blk_paddr = iopte_to_paddr(blk_pte, data);

pte = iopte_prot(blk_pte);
  
  	for (i = 0; i < tablesz / sizeof(pte); i++, blk_paddr += split_sz) {

/* Unmap! */
-   if (i == unmap_idx)
+   if (i >= unmap_idx_start && i < (unmap_idx_start + pgcount))
continue;
  
  		__arm_lpae_init_pte(data, blk_paddr, pte, lvl, &tablep[i]);

@@ -558,20 +574,24 @@ static size_t arm_lpae_split_blk_unmap(struct 
arm_lpae_io_pgtable *data,
return 0;
  
  		tablep = iopte_deref(pte, data);

-   } else if (unmap_idx >= 0) {
-   io_pgtable_tlb_add_page(&data->iop, gather, iova, size);
-   return size;
+   } else if (unmap_idx_start >= 0) {
+   for (i = 0; i < pgcount; i++) {
+   io_pgtable_tlb_add_page(&data->iop, gather, iova, size);
+   iova += size;
+   }
+   return pgcount * size;
}
  
-	return __arm_lpae_unmap(data, gather, iova, size, lvl, tablep);

+   return __arm_lpae_unmap(data, gather, iova, size, pgcount, lvl, tablep);
  }
  
  static size_t __arm_lpae_unmap(struct arm_lpae_io_pgtable *data,

   struct iommu_iotlb_gather *gather,
-  unsigned long iova, size_t size, int lvl,
-  arm_lpae_iopte *ptep)
+  unsigned long iova, size_t size,

Re: [PATCH v14 00/10] iommu: I/O page faults for SMMUv3

2021-04-01 Thread Will Deacon
On Thu, Apr 01, 2021 at 05:47:09PM +0200, Jean-Philippe Brucker wrote:
> Add stall support to the SMMUv3 driver, along with a common I/O Page
> Fault handler.
> 
> Since [v13] I added review and ack tags (Thanks!), and a lockdep_assert.
> It would be good to have all of it in v5.13, since patch 10 introduces
> the first user for the IOPF interface from patch 6.  But if that's not
> possible, please pick patches 1-6 so the Vt-d driver can start using
> them.

Patches 1-7 look good to me, but I'm not convinced about the utility of
stalling faults so I'd prefer the later patches to come along with a
real user.

Will
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH v14 10/10] iommu/arm-smmu-v3: Add stall support for platform devices

2021-04-01 Thread Will Deacon
On Thu, Apr 01, 2021 at 05:47:19PM +0200, Jean-Philippe Brucker wrote:
> The SMMU provides a Stall model for handling page faults in platform
> devices. It is similar to PCIe PRI, but doesn't require devices to have
> their own translation cache. Instead, faulting transactions are parked
> and the OS is given a chance to fix the page tables and retry the
> transaction.
> 
> Enable stall for devices that support it (opt-in by firmware). When an
> event corresponds to a translation error, call the IOMMU fault handler.
> If the fault is recoverable, it will call us back to terminate or
> continue the stall.

Which hardware is this useful for? Stalling adds a fair amount of complexity
to the driver, so I don't think we should support it unless we're likely to
see platforms that both implement it and do something useful with it.

Will
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH v14 07/10] iommu/arm-smmu-v3: Maintain a SID->device structure

2021-04-01 Thread Will Deacon
On Thu, Apr 01, 2021 at 05:47:16PM +0200, Jean-Philippe Brucker wrote:
> When handling faults from the event or PRI queue, we need to find the
> struct device associated with a SID. Add a rb_tree to keep track of
> SIDs.
> 
> Acked-by: Jonathan Cameron 
> Reviewed-by: Eric Auger 
> Reviewed-by: Keqian Zhu 
> Signed-off-by: Jean-Philippe Brucker 

Acked-by: Will Deacon 

Will
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH 14/20] iommu: remove DOMAIN_ATTR_PAGING

2021-04-01 Thread Christoph Hellwig
DOMAIN_ATTR_PAGING is never used.

Signed-off-by: Christoph Hellwig 
Acked-by: Will Deacon 
Acked-by: Li Yang 
---
 drivers/iommu/iommu.c | 5 -
 include/linux/iommu.h | 1 -
 2 files changed, 6 deletions(-)

diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index b212bf0261820b..9a4cda390993e6 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -2668,7 +2668,6 @@ int iommu_domain_get_attr(struct iommu_domain *domain,
  enum iommu_attr attr, void *data)
 {
struct iommu_domain_geometry *geometry;
-   bool *paging;
int ret = 0;
 
switch (attr) {
@@ -2676,10 +2675,6 @@ int iommu_domain_get_attr(struct iommu_domain *domain,
geometry  = data;
*geometry = domain->geometry;
 
-   break;
-   case DOMAIN_ATTR_PAGING:
-   paging  = data;
-   *paging = (domain->pgsize_bitmap != 0UL);
break;
default:
if (!domain->ops->domain_get_attr)
diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index 840864844027dc..180ff4bd7fa7ef 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -108,7 +108,6 @@ enum iommu_cap {
 
 enum iommu_attr {
DOMAIN_ATTR_GEOMETRY,
-   DOMAIN_ATTR_PAGING,
DOMAIN_ATTR_NESTING,/* two stages of translation */
DOMAIN_ATTR_DMA_USE_FLUSH_QUEUE,
DOMAIN_ATTR_IO_PGTABLE_CFG,
-- 
2.30.1

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH 20/20] iommu: remove iommu_domain_{get,set}_attr

2021-04-01 Thread Christoph Hellwig
Remove the now unused iommu attr infrastructure.

Signed-off-by: Christoph Hellwig 
Acked-by: Will Deacon 
---
 drivers/iommu/iommu.c | 26 --
 include/linux/iommu.h | 36 
 2 files changed, 62 deletions(-)

diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index bf7dcd2fc08643..d19944733b9dac 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -2665,32 +2665,6 @@ static int __init iommu_init(void)
 }
 core_initcall(iommu_init);
 
-int iommu_domain_get_attr(struct iommu_domain *domain,
- enum iommu_attr attr, void *data)
-{
-   if (!domain->ops->domain_get_attr)
-   return -EINVAL;
-   return domain->ops->domain_get_attr(domain, attr, data);
-}
-EXPORT_SYMBOL_GPL(iommu_domain_get_attr);
-
-int iommu_domain_set_attr(struct iommu_domain *domain,
- enum iommu_attr attr, void *data)
-{
-   int ret = 0;
-
-   switch (attr) {
-   default:
-   if (domain->ops->domain_set_attr == NULL)
-   return -EINVAL;
-
-   ret = domain->ops->domain_set_attr(domain, attr, data);
-   }
-
-   return ret;
-}
-EXPORT_SYMBOL_GPL(iommu_domain_set_attr);
-
 int iommu_enable_nesting(struct iommu_domain *domain)
 {
if (domain->type != IOMMU_DOMAIN_UNMANAGED)
diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index 4280be90a27956..1a905446dc4ca1 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -96,20 +96,6 @@ enum iommu_cap {
IOMMU_CAP_NOEXEC,   /* IOMMU_NOEXEC flag */
 };
 
-/*
- * Following constraints are specifc to FSL_PAMUV1:
- *  -aperture must be power of 2, and naturally aligned
- *  -number of windows must be power of 2, and address space size
- *   of each window is determined by aperture size / # of windows
- *  -the actual size of the mapped region of a window must be power
- *   of 2 starting with 4KB and physical address must be naturally
- *   aligned.
- */
-
-enum iommu_attr {
-   DOMAIN_ATTR_MAX,
-};
-
 /* These are the possible reserved region types */
 enum iommu_resv_type {
/* Memory regions which must be mapped 1:1 at all times */
@@ -191,8 +177,6 @@ struct iommu_iotlb_gather {
  * @probe_finalize: Do final setup work after the device is added to an IOMMU
  *  group and attached to the groups domain
  * @device_group: find iommu group for a particular device
- * @domain_get_attr: Query domain attributes
- * @domain_set_attr: Change domain attributes
  * @enable_nesting: Enable nesting
  * @set_pgtable_quirks: Set io page table quirks (IO_PGTABLE_QUIRK_*)
  * @get_resv_regions: Request list of reserved regions for a device
@@ -243,10 +227,6 @@ struct iommu_ops {
void (*release_device)(struct device *dev);
void (*probe_finalize)(struct device *dev);
struct iommu_group *(*device_group)(struct device *dev);
-   int (*domain_get_attr)(struct iommu_domain *domain,
-  enum iommu_attr attr, void *data);
-   int (*domain_set_attr)(struct iommu_domain *domain,
-  enum iommu_attr attr, void *data);
int (*enable_nesting)(struct iommu_domain *domain);
int (*set_pgtable_quirks)(struct iommu_domain *domain,
  unsigned long quirks);
@@ -493,10 +473,6 @@ extern int iommu_page_response(struct device *dev,
 extern int iommu_group_id(struct iommu_group *group);
 extern struct iommu_domain *iommu_group_default_domain(struct iommu_group *);
 
-extern int iommu_domain_get_attr(struct iommu_domain *domain, enum iommu_attr,
-void *data);
-extern int iommu_domain_set_attr(struct iommu_domain *domain, enum iommu_attr,
-void *data);
 int iommu_enable_nesting(struct iommu_domain *domain);
 int iommu_set_pgtable_quirks(struct iommu_domain *domain,
unsigned long quirks);
@@ -869,18 +845,6 @@ static inline int iommu_group_id(struct iommu_group *group)
return -ENODEV;
 }
 
-static inline int iommu_domain_get_attr(struct iommu_domain *domain,
-   enum iommu_attr attr, void *data)
-{
-   return -EINVAL;
-}
-
-static inline int iommu_domain_set_attr(struct iommu_domain *domain,
-   enum iommu_attr attr, void *data)
-{
-   return -EINVAL;
-}
-
 static inline int iommu_set_pgtable_quirks(struct iommu_domain *domain,
unsigned long quirks)
 {
-- 
2.30.1

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH 09/20] iommu/fsl_pamu: merge handle_attach_device into fsl_pamu_attach_device

2021-04-01 Thread Christoph Hellwig
No good reason to split this functionality over two functions.

Signed-off-by: Christoph Hellwig 
Acked-by: Will Deacon 
Acked-by: Li Yang 
---
 drivers/iommu/fsl_pamu_domain.c | 59 +++--
 1 file changed, 20 insertions(+), 39 deletions(-)

diff --git a/drivers/iommu/fsl_pamu_domain.c b/drivers/iommu/fsl_pamu_domain.c
index 198725ef27954f..41927c3c417751 100644
--- a/drivers/iommu/fsl_pamu_domain.c
+++ b/drivers/iommu/fsl_pamu_domain.c
@@ -240,45 +240,13 @@ static int update_domain_stash(struct fsl_dma_domain 
*dma_domain, u32 val)
return ret;
 }
 
-/*
- * Attach the LIODN to the DMA domain and configure the geometry
- * and window mappings.
- */
-static int handle_attach_device(struct fsl_dma_domain *dma_domain,
-   struct device *dev, const u32 *liodn,
-   int num)
-{
-   unsigned long flags;
-   int ret = 0;
-   int i;
-
-   spin_lock_irqsave(&dma_domain->domain_lock, flags);
-   for (i = 0; i < num; i++) {
-   /* Ensure that LIODN value is valid */
-   if (liodn[i] >= PAACE_NUMBER_ENTRIES) {
-   pr_debug("Invalid liodn %d, attach device failed for 
%pOF\n",
-liodn[i], dev->of_node);
-   ret = -EINVAL;
-   break;
-   }
-
-   attach_device(dma_domain, liodn[i], dev);
-   ret = pamu_set_liodn(dma_domain, dev, liodn[i]);
-   if (ret)
-   break;
-   }
-   spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
-
-   return ret;
-}
-
 static int fsl_pamu_attach_device(struct iommu_domain *domain,
  struct device *dev)
 {
struct fsl_dma_domain *dma_domain = to_fsl_dma_domain(domain);
+   unsigned long flags;
+   int len, ret = 0, i;
const u32 *liodn;
-   u32 liodn_cnt;
-   int len, ret = 0;
struct pci_dev *pdev = NULL;
struct pci_controller *pci_ctl;
 
@@ -298,14 +266,27 @@ static int fsl_pamu_attach_device(struct iommu_domain 
*domain,
}
 
liodn = of_get_property(dev->of_node, "fsl,liodn", &len);
-   if (liodn) {
-   liodn_cnt = len / sizeof(u32);
-   ret = handle_attach_device(dma_domain, dev, liodn, liodn_cnt);
-   } else {
+   if (!liodn) {
pr_debug("missing fsl,liodn property at %pOF\n", dev->of_node);
-   ret = -EINVAL;
+   return -EINVAL;
}
 
+   spin_lock_irqsave(&dma_domain->domain_lock, flags);
+   for (i = 0; i < len / sizeof(u32); i++) {
+   /* Ensure that LIODN value is valid */
+   if (liodn[i] >= PAACE_NUMBER_ENTRIES) {
+   pr_debug("Invalid liodn %d, attach device failed for 
%pOF\n",
+liodn[i], dev->of_node);
+   ret = -EINVAL;
+   break;
+   }
+
+   attach_device(dma_domain, liodn[i], dev);
+   ret = pamu_set_liodn(dma_domain, dev, liodn[i]);
+   if (ret)
+   break;
+   }
+   spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
return ret;
 }
 
-- 
2.30.1

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH 05/20] iommu/fsl_pamu: remove support for multiple windows

2021-04-01 Thread Christoph Hellwig
The only domains allocated forces use of a single window.  Remove all
the code related to multiple window support, as well as the need for
qman_portal to force a single window.

Remove the now unused DOMAIN_ATTR_WINDOWS iommu_attr.

Signed-off-by: Christoph Hellwig 
Acked-by: Will Deacon 
Acked-by: Li Yang 
---
 drivers/iommu/fsl_pamu.c| 264 +-
 drivers/iommu/fsl_pamu.h|  10 +-
 drivers/iommu/fsl_pamu_domain.c | 275 +---
 drivers/iommu/fsl_pamu_domain.h |  16 +-
 drivers/soc/fsl/qbman/qman_portal.c |   7 -
 include/linux/iommu.h   |   1 -
 6 files changed, 60 insertions(+), 513 deletions(-)

diff --git a/drivers/iommu/fsl_pamu.c b/drivers/iommu/fsl_pamu.c
index b9a974d9783113..3e1647cd5ad47a 100644
--- a/drivers/iommu/fsl_pamu.c
+++ b/drivers/iommu/fsl_pamu.c
@@ -63,19 +63,6 @@ static const struct of_device_id l3_device_ids[] = {
 /* maximum subwindows permitted per liodn */
 static u32 max_subwindow_count;
 
-/* Pool for fspi allocation */
-static struct gen_pool *spaace_pool;
-
-/**
- * pamu_get_max_subwin_cnt() - Return the maximum supported
- * subwindow count per liodn.
- *
- */
-u32 pamu_get_max_subwin_cnt(void)
-{
-   return max_subwindow_count;
-}
-
 /**
  * pamu_get_ppaace() - Return the primary PACCE
  * @liodn: liodn PAACT index for desired PAACE
@@ -155,13 +142,6 @@ static unsigned int map_addrspace_size_to_wse(phys_addr_t 
addrspace_size)
return fls64(addrspace_size) - 2;
 }
 
-/* Derive the PAACE window count encoding for the subwindow count */
-static unsigned int map_subwindow_cnt_to_wce(u32 subwindow_cnt)
-{
-   /* window count is 2^(WCE+1) bytes */
-   return __ffs(subwindow_cnt) - 1;
-}
-
 /*
  * Set the PAACE type as primary and set the coherency required domain
  * attribute
@@ -174,89 +154,11 @@ static void pamu_init_ppaace(struct paace *ppaace)
   PAACE_M_COHERENCE_REQ);
 }
 
-/*
- * Set the PAACE type as secondary and set the coherency required domain
- * attribute.
- */
-static void pamu_init_spaace(struct paace *spaace)
-{
-   set_bf(spaace->addr_bitfields, PAACE_AF_PT, PAACE_PT_SECONDARY);
-   set_bf(spaace->domain_attr.to_host.coherency_required, PAACE_DA_HOST_CR,
-  PAACE_M_COHERENCE_REQ);
-}
-
-/*
- * Return the spaace (corresponding to the secondary window index)
- * for a particular ppaace.
- */
-static struct paace *pamu_get_spaace(struct paace *paace, u32 wnum)
-{
-   u32 subwin_cnt;
-   struct paace *spaace = NULL;
-
-   subwin_cnt = 1UL << (get_bf(paace->impl_attr, PAACE_IA_WCE) + 1);
-
-   if (wnum < subwin_cnt)
-   spaace = &spaact[paace->fspi + wnum];
-   else
-   pr_debug("secondary paace out of bounds\n");
-
-   return spaace;
-}
-
-/**
- * pamu_get_fspi_and_allocate() - Allocates fspi index and reserves subwindows
- *required for primary PAACE in the secondary
- *PAACE table.
- * @subwin_cnt: Number of subwindows to be reserved.
- *
- * A PPAACE entry may have a number of associated subwindows. A subwindow
- * corresponds to a SPAACE entry in the SPAACT table. Each PAACE entry stores
- * the index (fspi) of the first SPAACE entry in the SPAACT table. This
- * function returns the index of the first SPAACE entry. The remaining
- * SPAACE entries are reserved contiguously from that index.
- *
- * Returns a valid fspi index in the range of 0 - SPAACE_NUMBER_ENTRIES on 
success.
- * If no SPAACE entry is available or the allocator can not reserve the 
required
- * number of contiguous entries function returns ULONG_MAX indicating a 
failure.
- *
- */
-static unsigned long pamu_get_fspi_and_allocate(u32 subwin_cnt)
-{
-   unsigned long spaace_addr;
-
-   spaace_addr = gen_pool_alloc(spaace_pool, subwin_cnt * sizeof(struct 
paace));
-   if (!spaace_addr)
-   return ULONG_MAX;
-
-   return (spaace_addr - (unsigned long)spaact) / (sizeof(struct paace));
-}
-
-/* Release the subwindows reserved for a particular LIODN */
-void pamu_free_subwins(int liodn)
-{
-   struct paace *ppaace;
-   u32 subwin_cnt, size;
-
-   ppaace = pamu_get_ppaace(liodn);
-   if (!ppaace) {
-   pr_debug("Invalid liodn entry\n");
-   return;
-   }
-
-   if (get_bf(ppaace->addr_bitfields, PPAACE_AF_MW)) {
-   subwin_cnt = 1UL << (get_bf(ppaace->impl_attr, PAACE_IA_WCE) + 
1);
-   size = (subwin_cnt - 1) * sizeof(struct paace);
-   gen_pool_free(spaace_pool, (unsigned 
long)&spaact[ppaace->fspi], size);
-   set_bf(ppaace->addr_bitfields, PPAACE_AF_MW, 0);
-   }
-}
-
 /*
  * Function used for updating stash destination for the coressponding
  * LIODN.
  */
-int  pamu_update_paace_stash(int liodn, u32 subwin, u32 value)
+int pamu_update_paace_stash(int liodn, u32 value)
 {
struct paace *paace;
 
@@ -265,11 +167,6 @@ int

[PATCH 08/20] iommu/fsl_pamu: merge pamu_set_liodn and map_liodn

2021-04-01 Thread Christoph Hellwig
Merge the two fuctions that configure the ppaace into a single coherent
function.  I somehow doubt we need the two pamu_config_ppaace calls,
but keep the existing behavior just to be on the safe side.

Signed-off-by: Christoph Hellwig 
Acked-by: Li Yang 
---
 drivers/iommu/fsl_pamu_domain.c | 65 +
 1 file changed, 17 insertions(+), 48 deletions(-)

diff --git a/drivers/iommu/fsl_pamu_domain.c b/drivers/iommu/fsl_pamu_domain.c
index 557a152c1d2c49..198725ef27954f 100644
--- a/drivers/iommu/fsl_pamu_domain.c
+++ b/drivers/iommu/fsl_pamu_domain.c
@@ -54,25 +54,6 @@ static int __init iommu_init_mempool(void)
return 0;
 }
 
-/* Map the DMA window corresponding to the LIODN */
-static int map_liodn(int liodn, struct fsl_dma_domain *dma_domain)
-{
-   int ret;
-   struct iommu_domain_geometry *geom = &dma_domain->iommu_domain.geometry;
-   unsigned long flags;
-
-   spin_lock_irqsave(&iommu_lock, flags);
-   ret = pamu_config_ppaace(liodn, geom->aperture_start,
-geom->aperture_end + 1, ~(u32)0,
-0, dma_domain->snoop_id, dma_domain->stash_id,
-PAACE_AP_PERMS_QUERY | PAACE_AP_PERMS_UPDATE);
-   spin_unlock_irqrestore(&iommu_lock, flags);
-   if (ret)
-   pr_debug("PAACE configuration failed for liodn %d\n", liodn);
-
-   return ret;
-}
-
 static int update_liodn_stash(int liodn, struct fsl_dma_domain *dma_domain,
  u32 val)
 {
@@ -94,11 +75,11 @@ static int update_liodn_stash(int liodn, struct 
fsl_dma_domain *dma_domain,
 }
 
 /* Set the geometry parameters for a LIODN */
-static int pamu_set_liodn(int liodn, struct device *dev,
- struct fsl_dma_domain *dma_domain,
- struct iommu_domain_geometry *geom_attr)
+static int pamu_set_liodn(struct fsl_dma_domain *dma_domain, struct device 
*dev,
+ int liodn)
 {
-   phys_addr_t window_addr, window_size;
+   struct iommu_domain *domain = &dma_domain->iommu_domain;
+   struct iommu_domain_geometry *geom = &domain->geometry;
u32 omi_index = ~(u32)0;
unsigned long flags;
int ret;
@@ -110,22 +91,25 @@ static int pamu_set_liodn(int liodn, struct device *dev,
 */
get_ome_index(&omi_index, dev);
 
-   window_addr = geom_attr->aperture_start;
-   window_size = geom_attr->aperture_end + 1;
-
spin_lock_irqsave(&iommu_lock, flags);
ret = pamu_disable_liodn(liodn);
-   if (!ret)
-   ret = pamu_config_ppaace(liodn, window_addr, window_size, 
omi_index,
-0, dma_domain->snoop_id,
-dma_domain->stash_id, 0);
+   if (ret)
+   goto out_unlock;
+   ret = pamu_config_ppaace(liodn, geom->aperture_start,
+geom->aperture_end + 1, omi_index, 0,
+dma_domain->snoop_id, dma_domain->stash_id, 0);
+   if (ret)
+   goto out_unlock;
+   ret = pamu_config_ppaace(liodn, geom->aperture_start,
+geom->aperture_end + 1, ~(u32)0,
+0, dma_domain->snoop_id, dma_domain->stash_id,
+PAACE_AP_PERMS_QUERY | PAACE_AP_PERMS_UPDATE);
+out_unlock:
spin_unlock_irqrestore(&iommu_lock, flags);
if (ret) {
pr_debug("PAACE configuration failed for liodn %d\n",
 liodn);
-   return ret;
}
-
return ret;
 }
 
@@ -265,7 +249,6 @@ static int handle_attach_device(struct fsl_dma_domain 
*dma_domain,
int num)
 {
unsigned long flags;
-   struct iommu_domain *domain = &dma_domain->iommu_domain;
int ret = 0;
int i;
 
@@ -280,21 +263,7 @@ static int handle_attach_device(struct fsl_dma_domain 
*dma_domain,
}
 
attach_device(dma_domain, liodn[i], dev);
-   /*
-* Check if geometry has already been configured
-* for the domain. If yes, set the geometry for
-* the LIODN.
-*/
-   ret = pamu_set_liodn(liodn[i], dev, dma_domain,
-&domain->geometry);
-   if (ret)
-   break;
-
-   /*
-* Create window/subwindow mapping for
-* the LIODN.
-*/
-   ret = map_liodn(liodn[i], dma_domain);
+   ret = pamu_set_liodn(dma_domain, dev, liodn[i]);
if (ret)
break;
}
-- 
2.30.1

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH 11/20] iommu/fsl_pamu: remove the snoop_id field

2021-04-01 Thread Christoph Hellwig
The snoop_id is always set to ~(u32)0.

Signed-off-by: Christoph Hellwig 
Acked-by: Will Deacon 
Acked-by: Li Yang 
---
 drivers/iommu/fsl_pamu_domain.c | 5 ++---
 drivers/iommu/fsl_pamu_domain.h | 1 -
 2 files changed, 2 insertions(+), 4 deletions(-)

diff --git a/drivers/iommu/fsl_pamu_domain.c b/drivers/iommu/fsl_pamu_domain.c
index c2e7e17570e76d..e9c1e0dd68f084 100644
--- a/drivers/iommu/fsl_pamu_domain.c
+++ b/drivers/iommu/fsl_pamu_domain.c
@@ -97,12 +97,12 @@ static int pamu_set_liodn(struct fsl_dma_domain 
*dma_domain, struct device *dev,
goto out_unlock;
ret = pamu_config_ppaace(liodn, geom->aperture_start,
 geom->aperture_end + 1, omi_index, 0,
-dma_domain->snoop_id, dma_domain->stash_id, 0);
+~(u32)0, dma_domain->stash_id, 0);
if (ret)
goto out_unlock;
ret = pamu_config_ppaace(liodn, geom->aperture_start,
 geom->aperture_end + 1, ~(u32)0,
-0, dma_domain->snoop_id, dma_domain->stash_id,
+0, ~(u32)0, dma_domain->stash_id,
 PAACE_AP_PERMS_QUERY | PAACE_AP_PERMS_UPDATE);
 out_unlock:
spin_unlock_irqrestore(&iommu_lock, flags);
@@ -210,7 +210,6 @@ static struct iommu_domain *fsl_pamu_domain_alloc(unsigned 
type)
return NULL;
 
dma_domain->stash_id = ~(u32)0;
-   dma_domain->snoop_id = ~(u32)0;
INIT_LIST_HEAD(&dma_domain->devices);
spin_lock_init(&dma_domain->domain_lock);
 
diff --git a/drivers/iommu/fsl_pamu_domain.h b/drivers/iommu/fsl_pamu_domain.h
index 5f4ed253f61b31..95ac1b3cab3b69 100644
--- a/drivers/iommu/fsl_pamu_domain.h
+++ b/drivers/iommu/fsl_pamu_domain.h
@@ -13,7 +13,6 @@ struct fsl_dma_domain {
/* list of devices associated with the domain */
struct list_headdevices;
u32 stash_id;
-   u32 snoop_id;
struct iommu_domain iommu_domain;
spinlock_t  domain_lock;
 };
-- 
2.30.1

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH 07/20] iommu/fsl_pamu: replace DOMAIN_ATTR_FSL_PAMU_STASH with a direct call

2021-04-01 Thread Christoph Hellwig
Add a fsl_pamu_configure_l1_stash API that qman_portal can call directly
instead of indirecting through the iommu attr API.

Signed-off-by: Christoph Hellwig 
Acked-by: Will Deacon 
Acked-by: Li Yang 
---
 arch/powerpc/include/asm/fsl_pamu_stash.h | 12 +++-
 drivers/iommu/fsl_pamu_domain.c   | 16 +++-
 drivers/iommu/fsl_pamu_domain.h   |  2 --
 drivers/soc/fsl/qbman/qman_portal.c   | 18 +++---
 include/linux/iommu.h |  1 -
 5 files changed, 9 insertions(+), 40 deletions(-)

diff --git a/arch/powerpc/include/asm/fsl_pamu_stash.h 
b/arch/powerpc/include/asm/fsl_pamu_stash.h
index 30a31ad2123d86..c0fbadb70b5dad 100644
--- a/arch/powerpc/include/asm/fsl_pamu_stash.h
+++ b/arch/powerpc/include/asm/fsl_pamu_stash.h
@@ -7,6 +7,8 @@
 #ifndef __FSL_PAMU_STASH_H
 #define __FSL_PAMU_STASH_H
 
+struct iommu_domain;
+
 /* cache stash targets */
 enum pamu_stash_target {
PAMU_ATTR_CACHE_L1 = 1,
@@ -14,14 +16,6 @@ enum pamu_stash_target {
PAMU_ATTR_CACHE_L3,
 };
 
-/*
- * This attribute allows configuring stashig specific parameters
- * in the PAMU hardware.
- */
-
-struct pamu_stash_attribute {
-   u32 cpu;/* cpu number */
-   u32 cache;  /* cache to stash to: L1,L2,L3 */
-};
+int fsl_pamu_configure_l1_stash(struct iommu_domain *domain, u32 cpu);
 
 #endif  /* __FSL_PAMU_STASH_H */
diff --git a/drivers/iommu/fsl_pamu_domain.c b/drivers/iommu/fsl_pamu_domain.c
index 689035e9d40955..557a152c1d2c49 100644
--- a/drivers/iommu/fsl_pamu_domain.c
+++ b/drivers/iommu/fsl_pamu_domain.c
@@ -372,27 +372,20 @@ static void fsl_pamu_detach_device(struct iommu_domain 
*domain,
 }
 
 /* Set the domain stash attribute */
-static int configure_domain_stash(struct fsl_dma_domain *dma_domain, void 
*data)
+int fsl_pamu_configure_l1_stash(struct iommu_domain *domain, u32 cpu)
 {
-   struct pamu_stash_attribute *stash_attr = data;
+   struct fsl_dma_domain *dma_domain = to_fsl_dma_domain(domain);
unsigned long flags;
int ret;
 
spin_lock_irqsave(&dma_domain->domain_lock, flags);
-
-   memcpy(&dma_domain->dma_stash, stash_attr,
-  sizeof(struct pamu_stash_attribute));
-
-   dma_domain->stash_id = get_stash_id(stash_attr->cache,
-   stash_attr->cpu);
+   dma_domain->stash_id = get_stash_id(PAMU_ATTR_CACHE_L1, cpu);
if (dma_domain->stash_id == ~(u32)0) {
pr_debug("Invalid stash attributes\n");
spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
return -EINVAL;
}
-
ret = update_domain_stash(dma_domain, dma_domain->stash_id);
-
spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
 
return ret;
@@ -426,9 +419,6 @@ static int fsl_pamu_set_domain_attr(struct iommu_domain 
*domain,
int ret = 0;
 
switch (attr_type) {
-   case DOMAIN_ATTR_FSL_PAMU_STASH:
-   ret = configure_domain_stash(dma_domain, data);
-   break;
case DOMAIN_ATTR_FSL_PAMU_ENABLE:
ret = configure_domain_dma_state(dma_domain, *(int *)data);
break;
diff --git a/drivers/iommu/fsl_pamu_domain.h b/drivers/iommu/fsl_pamu_domain.h
index 13ee06e0ef0136..cd488004acd1b3 100644
--- a/drivers/iommu/fsl_pamu_domain.h
+++ b/drivers/iommu/fsl_pamu_domain.h
@@ -22,9 +22,7 @@ struct fsl_dma_domain {
 *
 */
int enabled;
-   /* stash_id obtained from the stash attribute details */
u32 stash_id;
-   struct pamu_stash_attribute dma_stash;
u32 snoop_id;
struct iommu_domain iommu_domain;
spinlock_t  domain_lock;
diff --git a/drivers/soc/fsl/qbman/qman_portal.c 
b/drivers/soc/fsl/qbman/qman_portal.c
index 9ee1663f422cbf..798b3a1ffd0b9c 100644
--- a/drivers/soc/fsl/qbman/qman_portal.c
+++ b/drivers/soc/fsl/qbman/qman_portal.c
@@ -47,7 +47,6 @@ static void portal_set_cpu(struct qm_portal_config *pcfg, int 
cpu)
 #ifdef CONFIG_FSL_PAMU
struct device *dev = pcfg->dev;
int window_count = 1;
-   struct pamu_stash_attribute stash_attr;
int ret;
 
pcfg->iommu_domain = iommu_domain_alloc(&platform_bus_type);
@@ -55,13 +54,9 @@ static void portal_set_cpu(struct qm_portal_config *pcfg, 
int cpu)
dev_err(dev, "%s(): iommu_domain_alloc() failed", __func__);
goto no_iommu;
}
-   stash_attr.cpu = cpu;
-   stash_attr.cache = PAMU_ATTR_CACHE_L1;
-   ret = iommu_domain_set_attr(pcfg->iommu_domain,
-   DOMAIN_ATTR_FSL_PAMU_STASH,
-   &stash_attr);
+   ret = fsl_pamu_configure_l1_stash(pcfg->iommu_domain, cpu);
if (ret < 0) {
-   dev_err(dev, "%s(): iommu_domain_set_attr() = %d",
+  

[PATCH 04/20] iommu/fsl_pamu: merge iommu_alloc_dma_domain into fsl_pamu_domain_alloc

2021-04-01 Thread Christoph Hellwig
Keep the functionality to allocate the domain together.

Signed-off-by: Christoph Hellwig 
Acked-by: Will Deacon 
Acked-by: Li Yang 
---
 drivers/iommu/fsl_pamu_domain.c | 34 ++---
 1 file changed, 10 insertions(+), 24 deletions(-)

diff --git a/drivers/iommu/fsl_pamu_domain.c b/drivers/iommu/fsl_pamu_domain.c
index 7bd08ddad07779..a4da5597755d3d 100644
--- a/drivers/iommu/fsl_pamu_domain.c
+++ b/drivers/iommu/fsl_pamu_domain.c
@@ -292,25 +292,6 @@ static int check_size(u64 size, dma_addr_t iova)
return 0;
 }
 
-static struct fsl_dma_domain *iommu_alloc_dma_domain(void)
-{
-   struct fsl_dma_domain *domain;
-
-   domain = kmem_cache_zalloc(fsl_pamu_domain_cache, GFP_KERNEL);
-   if (!domain)
-   return NULL;
-
-   domain->stash_id = ~(u32)0;
-   domain->snoop_id = ~(u32)0;
-   domain->win_cnt = pamu_get_max_subwin_cnt();
-
-   INIT_LIST_HEAD(&domain->devices);
-
-   spin_lock_init(&domain->domain_lock);
-
-   return domain;
-}
-
 static void remove_device_ref(struct device_domain_info *info, u32 win_cnt)
 {
unsigned long flags;
@@ -412,12 +393,17 @@ static struct iommu_domain 
*fsl_pamu_domain_alloc(unsigned type)
if (type != IOMMU_DOMAIN_UNMANAGED)
return NULL;
 
-   dma_domain = iommu_alloc_dma_domain();
-   if (!dma_domain) {
-   pr_debug("dma_domain allocation failed\n");
+   dma_domain = kmem_cache_zalloc(fsl_pamu_domain_cache, GFP_KERNEL);
+   if (!dma_domain)
return NULL;
-   }
-   /* defaul geometry 64 GB i.e. maximum system address */
+
+   dma_domain->stash_id = ~(u32)0;
+   dma_domain->snoop_id = ~(u32)0;
+   dma_domain->win_cnt = pamu_get_max_subwin_cnt();
+   INIT_LIST_HEAD(&dma_domain->devices);
+   spin_lock_init(&dma_domain->domain_lock);
+
+   /* default geometry 64 GB i.e. maximum system address */
dma_domain->iommu_domain. geometry.aperture_start = 0;
dma_domain->iommu_domain.geometry.aperture_end = (1ULL << 36) - 1;
dma_domain->iommu_domain.geometry.force_aperture = true;
-- 
2.30.1

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH 16/20] iommu: remove DOMAIN_ATTR_NESTING

2021-04-01 Thread Christoph Hellwig
Use an explicit enable_nesting method instead.

Signed-off-by: Christoph Hellwig 
Acked-by: Will Deacon 
Acked-by: Li Yang 
---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 43 -
 drivers/iommu/arm/arm-smmu/arm-smmu.c   | 30 +++---
 drivers/iommu/intel/iommu.c | 31 +--
 drivers/iommu/iommu.c   | 10 +
 drivers/vfio/vfio_iommu_type1.c |  5 +--
 include/linux/iommu.h   |  4 +-
 6 files changed, 55 insertions(+), 68 deletions(-)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c 
b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index 8594b4a8304375..f1e38526d5bd40 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -2455,15 +2455,6 @@ static int arm_smmu_domain_get_attr(struct iommu_domain 
*domain,
struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
 
switch (domain->type) {
-   case IOMMU_DOMAIN_UNMANAGED:
-   switch (attr) {
-   case DOMAIN_ATTR_NESTING:
-   *(int *)data = (smmu_domain->stage == 
ARM_SMMU_DOMAIN_NESTED);
-   return 0;
-   default:
-   return -ENODEV;
-   }
-   break;
case IOMMU_DOMAIN_DMA:
switch (attr) {
case DOMAIN_ATTR_DMA_USE_FLUSH_QUEUE:
@@ -2487,23 +2478,6 @@ static int arm_smmu_domain_set_attr(struct iommu_domain 
*domain,
mutex_lock(&smmu_domain->init_mutex);
 
switch (domain->type) {
-   case IOMMU_DOMAIN_UNMANAGED:
-   switch (attr) {
-   case DOMAIN_ATTR_NESTING:
-   if (smmu_domain->smmu) {
-   ret = -EPERM;
-   goto out_unlock;
-   }
-
-   if (*(int *)data)
-   smmu_domain->stage = ARM_SMMU_DOMAIN_NESTED;
-   else
-   smmu_domain->stage = ARM_SMMU_DOMAIN_S1;
-   break;
-   default:
-   ret = -ENODEV;
-   }
-   break;
case IOMMU_DOMAIN_DMA:
switch(attr) {
case DOMAIN_ATTR_DMA_USE_FLUSH_QUEUE:
@@ -2517,11 +2491,25 @@ static int arm_smmu_domain_set_attr(struct iommu_domain 
*domain,
ret = -EINVAL;
}
 
-out_unlock:
mutex_unlock(&smmu_domain->init_mutex);
return ret;
 }
 
+static int arm_smmu_enable_nesting(struct iommu_domain *domain)
+{
+   struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
+   int ret = 0;
+
+   mutex_lock(&smmu_domain->init_mutex);
+   if (smmu_domain->smmu)
+   ret = -EPERM;
+   else
+   smmu_domain->stage = ARM_SMMU_DOMAIN_NESTED;
+   mutex_unlock(&smmu_domain->init_mutex);
+
+   return ret;
+}
+
 static int arm_smmu_of_xlate(struct device *dev, struct of_phandle_args *args)
 {
return iommu_fwspec_add_ids(dev, args->args, 1);
@@ -2621,6 +2609,7 @@ static struct iommu_ops arm_smmu_ops = {
.device_group   = arm_smmu_device_group,
.domain_get_attr= arm_smmu_domain_get_attr,
.domain_set_attr= arm_smmu_domain_set_attr,
+   .enable_nesting = arm_smmu_enable_nesting,
.of_xlate   = arm_smmu_of_xlate,
.get_resv_regions   = arm_smmu_get_resv_regions,
.put_resv_regions   = generic_iommu_put_resv_regions,
diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu.c 
b/drivers/iommu/arm/arm-smmu/arm-smmu.c
index d8c6bfde6a6158..0aa6d667274970 100644
--- a/drivers/iommu/arm/arm-smmu/arm-smmu.c
+++ b/drivers/iommu/arm/arm-smmu/arm-smmu.c
@@ -1489,9 +1489,6 @@ static int arm_smmu_domain_get_attr(struct iommu_domain 
*domain,
switch(domain->type) {
case IOMMU_DOMAIN_UNMANAGED:
switch (attr) {
-   case DOMAIN_ATTR_NESTING:
-   *(int *)data = (smmu_domain->stage == 
ARM_SMMU_DOMAIN_NESTED);
-   return 0;
case DOMAIN_ATTR_IO_PGTABLE_CFG: {
struct io_pgtable_domain_attr *pgtbl_cfg = data;
*pgtbl_cfg = smmu_domain->pgtbl_cfg;
@@ -1519,6 +1516,21 @@ static int arm_smmu_domain_get_attr(struct iommu_domain 
*domain,
}
 }
 
+static int arm_smmu_enable_nesting(struct iommu_domain *domain)
+{
+   struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
+   int ret = 0;
+
+   mutex_lock(&smmu_domain->init_mutex);
+   if (smmu_domain->smmu)
+   ret = -EPERM;
+   else
+   smmu_domain->stage = ARM_SMMU_DOMAIN_NESTED;
+   mutex_unlock(&smmu_domain->init_mutex);
+
+   return ret;
+}
+
 static int arm_smmu_domain_set_attr(struct iommu_domain *domain,
   

[PATCH 18/20] iommu: remove DOMAIN_ATTR_DMA_USE_FLUSH_QUEUE

2021-04-01 Thread Christoph Hellwig
From: Robin Murphy 

Instead make the global iommu_dma_strict paramete in iommu.c canonical by
exporting helpers to get and set it and use those directly in the drivers.

This make sure that the iommu.strict parameter also works for the AMD and
Intel IOMMU drivers on x86.  As those default to lazy flushing a new
IOMMU_CMD_LINE_STRICT is used to turn the value into a tristate to
represent the default if not overriden by an explicit parameter.

Signed-off-by: Robin Murphy .
[ported on top of the other iommu_attr changes and added a few small
 missing bits]
Signed-off-by: Christoph Hellwig 
---
 drivers/iommu/amd/iommu.c   | 23 +---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 50 +---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h |  1 -
 drivers/iommu/arm/arm-smmu/arm-smmu.c   | 27 +
 drivers/iommu/dma-iommu.c   |  9 +--
 drivers/iommu/intel/iommu.c | 64 -
 drivers/iommu/iommu.c   | 30 +++---
 include/linux/iommu.h   |  4 +-
 8 files changed, 43 insertions(+), 165 deletions(-)

diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c
index a69a8b573e40d0..ce6393d2224d86 100644
--- a/drivers/iommu/amd/iommu.c
+++ b/drivers/iommu/amd/iommu.c
@@ -1771,26 +1771,6 @@ static struct iommu_group *amd_iommu_device_group(struct 
device *dev)
return acpihid_device_group(dev);
 }
 
-static int amd_iommu_domain_get_attr(struct iommu_domain *domain,
-   enum iommu_attr attr, void *data)
-{
-   switch (domain->type) {
-   case IOMMU_DOMAIN_UNMANAGED:
-   return -ENODEV;
-   case IOMMU_DOMAIN_DMA:
-   switch (attr) {
-   case DOMAIN_ATTR_DMA_USE_FLUSH_QUEUE:
-   *(int *)data = !amd_iommu_unmap_flush;
-   return 0;
-   default:
-   return -ENODEV;
-   }
-   break;
-   default:
-   return -EINVAL;
-   }
-}
-
 /*
  *
  * The next functions belong to the dma_ops mapping/unmapping code.
@@ -1855,7 +1835,7 @@ int __init amd_iommu_init_dma_ops(void)
pr_info("IO/TLB flush on unmap enabled\n");
else
pr_info("Lazy IO/TLB flushing enabled\n");
-
+   iommu_set_dma_strict(amd_iommu_unmap_flush);
return 0;
 
 }
@@ -2257,7 +2237,6 @@ const struct iommu_ops amd_iommu_ops = {
.release_device = amd_iommu_release_device,
.probe_finalize = amd_iommu_probe_finalize,
.device_group = amd_iommu_device_group,
-   .domain_get_attr = amd_iommu_domain_get_attr,
.get_resv_regions = amd_iommu_get_resv_regions,
.put_resv_regions = generic_iommu_put_resv_regions,
.is_attach_deferred = amd_iommu_is_attach_deferred,
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c 
b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index f1e38526d5bd40..91f7e7a3b34dfd 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -2017,7 +2017,7 @@ static int arm_smmu_domain_finalise(struct iommu_domain 
*domain,
.iommu_dev  = smmu->dev,
};
 
-   if (smmu_domain->non_strict)
+   if (!iommu_get_dma_strict(domain))
pgtbl_cfg.quirks |= IO_PGTABLE_QUIRK_NON_STRICT;
 
pgtbl_ops = alloc_io_pgtable_ops(fmt, &pgtbl_cfg, smmu_domain);
@@ -2449,52 +2449,6 @@ static struct iommu_group *arm_smmu_device_group(struct 
device *dev)
return group;
 }
 
-static int arm_smmu_domain_get_attr(struct iommu_domain *domain,
-   enum iommu_attr attr, void *data)
-{
-   struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
-
-   switch (domain->type) {
-   case IOMMU_DOMAIN_DMA:
-   switch (attr) {
-   case DOMAIN_ATTR_DMA_USE_FLUSH_QUEUE:
-   *(int *)data = smmu_domain->non_strict;
-   return 0;
-   default:
-   return -ENODEV;
-   }
-   break;
-   default:
-   return -EINVAL;
-   }
-}
-
-static int arm_smmu_domain_set_attr(struct iommu_domain *domain,
-   enum iommu_attr attr, void *data)
-{
-   int ret = 0;
-   struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
-
-   mutex_lock(&smmu_domain->init_mutex);
-
-   switch (domain->type) {
-   case IOMMU_DOMAIN_DMA:
-   switch(attr) {
-   case DOMAIN_ATTR_DMA_USE_FLUSH_QUEUE:
-   smmu_domain->non_strict = *(int *)data;
-   break;
-   default:
-   ret = -ENODEV;
-   }
-   break;
-   default:
-   ret = -EINVAL;
-   }
-
-   mutex_unlock(&smmu_d

[PATCH 13/20] iommu/fsl_pamu: hardcode the window address and size in pamu_config_ppaace

2021-04-01 Thread Christoph Hellwig
The win_addr and win_size parameters are always set to 0 and 1 << 36
respectively, so just hard code them.

Signed-off-by: Christoph Hellwig 
---
 drivers/iommu/fsl_pamu.c| 23 ---
 drivers/iommu/fsl_pamu.h|  3 +--
 drivers/iommu/fsl_pamu_domain.c | 10 ++
 3 files changed, 7 insertions(+), 29 deletions(-)

diff --git a/drivers/iommu/fsl_pamu.c b/drivers/iommu/fsl_pamu.c
index 742fa0e8c45b88..fc38b1fba7cff0 100644
--- a/drivers/iommu/fsl_pamu.c
+++ b/drivers/iommu/fsl_pamu.c
@@ -178,8 +178,6 @@ int pamu_update_paace_stash(int liodn, u32 value)
  * pamu_config_paace() - Sets up PPAACE entry for specified liodn
  *
  * @liodn: Logical IO device number
- * @win_addr: starting address of DSA window
- * @win-size: size of DSA window
  * @omi: Operation mapping index -- if ~omi == 0 then omi not defined
  * @stashid: cache stash id for associated cpu -- if ~stashid == 0 then
  *  stashid not defined
@@ -187,35 +185,22 @@ int pamu_update_paace_stash(int liodn, u32 value)
  *
  * Returns 0 upon success else error code < 0 returned
  */
-int pamu_config_ppaace(int liodn, phys_addr_t win_addr, phys_addr_t win_size,
-  u32 omi, u32 stashid, int prot)
+int pamu_config_ppaace(int liodn, u32 omi, u32 stashid, int prot)
 {
struct paace *ppaace;
 
-   if ((win_size & (win_size - 1)) || win_size < PAMU_PAGE_SIZE) {
-   pr_debug("window size too small or not a power of two %pa\n",
-&win_size);
-   return -EINVAL;
-   }
-
-   if (win_addr & (win_size - 1)) {
-   pr_debug("window address is not aligned with window size\n");
-   return -EINVAL;
-   }
-
ppaace = pamu_get_ppaace(liodn);
if (!ppaace)
return -ENOENT;
 
/* window size is 2^(WSE+1) bytes */
set_bf(ppaace->addr_bitfields, PPAACE_AF_WSE,
-  map_addrspace_size_to_wse(win_size));
+  map_addrspace_size_to_wse(1ULL << 36));
 
pamu_init_ppaace(ppaace);
 
-   ppaace->wbah = win_addr >> (PAMU_PAGE_SHIFT + 20);
-   set_bf(ppaace->addr_bitfields, PPAACE_AF_WBAL,
-  (win_addr >> PAMU_PAGE_SHIFT));
+   ppaace->wbah = 0;
+   set_bf(ppaace->addr_bitfields, PPAACE_AF_WBAL, 0);
 
/* set up operation mapping if it's configured */
if (omi < OME_NUMBER_ENTRIES) {
diff --git a/drivers/iommu/fsl_pamu.h b/drivers/iommu/fsl_pamu.h
index c96b29f0c7077f..36df7975ff64d3 100644
--- a/drivers/iommu/fsl_pamu.h
+++ b/drivers/iommu/fsl_pamu.h
@@ -383,8 +383,7 @@ struct ome {
 int pamu_domain_init(void);
 int pamu_enable_liodn(int liodn);
 int pamu_disable_liodn(int liodn);
-int pamu_config_ppaace(int liodn, phys_addr_t win_addr, phys_addr_t win_size,
-  u32 omi, uint32_t stashid, int prot);
+int pamu_config_ppaace(int liodn, u32 omi, uint32_t stashid, int prot);
 
 u32 get_stash_id(u32 stash_dest_hint, u32 vcpu);
 void get_ome_index(u32 *omi_index, struct device *dev);
diff --git a/drivers/iommu/fsl_pamu_domain.c b/drivers/iommu/fsl_pamu_domain.c
index c83f1e7c2cb0c9..32944d67baa495 100644
--- a/drivers/iommu/fsl_pamu_domain.c
+++ b/drivers/iommu/fsl_pamu_domain.c
@@ -78,8 +78,6 @@ static int update_liodn_stash(int liodn, struct 
fsl_dma_domain *dma_domain,
 static int pamu_set_liodn(struct fsl_dma_domain *dma_domain, struct device 
*dev,
  int liodn)
 {
-   struct iommu_domain *domain = &dma_domain->iommu_domain;
-   struct iommu_domain_geometry *geom = &domain->geometry;
u32 omi_index = ~(u32)0;
unsigned long flags;
int ret;
@@ -95,14 +93,10 @@ static int pamu_set_liodn(struct fsl_dma_domain 
*dma_domain, struct device *dev,
ret = pamu_disable_liodn(liodn);
if (ret)
goto out_unlock;
-   ret = pamu_config_ppaace(liodn, geom->aperture_start,
-geom->aperture_end + 1, omi_index,
-dma_domain->stash_id, 0);
+   ret = pamu_config_ppaace(liodn, omi_index, dma_domain->stash_id, 0);
if (ret)
goto out_unlock;
-   ret = pamu_config_ppaace(liodn, geom->aperture_start,
-geom->aperture_end + 1, ~(u32)0,
-dma_domain->stash_id,
+   ret = pamu_config_ppaace(liodn, ~(u32)0, dma_domain->stash_id,
 PAACE_AP_PERMS_QUERY | PAACE_AP_PERMS_UPDATE);
 out_unlock:
spin_unlock_irqrestore(&iommu_lock, flags);
-- 
2.30.1

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


cleanup unused or almost unused IOMMU APIs and the FSL PAMU driver v3

2021-04-01 Thread Christoph Hellwig
Hi all,

there are a bunch of IOMMU APIs that are entirely unused, or only used as
a private communication channel between the FSL PAMU driver and it's only
consumer, the qbman portal driver.

So this series drops a huge chunk of entirely unused FSL PAMU
functionality, then drops all kinds of unused IOMMU APIs, and then
replaces what is left of the iommu_attrs with properly typed, smaller
and easier to use specific APIs.

Changes since v2:
 - remove a comment fragment a little bit earlier
 - fix the aperture end passed to pamu_config_ppaace
 - fix a few trivial typos
 - remove more unused arguments to pamu_config_ppaace
 - do not accidentally enable lazy flushing for non-dma domains

Changes since v1:
 - use a different way to control strict flushing behavior (from Robin)
 - remove the iommu_cmd_line wrappers
 - simplify the pagetbl quirks a little more
 - slightly improved patch ordering
 - better changelogs

Diffstat:
 arch/powerpc/include/asm/fsl_pamu_stash.h   |   12 
 drivers/gpu/drm/msm/adreno/adreno_gpu.c |5 
 drivers/iommu/amd/iommu.c   |   23 
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c |   75 ---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h |1 
 drivers/iommu/arm/arm-smmu/arm-smmu.c   |  111 +---
 drivers/iommu/arm/arm-smmu/arm-smmu.h   |2 
 drivers/iommu/dma-iommu.c   |9 
 drivers/iommu/fsl_pamu.c|  293 ---
 drivers/iommu/fsl_pamu.h|   12 
 drivers/iommu/fsl_pamu_domain.c |  688 ++--
 drivers/iommu/fsl_pamu_domain.h |   46 -
 drivers/iommu/intel/iommu.c |   95 ---
 drivers/iommu/iommu.c   |  118 +---
 drivers/soc/fsl/qbman/qman_portal.c |   55 --
 drivers/vfio/vfio_iommu_type1.c |   31 -
 drivers/vhost/vdpa.c|   10 
 include/linux/io-pgtable.h  |4 
 include/linux/iommu.h   |   76 ---
 19 files changed, 203 insertions(+), 1463 deletions(-)
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH 12/20] iommu/fsl_pamu: remove the rpn and snoop_id arguments to pamu_config_ppaac

2021-04-01 Thread Christoph Hellwig
These are always wired to fixed values, so don't bother passing them as
arguments.

Signed-off-by: Christoph Hellwig 
---
 drivers/iommu/fsl_pamu.c| 14 +++---
 drivers/iommu/fsl_pamu.h|  3 +--
 drivers/iommu/fsl_pamu_domain.c |  6 +++---
 3 files changed, 7 insertions(+), 16 deletions(-)

diff --git a/drivers/iommu/fsl_pamu.c b/drivers/iommu/fsl_pamu.c
index 3e1647cd5ad47a..742fa0e8c45b88 100644
--- a/drivers/iommu/fsl_pamu.c
+++ b/drivers/iommu/fsl_pamu.c
@@ -181,18 +181,14 @@ int pamu_update_paace_stash(int liodn, u32 value)
  * @win_addr: starting address of DSA window
  * @win-size: size of DSA window
  * @omi: Operation mapping index -- if ~omi == 0 then omi not defined
- * @rpn: real (true physical) page number
  * @stashid: cache stash id for associated cpu -- if ~stashid == 0 then
  *  stashid not defined
- * @snoopid: snoop id for hardware coherency -- if ~snoopid == 0 then
- *  snoopid not defined
  * @prot: window permissions
  *
  * Returns 0 upon success else error code < 0 returned
  */
 int pamu_config_ppaace(int liodn, phys_addr_t win_addr, phys_addr_t win_size,
-  u32 omi, unsigned long rpn, u32 snoopid, u32 stashid,
-  int prot)
+  u32 omi, u32 stashid, int prot)
 {
struct paace *ppaace;
 
@@ -234,13 +230,9 @@ int pamu_config_ppaace(int liodn, phys_addr_t win_addr, 
phys_addr_t win_size,
if (~stashid != 0)
set_bf(ppaace->impl_attr, PAACE_IA_CID, stashid);
 
-   /* configure snoop id */
-   if (~snoopid != 0)
-   ppaace->domain_attr.to_host.snpid = snoopid;
-
set_bf(ppaace->impl_attr, PAACE_IA_ATM, PAACE_ATM_WINDOW_XLATE);
-   ppaace->twbah = rpn >> 20;
-   set_bf(ppaace->win_bitfields, PAACE_WIN_TWBAL, rpn);
+   ppaace->twbah = 0;
+   set_bf(ppaace->win_bitfields, PAACE_WIN_TWBAL, 0);
set_bf(ppaace->addr_bitfields, PAACE_AF_AP, prot);
set_bf(ppaace->impl_attr, PAACE_IA_WCE, 0);
set_bf(ppaace->addr_bitfields, PPAACE_AF_MW, 0);
diff --git a/drivers/iommu/fsl_pamu.h b/drivers/iommu/fsl_pamu.h
index 04fd843d718dd1..c96b29f0c7077f 100644
--- a/drivers/iommu/fsl_pamu.h
+++ b/drivers/iommu/fsl_pamu.h
@@ -384,8 +384,7 @@ int pamu_domain_init(void);
 int pamu_enable_liodn(int liodn);
 int pamu_disable_liodn(int liodn);
 int pamu_config_ppaace(int liodn, phys_addr_t win_addr, phys_addr_t win_size,
-  u32 omi, unsigned long rpn, u32 snoopid, uint32_t 
stashid,
-  int prot);
+  u32 omi, uint32_t stashid, int prot);
 
 u32 get_stash_id(u32 stash_dest_hint, u32 vcpu);
 void get_ome_index(u32 *omi_index, struct device *dev);
diff --git a/drivers/iommu/fsl_pamu_domain.c b/drivers/iommu/fsl_pamu_domain.c
index e9c1e0dd68f084..c83f1e7c2cb0c9 100644
--- a/drivers/iommu/fsl_pamu_domain.c
+++ b/drivers/iommu/fsl_pamu_domain.c
@@ -96,13 +96,13 @@ static int pamu_set_liodn(struct fsl_dma_domain 
*dma_domain, struct device *dev,
if (ret)
goto out_unlock;
ret = pamu_config_ppaace(liodn, geom->aperture_start,
-geom->aperture_end + 1, omi_index, 0,
-~(u32)0, dma_domain->stash_id, 0);
+geom->aperture_end + 1, omi_index,
+dma_domain->stash_id, 0);
if (ret)
goto out_unlock;
ret = pamu_config_ppaace(liodn, geom->aperture_start,
 geom->aperture_end + 1, ~(u32)0,
-0, ~(u32)0, dma_domain->stash_id,
+dma_domain->stash_id,
 PAACE_AP_PERMS_QUERY | PAACE_AP_PERMS_UPDATE);
 out_unlock:
spin_unlock_irqrestore(&iommu_lock, flags);
-- 
2.30.1

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH 17/20] iommu: remove iommu_set_cmd_line_dma_api and iommu_cmd_line_dma_api

2021-04-01 Thread Christoph Hellwig
Don't obsfucate the trivial bit flag check.

Signed-off-by: Christoph Hellwig 
Acked-by: Will Deacon 
---
 drivers/iommu/iommu.c | 23 +--
 1 file changed, 5 insertions(+), 18 deletions(-)

diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 58d1d11a8d5c10..052cef11ae30df 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -70,16 +70,6 @@ static const char * const iommu_group_resv_type_string[] = {
 
 #define IOMMU_CMD_LINE_DMA_API BIT(0)
 
-static void iommu_set_cmd_line_dma_api(void)
-{
-   iommu_cmd_line |= IOMMU_CMD_LINE_DMA_API;
-}
-
-static bool iommu_cmd_line_dma_api(void)
-{
-   return !!(iommu_cmd_line & IOMMU_CMD_LINE_DMA_API);
-}
-
 static int iommu_alloc_default_domain(struct iommu_group *group,
  struct device *dev);
 static struct iommu_domain *__iommu_domain_alloc(struct bus_type *bus,
@@ -130,9 +120,7 @@ static const char *iommu_domain_type_str(unsigned int t)
 
 static int __init iommu_subsys_init(void)
 {
-   bool cmd_line = iommu_cmd_line_dma_api();
-
-   if (!cmd_line) {
+   if (!(iommu_cmd_line & IOMMU_CMD_LINE_DMA_API)) {
if (IS_ENABLED(CONFIG_IOMMU_DEFAULT_PASSTHROUGH))
iommu_set_default_passthrough(false);
else
@@ -146,7 +134,8 @@ static int __init iommu_subsys_init(void)
 
pr_info("Default domain type: %s %s\n",
iommu_domain_type_str(iommu_def_domain_type),
-   cmd_line ? "(set via kernel command line)" : "");
+   (iommu_cmd_line & IOMMU_CMD_LINE_DMA_API) ?
+   "(set via kernel command line)" : "");
 
return 0;
 }
@@ -2757,16 +2746,14 @@ EXPORT_SYMBOL_GPL(iommu_alloc_resv_region);
 void iommu_set_default_passthrough(bool cmd_line)
 {
if (cmd_line)
-   iommu_set_cmd_line_dma_api();
-
+   iommu_cmd_line |= IOMMU_CMD_LINE_DMA_API;
iommu_def_domain_type = IOMMU_DOMAIN_IDENTITY;
 }
 
 void iommu_set_default_translated(bool cmd_line)
 {
if (cmd_line)
-   iommu_set_cmd_line_dma_api();
-
+   iommu_cmd_line |= IOMMU_CMD_LINE_DMA_API;
iommu_def_domain_type = IOMMU_DOMAIN_DMA;
 }
 
-- 
2.30.1

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH 10/20] iommu/fsl_pamu: enable the liodn when attaching a device

2021-04-01 Thread Christoph Hellwig
Instead of a separate call to enable all devices from the list, just
enable the liodn once the device is attached to the iommu domain.

This also remove the DOMAIN_ATTR_FSL_PAMU_ENABLE iommu_attr.

Signed-off-by: Christoph Hellwig 
Acked-by: Will Deacon 
Acked-by: Li Yang 
---
 drivers/iommu/fsl_pamu_domain.c | 47 ++---
 drivers/iommu/fsl_pamu_domain.h | 10 --
 drivers/soc/fsl/qbman/qman_portal.c | 11 ---
 include/linux/iommu.h   |  1 -
 4 files changed, 3 insertions(+), 66 deletions(-)

diff --git a/drivers/iommu/fsl_pamu_domain.c b/drivers/iommu/fsl_pamu_domain.c
index 41927c3c417751..c2e7e17570e76d 100644
--- a/drivers/iommu/fsl_pamu_domain.c
+++ b/drivers/iommu/fsl_pamu_domain.c
@@ -195,9 +195,6 @@ static void fsl_pamu_domain_free(struct iommu_domain 
*domain)
 
/* remove all the devices from the device list */
detach_device(NULL, dma_domain);
-
-   dma_domain->enabled = 0;
-
kmem_cache_free(fsl_pamu_domain_cache, dma_domain);
 }
 
@@ -285,6 +282,9 @@ static int fsl_pamu_attach_device(struct iommu_domain 
*domain,
ret = pamu_set_liodn(dma_domain, dev, liodn[i]);
if (ret)
break;
+   ret = pamu_enable_liodn(liodn[i]);
+   if (ret)
+   break;
}
spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
return ret;
@@ -341,46 +341,6 @@ int fsl_pamu_configure_l1_stash(struct iommu_domain 
*domain, u32 cpu)
return ret;
 }
 
-/* Configure domain dma state i.e. enable/disable DMA */
-static int configure_domain_dma_state(struct fsl_dma_domain *dma_domain, bool 
enable)
-{
-   struct device_domain_info *info;
-   unsigned long flags;
-   int ret;
-
-   spin_lock_irqsave(&dma_domain->domain_lock, flags);
-   dma_domain->enabled = enable;
-   list_for_each_entry(info, &dma_domain->devices, link) {
-   ret = (enable) ? pamu_enable_liodn(info->liodn) :
-   pamu_disable_liodn(info->liodn);
-   if (ret)
-   pr_debug("Unable to set dma state for liodn %d",
-info->liodn);
-   }
-   spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
-
-   return 0;
-}
-
-static int fsl_pamu_set_domain_attr(struct iommu_domain *domain,
-   enum iommu_attr attr_type, void *data)
-{
-   struct fsl_dma_domain *dma_domain = to_fsl_dma_domain(domain);
-   int ret = 0;
-
-   switch (attr_type) {
-   case DOMAIN_ATTR_FSL_PAMU_ENABLE:
-   ret = configure_domain_dma_state(dma_domain, *(int *)data);
-   break;
-   default:
-   pr_debug("Unsupported attribute type\n");
-   ret = -EINVAL;
-   break;
-   }
-
-   return ret;
-}
-
 static struct iommu_group *get_device_iommu_group(struct device *dev)
 {
struct iommu_group *group;
@@ -505,7 +465,6 @@ static const struct iommu_ops fsl_pamu_ops = {
.attach_dev = fsl_pamu_attach_device,
.detach_dev = fsl_pamu_detach_device,
.iova_to_phys   = fsl_pamu_iova_to_phys,
-   .domain_set_attr = fsl_pamu_set_domain_attr,
.probe_device   = fsl_pamu_probe_device,
.release_device = fsl_pamu_release_device,
.device_group   = fsl_pamu_device_group,
diff --git a/drivers/iommu/fsl_pamu_domain.h b/drivers/iommu/fsl_pamu_domain.h
index cd488004acd1b3..5f4ed253f61b31 100644
--- a/drivers/iommu/fsl_pamu_domain.h
+++ b/drivers/iommu/fsl_pamu_domain.h
@@ -12,16 +12,6 @@
 struct fsl_dma_domain {
/* list of devices associated with the domain */
struct list_headdevices;
-   /* dma_domain states:
-* enabled - DMA has been enabled for the given
-* domain. This translates to setting of the
-* valid bit for the primary PAACE in the PAMU
-* PAACT table. Domain geometry should be set and
-* it must have a valid mapping before DMA can be
-* enabled for it.
-*
-*/
-   int enabled;
u32 stash_id;
u32 snoop_id;
struct iommu_domain iommu_domain;
diff --git a/drivers/soc/fsl/qbman/qman_portal.c 
b/drivers/soc/fsl/qbman/qman_portal.c
index 798b3a1ffd0b9c..bf38eb0042ed52 100644
--- a/drivers/soc/fsl/qbman/qman_portal.c
+++ b/drivers/soc/fsl/qbman/qman_portal.c
@@ -46,7 +46,6 @@ static void portal_set_cpu(struct qm_portal_config *pcfg, int 
cpu)
 {
 #ifdef CONFIG_FSL_PAMU
struct device *dev = pcfg->dev;
-   int window_count = 1;
int ret;
 
pcfg->iommu_domain = iommu_domain_alloc(&platform_bus_type);
@@ -66,14 +65,6 @@ static void portal_set_cpu(struct qm_portal_config *pcfg, 
int cpu)
ret);
goto out_domain_free;
}
-   ret 

[PATCH 03/20] iommu/fsl_pamu: remove support for setting DOMAIN_ATTR_GEOMETRY

2021-04-01 Thread Christoph Hellwig
The default geometry is the same as the one set by qman_port given
that FSL_PAMU depends on having 64-bit physical and thus DMA addresses.

Remove the support to update the geometry and remove the now pointless
geom_size field.

Signed-off-by: Christoph Hellwig 
Acked-by: Will Deacon 
Acked-by: Li Yang 
---
 drivers/iommu/fsl_pamu_domain.c | 55 +++--
 drivers/iommu/fsl_pamu_domain.h |  6 
 drivers/soc/fsl/qbman/qman_portal.c | 12 ---
 3 files changed, 5 insertions(+), 68 deletions(-)

diff --git a/drivers/iommu/fsl_pamu_domain.c b/drivers/iommu/fsl_pamu_domain.c
index e587ec43f7e750..7bd08ddad07779 100644
--- a/drivers/iommu/fsl_pamu_domain.c
+++ b/drivers/iommu/fsl_pamu_domain.c
@@ -62,7 +62,7 @@ static phys_addr_t get_phys_addr(struct fsl_dma_domain 
*dma_domain, dma_addr_t i
 
geom = &dma_domain->iommu_domain.geometry;
 
-   if (!win_cnt || !dma_domain->geom_size) {
+   if (!win_cnt) {
pr_debug("Number of windows/geometry not configured for the 
domain\n");
return 0;
}
@@ -72,7 +72,7 @@ static phys_addr_t get_phys_addr(struct fsl_dma_domain 
*dma_domain, dma_addr_t i
dma_addr_t subwin_iova;
u32 wnd;
 
-   subwin_size = dma_domain->geom_size >> ilog2(win_cnt);
+   subwin_size = (geom->aperture_end + 1) >> ilog2(win_cnt);
subwin_iova = iova & ~(subwin_size - 1);
wnd = (subwin_iova - geom->aperture_start) >> 
ilog2(subwin_size);
win_ptr = &dma_domain->win_arr[wnd];
@@ -234,7 +234,7 @@ static int pamu_set_liodn(int liodn, struct device *dev,
get_ome_index(&omi_index, dev);
 
window_addr = geom_attr->aperture_start;
-   window_size = dma_domain->geom_size;
+   window_size = geom_attr->aperture_end + 1;
 
spin_lock_irqsave(&iommu_lock, flags);
ret = pamu_disable_liodn(liodn);
@@ -303,7 +303,6 @@ static struct fsl_dma_domain *iommu_alloc_dma_domain(void)
domain->stash_id = ~(u32)0;
domain->snoop_id = ~(u32)0;
domain->win_cnt = pamu_get_max_subwin_cnt();
-   domain->geom_size = 0;
 
INIT_LIST_HEAD(&domain->devices);
 
@@ -502,7 +501,8 @@ static int fsl_pamu_window_enable(struct iommu_domain 
*domain, u32 wnd_nr,
return -EINVAL;
}
 
-   win_size = dma_domain->geom_size >> ilog2(dma_domain->win_cnt);
+   win_size = (domain->geometry.aperture_end + 1) >>
+   ilog2(dma_domain->win_cnt);
if (size > win_size) {
pr_debug("Invalid window size\n");
spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
@@ -665,41 +665,6 @@ static void fsl_pamu_detach_device(struct iommu_domain 
*domain,
pr_debug("missing fsl,liodn property at %pOF\n", dev->of_node);
 }
 
-static  int configure_domain_geometry(struct iommu_domain *domain, void *data)
-{
-   struct iommu_domain_geometry *geom_attr = data;
-   struct fsl_dma_domain *dma_domain = to_fsl_dma_domain(domain);
-   dma_addr_t geom_size;
-   unsigned long flags;
-
-   geom_size = geom_attr->aperture_end - geom_attr->aperture_start + 1;
-   /*
-* Sanity check the geometry size. Also, we do not support
-* DMA outside of the geometry.
-*/
-   if (check_size(geom_size, geom_attr->aperture_start) ||
-   !geom_attr->force_aperture) {
-   pr_debug("Invalid PAMU geometry attributes\n");
-   return -EINVAL;
-   }
-
-   spin_lock_irqsave(&dma_domain->domain_lock, flags);
-   if (dma_domain->enabled) {
-   pr_debug("Can't set geometry attributes as domain is active\n");
-   spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
-   return  -EBUSY;
-   }
-
-   /* Copy the domain geometry information */
-   memcpy(&domain->geometry, geom_attr,
-  sizeof(struct iommu_domain_geometry));
-   dma_domain->geom_size = geom_size;
-
-   spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
-
-   return 0;
-}
-
 /* Set the domain stash attribute */
 static int configure_domain_stash(struct fsl_dma_domain *dma_domain, void 
*data)
 {
@@ -769,13 +734,6 @@ static int fsl_pamu_set_windows(struct iommu_domain 
*domain, u32 w_count)
return  -EBUSY;
}
 
-   /* Ensure that the geometry has been set for the domain */
-   if (!dma_domain->geom_size) {
-   pr_debug("Please configure geometry before setting the number 
of windows\n");
-   spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
-   return -EINVAL;
-   }
-
/*
 * Ensure we have valid window count i.e. it should be less than
 * maximum permissible limit and should be a power of two.
@@ -811,9 +769,6 @@ static int fsl_pamu_set_domain_attr(struct iommu_domain 
*domain,
int ret = 0;
 
switch (a

[PATCH 19/20] iommu: remove DOMAIN_ATTR_IO_PGTABLE_CFG

2021-04-01 Thread Christoph Hellwig
Use an explicit set_pgtable_quirks method instead that just passes
the actual quirk bitmask instead.

Signed-off-by: Christoph Hellwig 
Acked-by: Will Deacon 
Acked-by: Li Yang 
---
 drivers/gpu/drm/msm/adreno/adreno_gpu.c |  5 +-
 drivers/iommu/arm/arm-smmu/arm-smmu.c   | 64 +
 drivers/iommu/arm/arm-smmu/arm-smmu.h   |  2 +-
 drivers/iommu/iommu.c   | 11 +
 include/linux/io-pgtable.h  |  4 --
 include/linux/iommu.h   | 12 -
 6 files changed, 35 insertions(+), 63 deletions(-)

diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c 
b/drivers/gpu/drm/msm/adreno/adreno_gpu.c
index 0f184c3dd9d9ec..4a0b14dad93e2e 100644
--- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c
@@ -188,10 +188,7 @@ int adreno_zap_shader_load(struct msm_gpu *gpu, u32 pasid)
 
 void adreno_set_llc_attributes(struct iommu_domain *iommu)
 {
-   struct io_pgtable_domain_attr pgtbl_cfg;
-
-   pgtbl_cfg.quirks = IO_PGTABLE_QUIRK_ARM_OUTER_WBWA;
-   iommu_domain_set_attr(iommu, DOMAIN_ATTR_IO_PGTABLE_CFG, &pgtbl_cfg);
+   iommu_set_pgtable_quirks(iommu, IO_PGTABLE_QUIRK_ARM_OUTER_WBWA);
 }
 
 struct msm_gem_address_space *
diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu.c 
b/drivers/iommu/arm/arm-smmu/arm-smmu.c
index f17c54a76ef6f1..3c6adcdb201bb8 100644
--- a/drivers/iommu/arm/arm-smmu/arm-smmu.c
+++ b/drivers/iommu/arm/arm-smmu/arm-smmu.c
@@ -770,8 +770,8 @@ static int arm_smmu_init_domain_context(struct iommu_domain 
*domain,
goto out_clear_smmu;
}
 
-   if (smmu_domain->pgtbl_cfg.quirks)
-   pgtbl_cfg.quirks |= smmu_domain->pgtbl_cfg.quirks;
+   if (smmu_domain->pgtbl_quirks)
+   pgtbl_cfg.quirks |= smmu_domain->pgtbl_quirks;
 
pgtbl_ops = alloc_io_pgtable_ops(fmt, &pgtbl_cfg, smmu_domain);
if (!pgtbl_ops) {
@@ -1484,29 +1484,6 @@ static struct iommu_group *arm_smmu_device_group(struct 
device *dev)
return group;
 }
 
-static int arm_smmu_domain_get_attr(struct iommu_domain *domain,
-   enum iommu_attr attr, void *data)
-{
-   struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
-
-   switch(domain->type) {
-   case IOMMU_DOMAIN_UNMANAGED:
-   switch (attr) {
-   case DOMAIN_ATTR_IO_PGTABLE_CFG: {
-   struct io_pgtable_domain_attr *pgtbl_cfg = data;
-   *pgtbl_cfg = smmu_domain->pgtbl_cfg;
-
-   return 0;
-   }
-   default:
-   return -ENODEV;
-   }
-   break;
-   default:
-   return -EINVAL;
-   }
-}
-
 static int arm_smmu_enable_nesting(struct iommu_domain *domain)
 {
struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
@@ -1522,37 +1499,19 @@ static int arm_smmu_enable_nesting(struct iommu_domain 
*domain)
return ret;
 }
 
-static int arm_smmu_domain_set_attr(struct iommu_domain *domain,
-   enum iommu_attr attr, void *data)
+static int arm_smmu_set_pgtable_quirks(struct iommu_domain *domain,
+   unsigned long quirks)
 {
-   int ret = 0;
struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
+   int ret = 0;
 
mutex_lock(&smmu_domain->init_mutex);
-
-   switch(domain->type) {
-   case IOMMU_DOMAIN_UNMANAGED:
-   switch (attr) {
-   case DOMAIN_ATTR_IO_PGTABLE_CFG: {
-   struct io_pgtable_domain_attr *pgtbl_cfg = data;
-
-   if (smmu_domain->smmu) {
-   ret = -EPERM;
-   goto out_unlock;
-   }
-
-   smmu_domain->pgtbl_cfg = *pgtbl_cfg;
-   break;
-   }
-   default:
-   ret = -ENODEV;
-   }
-   break;
-   default:
-   ret = -EINVAL;
-   }
-out_unlock:
+   if (smmu_domain->smmu)
+   ret = -EPERM;
+   else
+   smmu_domain->pgtbl_quirks = quirks;
mutex_unlock(&smmu_domain->init_mutex);
+
return ret;
 }
 
@@ -1611,9 +1570,8 @@ static struct iommu_ops arm_smmu_ops = {
.probe_device   = arm_smmu_probe_device,
.release_device = arm_smmu_release_device,
.device_group   = arm_smmu_device_group,
-   .domain_get_attr= arm_smmu_domain_get_attr,
-   .domain_set_attr= arm_smmu_domain_set_attr,
.enable_nesting = arm_smmu_enable_nesting,
+   .set_pgtable_quirks = arm_smmu_set_pgtable_quirks,
.of_xlate   = arm_smmu_of_xlate,
.get_resv_regions   = arm_smmu_get_resv_regions,
.put_resv_regions   = generic_iommu_put_resv_regions,
diff --git a/drivers/iommu/arm/arm-smm

[PATCH 06/20] iommu/fsl_pamu: remove ->domain_window_enable

2021-04-01 Thread Christoph Hellwig
The only thing that fsl_pamu_window_enable does for the current caller
is to fill in the prot value in the only dma_window structure, and to
propagate a few values from the iommu_domain_geometry struture into the
dma_window.  Remove the dma_window entirely, hardcode the prot value and
otherwise use the iommu_domain_geometry structure instead.

Remove the now unused ->domain_window_enable iommu method.

Signed-off-by: Christoph Hellwig 
Acked-by: Li Yang 
---
 drivers/iommu/fsl_pamu_domain.c | 182 +++-
 drivers/iommu/fsl_pamu_domain.h |  15 ---
 drivers/iommu/iommu.c   |  11 --
 drivers/soc/fsl/qbman/qman_portal.c |   7 --
 include/linux/iommu.h   |  17 ---
 5 files changed, 14 insertions(+), 218 deletions(-)

diff --git a/drivers/iommu/fsl_pamu_domain.c b/drivers/iommu/fsl_pamu_domain.c
index e6bdd38fc18409..689035e9d40955 100644
--- a/drivers/iommu/fsl_pamu_domain.c
+++ b/drivers/iommu/fsl_pamu_domain.c
@@ -54,34 +54,18 @@ static int __init iommu_init_mempool(void)
return 0;
 }
 
-static phys_addr_t get_phys_addr(struct fsl_dma_domain *dma_domain, dma_addr_t 
iova)
-{
-   struct dma_window *win_ptr = &dma_domain->win_arr[0];
-   struct iommu_domain_geometry *geom;
-
-   geom = &dma_domain->iommu_domain.geometry;
-
-   if (win_ptr->valid)
-   return win_ptr->paddr + (iova & (win_ptr->size - 1));
-
-   return 0;
-}
-
 /* Map the DMA window corresponding to the LIODN */
 static int map_liodn(int liodn, struct fsl_dma_domain *dma_domain)
 {
int ret;
-   struct dma_window *wnd = &dma_domain->win_arr[0];
-   phys_addr_t wnd_addr = dma_domain->iommu_domain.geometry.aperture_start;
+   struct iommu_domain_geometry *geom = &dma_domain->iommu_domain.geometry;
unsigned long flags;
 
spin_lock_irqsave(&iommu_lock, flags);
-   ret = pamu_config_ppaace(liodn, wnd_addr,
-wnd->size,
-~(u32)0,
-wnd->paddr >> PAMU_PAGE_SHIFT,
-dma_domain->snoop_id, dma_domain->stash_id,
-wnd->prot);
+   ret = pamu_config_ppaace(liodn, geom->aperture_start,
+geom->aperture_end + 1, ~(u32)0,
+0, dma_domain->snoop_id, dma_domain->stash_id,
+PAACE_AP_PERMS_QUERY | PAACE_AP_PERMS_UPDATE);
spin_unlock_irqrestore(&iommu_lock, flags);
if (ret)
pr_debug("PAACE configuration failed for liodn %d\n", liodn);
@@ -89,33 +73,6 @@ static int map_liodn(int liodn, struct fsl_dma_domain 
*dma_domain)
return ret;
 }
 
-/* Update window/subwindow mapping for the LIODN */
-static int update_liodn(int liodn, struct fsl_dma_domain *dma_domain, u32 
wnd_nr)
-{
-   int ret;
-   struct dma_window *wnd = &dma_domain->win_arr[wnd_nr];
-   phys_addr_t wnd_addr;
-   unsigned long flags;
-
-   spin_lock_irqsave(&iommu_lock, flags);
-
-   wnd_addr = dma_domain->iommu_domain.geometry.aperture_start;
-
-   ret = pamu_config_ppaace(liodn, wnd_addr,
-wnd->size,
-~(u32)0,
-wnd->paddr >> PAMU_PAGE_SHIFT,
-dma_domain->snoop_id, dma_domain->stash_id,
-wnd->prot);
-   if (ret)
-   pr_debug("Window reconfiguration failed for liodn %d\n",
-liodn);
-
-   spin_unlock_irqrestore(&iommu_lock, flags);
-
-   return ret;
-}
-
 static int update_liodn_stash(int liodn, struct fsl_dma_domain *dma_domain,
  u32 val)
 {
@@ -172,26 +129,6 @@ static int pamu_set_liodn(int liodn, struct device *dev,
return ret;
 }
 
-static int check_size(u64 size, dma_addr_t iova)
-{
-   /*
-* Size must be a power of two and at least be equal
-* to PAMU page size.
-*/
-   if ((size & (size - 1)) || size < PAMU_PAGE_SIZE) {
-   pr_debug("Size too small or not a power of two\n");
-   return -EINVAL;
-   }
-
-   /* iova must be page size aligned */
-   if (iova & (size - 1)) {
-   pr_debug("Address is not aligned with window size\n");
-   return -EINVAL;
-   }
-
-   return 0;
-}
-
 static void remove_device_ref(struct device_domain_info *info)
 {
unsigned long flags;
@@ -257,13 +194,10 @@ static void attach_device(struct fsl_dma_domain 
*dma_domain, int liodn, struct d
 static phys_addr_t fsl_pamu_iova_to_phys(struct iommu_domain *domain,
 dma_addr_t iova)
 {
-   struct fsl_dma_domain *dma_domain = to_fsl_dma_domain(domain);
-
if (iova < domain->geometry.aperture_start ||
iova > domain->geometry.aperture_end)
return 0;
-
-   return g

[PATCH 02/20] iommu/fsl_pamu: remove fsl_pamu_get_domain_attr

2021-04-01 Thread Christoph Hellwig
None of the values returned by this function are ever queried.  Also
remove the DOMAIN_ATTR_FSL_PAMUV1 enum value that is not otherwise used.

Signed-off-by: Christoph Hellwig 
Acked-by: Will Deacon 
Acked-by: Li Yang 
---
 drivers/iommu/fsl_pamu_domain.c | 30 --
 include/linux/iommu.h   |  4 
 2 files changed, 34 deletions(-)

diff --git a/drivers/iommu/fsl_pamu_domain.c b/drivers/iommu/fsl_pamu_domain.c
index 53380cf1fa452f..e587ec43f7e750 100644
--- a/drivers/iommu/fsl_pamu_domain.c
+++ b/drivers/iommu/fsl_pamu_domain.c
@@ -832,35 +832,6 @@ static int fsl_pamu_set_domain_attr(struct iommu_domain 
*domain,
return ret;
 }
 
-static int fsl_pamu_get_domain_attr(struct iommu_domain *domain,
-   enum iommu_attr attr_type, void *data)
-{
-   struct fsl_dma_domain *dma_domain = to_fsl_dma_domain(domain);
-   int ret = 0;
-
-   switch (attr_type) {
-   case DOMAIN_ATTR_FSL_PAMU_STASH:
-   memcpy(data, &dma_domain->dma_stash,
-  sizeof(struct pamu_stash_attribute));
-   break;
-   case DOMAIN_ATTR_FSL_PAMU_ENABLE:
-   *(int *)data = dma_domain->enabled;
-   break;
-   case DOMAIN_ATTR_FSL_PAMUV1:
-   *(int *)data = DOMAIN_ATTR_FSL_PAMUV1;
-   break;
-   case DOMAIN_ATTR_WINDOWS:
-   *(u32 *)data = dma_domain->win_cnt;
-   break;
-   default:
-   pr_debug("Unsupported attribute type\n");
-   ret = -EINVAL;
-   break;
-   }
-
-   return ret;
-}
-
 static struct iommu_group *get_device_iommu_group(struct device *dev)
 {
struct iommu_group *group;
@@ -987,7 +958,6 @@ static const struct iommu_ops fsl_pamu_ops = {
.domain_window_enable = fsl_pamu_window_enable,
.iova_to_phys   = fsl_pamu_iova_to_phys,
.domain_set_attr = fsl_pamu_set_domain_attr,
-   .domain_get_attr = fsl_pamu_get_domain_attr,
.probe_device   = fsl_pamu_probe_device,
.release_device = fsl_pamu_release_device,
.device_group   = fsl_pamu_device_group,
diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index 47c8b318d8f523..52874ae164dd60 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -104,9 +104,6 @@ enum iommu_cap {
  *  -the actual size of the mapped region of a window must be power
  *   of 2 starting with 4KB and physical address must be naturally
  *   aligned.
- * DOMAIN_ATTR_FSL_PAMUV1 corresponds to the above mentioned contraints.
- * The caller can invoke iommu_domain_get_attr to check if the underlying
- * iommu implementation supports these constraints.
  */
 
 enum iommu_attr {
@@ -115,7 +112,6 @@ enum iommu_attr {
DOMAIN_ATTR_WINDOWS,
DOMAIN_ATTR_FSL_PAMU_STASH,
DOMAIN_ATTR_FSL_PAMU_ENABLE,
-   DOMAIN_ATTR_FSL_PAMUV1,
DOMAIN_ATTR_NESTING,/* two stages of translation */
DOMAIN_ATTR_DMA_USE_FLUSH_QUEUE,
DOMAIN_ATTR_IO_PGTABLE_CFG,
-- 
2.30.1

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH 01/20] iommu: remove the unused domain_window_disable method

2021-04-01 Thread Christoph Hellwig
domain_window_disable is wired up by fsl_pamu, but never actually called.

Signed-off-by: Christoph Hellwig 
Acked-by: Will Deacon 
Acked-by: Li Yang 
---
 drivers/iommu/fsl_pamu_domain.c | 48 -
 include/linux/iommu.h   |  2 --
 2 files changed, 50 deletions(-)

diff --git a/drivers/iommu/fsl_pamu_domain.c b/drivers/iommu/fsl_pamu_domain.c
index b2110767caf49c..53380cf1fa452f 100644
--- a/drivers/iommu/fsl_pamu_domain.c
+++ b/drivers/iommu/fsl_pamu_domain.c
@@ -473,53 +473,6 @@ static int update_domain_mapping(struct fsl_dma_domain 
*dma_domain, u32 wnd_nr)
return ret;
 }
 
-static int disable_domain_win(struct fsl_dma_domain *dma_domain, u32 wnd_nr)
-{
-   struct device_domain_info *info;
-   int ret = 0;
-
-   list_for_each_entry(info, &dma_domain->devices, link) {
-   if (dma_domain->win_cnt == 1 && dma_domain->enabled) {
-   ret = pamu_disable_liodn(info->liodn);
-   if (!ret)
-   dma_domain->enabled = 0;
-   } else {
-   ret = pamu_disable_spaace(info->liodn, wnd_nr);
-   }
-   }
-
-   return ret;
-}
-
-static void fsl_pamu_window_disable(struct iommu_domain *domain, u32 wnd_nr)
-{
-   struct fsl_dma_domain *dma_domain = to_fsl_dma_domain(domain);
-   unsigned long flags;
-   int ret;
-
-   spin_lock_irqsave(&dma_domain->domain_lock, flags);
-   if (!dma_domain->win_arr) {
-   pr_debug("Number of windows not configured\n");
-   spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
-   return;
-   }
-
-   if (wnd_nr >= dma_domain->win_cnt) {
-   pr_debug("Invalid window index\n");
-   spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
-   return;
-   }
-
-   if (dma_domain->win_arr[wnd_nr].valid) {
-   ret = disable_domain_win(dma_domain, wnd_nr);
-   if (!ret) {
-   dma_domain->win_arr[wnd_nr].valid = 0;
-   dma_domain->mapped--;
-   }
-   }
-
-   spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
-}
 
 static int fsl_pamu_window_enable(struct iommu_domain *domain, u32 wnd_nr,
  phys_addr_t paddr, u64 size, int prot)
@@ -1032,7 +985,6 @@ static const struct iommu_ops fsl_pamu_ops = {
.attach_dev = fsl_pamu_attach_device,
.detach_dev = fsl_pamu_detach_device,
.domain_window_enable = fsl_pamu_window_enable,
-   .domain_window_disable = fsl_pamu_window_disable,
.iova_to_phys   = fsl_pamu_iova_to_phys,
.domain_set_attr = fsl_pamu_set_domain_attr,
.domain_get_attr = fsl_pamu_get_domain_attr,
diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index 5e7fe519430af4..47c8b318d8f523 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -209,7 +209,6 @@ struct iommu_iotlb_gather {
  * @put_resv_regions: Free list of reserved regions for a device
  * @apply_resv_region: Temporary helper call-back for iova reserved ranges
  * @domain_window_enable: Configure and enable a particular window for a domain
- * @domain_window_disable: Disable a particular window for a domain
  * @of_xlate: add OF master IDs to iommu grouping
  * @is_attach_deferred: Check if domain attach should be deferred from iommu
  *  driver init to device driver init (default no)
@@ -270,7 +269,6 @@ struct iommu_ops {
/* Window handling functions */
int (*domain_window_enable)(struct iommu_domain *domain, u32 wnd_nr,
phys_addr_t paddr, u64 size, int prot);
-   void (*domain_window_disable)(struct iommu_domain *domain, u32 wnd_nr);
 
int (*of_xlate)(struct device *dev, struct of_phandle_args *args);
bool (*is_attach_deferred)(struct iommu_domain *domain, struct device 
*dev);
-- 
2.30.1

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH 15/20] iommu: remove DOMAIN_ATTR_GEOMETRY

2021-04-01 Thread Christoph Hellwig
The geometry information can be trivially queried from the iommu_domain
struture.

Signed-off-by: Christoph Hellwig 
Acked-by: Will Deacon 
Acked-by: Li Yang 
---
 drivers/iommu/iommu.c   | 20 +++-
 drivers/vfio/vfio_iommu_type1.c | 26 --
 drivers/vhost/vdpa.c| 10 +++---
 include/linux/iommu.h   |  1 -
 4 files changed, 18 insertions(+), 39 deletions(-)

diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 9a4cda390993e6..23daaea7883b75 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -2667,23 +2667,9 @@ core_initcall(iommu_init);
 int iommu_domain_get_attr(struct iommu_domain *domain,
  enum iommu_attr attr, void *data)
 {
-   struct iommu_domain_geometry *geometry;
-   int ret = 0;
-
-   switch (attr) {
-   case DOMAIN_ATTR_GEOMETRY:
-   geometry  = data;
-   *geometry = domain->geometry;
-
-   break;
-   default:
-   if (!domain->ops->domain_get_attr)
-   return -EINVAL;
-
-   ret = domain->ops->domain_get_attr(domain, attr, data);
-   }
-
-   return ret;
+   if (!domain->ops->domain_get_attr)
+   return -EINVAL;
+   return domain->ops->domain_get_attr(domain, attr, data);
 }
 EXPORT_SYMBOL_GPL(iommu_domain_get_attr);
 
diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c
index 45cbfd4879a553..ae6d72f17aee78 100644
--- a/drivers/vfio/vfio_iommu_type1.c
+++ b/drivers/vfio/vfio_iommu_type1.c
@@ -2262,7 +2262,7 @@ static int vfio_iommu_type1_attach_group(void *iommu_data,
int ret;
bool resv_msi, msi_remap;
phys_addr_t resv_msi_base = 0;
-   struct iommu_domain_geometry geo;
+   struct iommu_domain_geometry *geo;
LIST_HEAD(iova_copy);
LIST_HEAD(group_resv_regions);
 
@@ -2343,10 +2343,9 @@ static int vfio_iommu_type1_attach_group(void 
*iommu_data,
goto out_domain;
 
/* Get aperture info */
-   iommu_domain_get_attr(domain->domain, DOMAIN_ATTR_GEOMETRY, &geo);
-
-   if (vfio_iommu_aper_conflict(iommu, geo.aperture_start,
-geo.aperture_end)) {
+   geo = &domain->domain->geometry;
+   if (vfio_iommu_aper_conflict(iommu, geo->aperture_start,
+geo->aperture_end)) {
ret = -EINVAL;
goto out_detach;
}
@@ -2369,8 +2368,8 @@ static int vfio_iommu_type1_attach_group(void *iommu_data,
if (ret)
goto out_detach;
 
-   ret = vfio_iommu_aper_resize(&iova_copy, geo.aperture_start,
-geo.aperture_end);
+   ret = vfio_iommu_aper_resize(&iova_copy, geo->aperture_start,
+geo->aperture_end);
if (ret)
goto out_detach;
 
@@ -2503,7 +2502,6 @@ static void vfio_iommu_aper_expand(struct vfio_iommu 
*iommu,
   struct list_head *iova_copy)
 {
struct vfio_domain *domain;
-   struct iommu_domain_geometry geo;
struct vfio_iova *node;
dma_addr_t start = 0;
dma_addr_t end = (dma_addr_t)~0;
@@ -2512,12 +2510,12 @@ static void vfio_iommu_aper_expand(struct vfio_iommu 
*iommu,
return;
 
list_for_each_entry(domain, &iommu->domain_list, next) {
-   iommu_domain_get_attr(domain->domain, DOMAIN_ATTR_GEOMETRY,
- &geo);
-   if (geo.aperture_start > start)
-   start = geo.aperture_start;
-   if (geo.aperture_end < end)
-   end = geo.aperture_end;
+   struct iommu_domain_geometry *geo = &domain->domain->geometry;
+
+   if (geo->aperture_start > start)
+   start = geo->aperture_start;
+   if (geo->aperture_end < end)
+   end = geo->aperture_end;
}
 
/* Modify aperture limits. The new aper is either same or bigger */
diff --git a/drivers/vhost/vdpa.c b/drivers/vhost/vdpa.c
index e0a27e33629356..cd1ff7b556dcee 100644
--- a/drivers/vhost/vdpa.c
+++ b/drivers/vhost/vdpa.c
@@ -832,18 +832,14 @@ static void vhost_vdpa_free_domain(struct vhost_vdpa *v)
 static void vhost_vdpa_set_iova_range(struct vhost_vdpa *v)
 {
struct vdpa_iova_range *range = &v->range;
-   struct iommu_domain_geometry geo;
struct vdpa_device *vdpa = v->vdpa;
const struct vdpa_config_ops *ops = vdpa->config;
 
if (ops->get_iova_range) {
*range = ops->get_iova_range(vdpa);
-   } else if (v->domain &&
-  !iommu_domain_get_attr(v->domain,
-  DOMAIN_ATTR_GEOMETRY, &geo) &&
-  geo.force_aperture) {
-   range->first = geo.aperture_start;
-   range->last = geo.aperture_end;
+   } 

[RFC PATCH 5/6] iommu: Hook up '->unmap_pages' driver callback

2021-04-01 Thread Will Deacon
Extend iommu_pgsize() to populate an optional 'count' paramater so that
we can direct unmapping operation to the ->unmap_pages callback if it
has been provided by the driver.

Signed-off-by: Will Deacon 
---
 drivers/iommu/iommu.c | 26 --
 1 file changed, 20 insertions(+), 6 deletions(-)

diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index ab689611a03b..fe186691fc21 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -2358,7 +2358,7 @@ phys_addr_t iommu_iova_to_phys(struct iommu_domain 
*domain, dma_addr_t iova)
 EXPORT_SYMBOL_GPL(iommu_iova_to_phys);
 
 static size_t iommu_pgsize(struct iommu_domain *domain, unsigned long iova,
-  phys_addr_t paddr, size_t size)
+  phys_addr_t paddr, size_t size, size_t *count)
 {
unsigned int pgsize_idx;
unsigned long pgsizes;
@@ -2379,6 +2379,8 @@ static size_t iommu_pgsize(struct iommu_domain *domain, 
unsigned long iova,
pgsize_idx = __fls(pgsizes);
pgsize = BIT(pgsize_idx);
 
+   if (count)
+   *count = size >> pgsize_idx;
return pgsize;
 }
 
@@ -2416,7 +2418,7 @@ static int __iommu_map(struct iommu_domain *domain, 
unsigned long iova,
pr_debug("map: iova 0x%lx pa %pa size 0x%zx\n", iova, &paddr, size);
 
while (size) {
-   size_t pgsize = iommu_pgsize(domain, iova, paddr, size);
+   size_t pgsize = iommu_pgsize(domain, iova, paddr, size, NULL);
 
pr_debug("mapping: iova 0x%lx pa %pa pgsize 0x%zx\n",
 iova, &paddr, pgsize);
@@ -2467,6 +2469,19 @@ int iommu_map_atomic(struct iommu_domain *domain, 
unsigned long iova,
 }
 EXPORT_SYMBOL_GPL(iommu_map_atomic);
 
+static size_t __iommu_unmap_pages(struct iommu_domain *domain,
+ unsigned long iova, size_t size,
+ struct iommu_iotlb_gather *iotlb_gather)
+{
+   const struct iommu_ops *ops = domain->ops;
+   size_t pgsize, count;
+
+   pgsize = iommu_pgsize(domain, iova, iova, size, &count);
+   return ops->unmap_pages ?
+  ops->unmap_pages(domain, iova, pgsize, count, iotlb_gather) :
+  ops->unmap(domain, iova, pgsize, iotlb_gather);
+}
+
 static size_t __iommu_unmap(struct iommu_domain *domain,
unsigned long iova, size_t size,
struct iommu_iotlb_gather *iotlb_gather)
@@ -2504,10 +2519,9 @@ static size_t __iommu_unmap(struct iommu_domain *domain,
 * or we hit an area that isn't mapped.
 */
while (unmapped < size) {
-   size_t pgsize;
-
-   pgsize = iommu_pgsize(domain, iova, iova, size - unmapped);
-   unmapped_page = ops->unmap(domain, iova, pgsize, iotlb_gather);
+   unmapped_page = __iommu_unmap_pages(domain, iova,
+   size - unmapped,
+   iotlb_gather);
if (!unmapped_page)
break;
 
-- 
2.31.0.291.g576ba9dcdaf-goog

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[RFC PATCH 6/6] iommu: Accomodate larger pages in iommu_pgsize() 'count' calculation

2021-04-01 Thread Will Deacon
Extend the calculation of 'count' in iommu_pgsize() so that it takes
larger page sizes into consideration and returns a value which will
allow a larger page size to be used on the next call.

Signed-off-by: Will Deacon 
---
 drivers/iommu/iommu.c | 36 
 1 file changed, 32 insertions(+), 4 deletions(-)

diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index fe186691fc21..0572a4dcd9e2 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -2360,9 +2360,9 @@ EXPORT_SYMBOL_GPL(iommu_iova_to_phys);
 static size_t iommu_pgsize(struct iommu_domain *domain, unsigned long iova,
   phys_addr_t paddr, size_t size, size_t *count)
 {
-   unsigned int pgsize_idx;
+   unsigned int pgsize_idx, pgsize_idx_next;
unsigned long pgsizes;
-   size_t pgsize;
+   size_t offset, pgsize, pgsize_next;
phys_addr_t addr_merge = paddr | iova;
 
/* Page sizes supported by the hardware and small enough for @size */
@@ -2378,9 +2378,37 @@ static size_t iommu_pgsize(struct iommu_domain *domain, 
unsigned long iova,
/* Pick the biggest page size remaining */
pgsize_idx = __fls(pgsizes);
pgsize = BIT(pgsize_idx);
+   if (!count)
+   return pgsize;
 
-   if (count)
-   *count = size >> pgsize_idx;
+
+   /* Find the next biggest support page size, if it exists */
+   pgsizes = domain->pgsize_bitmap & ~GENMASK(pgsize_idx, 0);
+   if (!pgsizes)
+   goto out_set_count;
+
+   pgsize_idx_next = __ffs(pgsizes);
+   pgsize_next = BIT(pgsize_idx_next);
+
+   /*
+* There's no point trying a bigger page size unless the virtual
+* and physical addresses are similarly offset within the larger page.
+*/
+   if ((iova ^ paddr) & (pgsize_next - 1))
+   goto out_set_count;
+
+   /* Calculate the offset to the next page size alignment boundary */
+   offset = pgsize_next - (addr_merge & (pgsize_next - 1));
+
+   /*
+* If size is big enough to accomodate the larger page, reduce
+* the number of smaller pages.
+*/
+   if (offset + pgsize_next <= size)
+   size = offset;
+
+out_set_count:
+   *count = size >> pgsize_idx;
return pgsize;
 }
 
-- 
2.31.0.291.g576ba9dcdaf-goog

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[RFC PATCH 3/6] iommu: Use bitmap to calculate page size in iommu_pgsize()

2021-04-01 Thread Will Deacon
Avoid the potential for shifting values by amounts greater than the
width of their type by using a bitmap to compute page size in
iommu_pgsize().

Signed-off-by: Will Deacon 
---
 drivers/iommu/iommu.c | 31 ---
 1 file changed, 12 insertions(+), 19 deletions(-)

diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index d0b0a15dba84..bcd623862bf9 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -8,6 +8,7 @@
 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -2360,30 +2361,22 @@ static size_t iommu_pgsize(struct iommu_domain *domain,
   unsigned long addr_merge, size_t size)
 {
unsigned int pgsize_idx;
+   unsigned long pgsizes;
size_t pgsize;
 
-   /* Max page size that still fits into 'size' */
-   pgsize_idx = __fls(size);
+   /* Page sizes supported by the hardware and small enough for @size */
+   pgsizes = domain->pgsize_bitmap & GENMASK(__fls(size), 0);
 
-   /* need to consider alignment requirements ? */
-   if (likely(addr_merge)) {
-   /* Max page size allowed by address */
-   unsigned int align_pgsize_idx = __ffs(addr_merge);
-   pgsize_idx = min(pgsize_idx, align_pgsize_idx);
-   }
-
-   /* build a mask of acceptable page sizes */
-   pgsize = (1UL << (pgsize_idx + 1)) - 1;
-
-   /* throw away page sizes not supported by the hardware */
-   pgsize &= domain->pgsize_bitmap;
+   /* Constrain the page sizes further based on the maximum alignment */
+   if (likely(addr_merge))
+   pgsizes &= GENMASK(__ffs(addr_merge), 0);
 
-   /* make sure we're still sane */
-   BUG_ON(!pgsize);
+   /* Make sure we have at least one suitable page size */
+   BUG_ON(!pgsizes);
 
-   /* pick the biggest page */
-   pgsize_idx = __fls(pgsize);
-   pgsize = 1UL << pgsize_idx;
+   /* Pick the biggest page size remaining */
+   pgsize_idx = __fls(pgsizes);
+   pgsize = BIT(pgsize_idx);
 
return pgsize;
 }
-- 
2.31.0.291.g576ba9dcdaf-goog

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[RFC PATCH 4/6] iommu: Split 'addr_merge' argument to iommu_pgsize() into separate parts

2021-04-01 Thread Will Deacon
The 'addr_merge' parameter to iommu_pgsize() is a fabricated address
intended to describe the alignment requirements to consider when
choosing an appropriate page size. On the iommu_map() path, this address
is the logical OR of the virtual and physical addresses.

Subsequent improvements to iommu_pgsize() will need to check the
alignment of the virtual and physical components of 'addr_merge'
independently, so pass them in as separate parameters and reconstruct
'addr_merge' locally.

No functional change.

Signed-off-by: Will Deacon 
---
 drivers/iommu/iommu.c | 10 ++
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index bcd623862bf9..ab689611a03b 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -2357,12 +2357,13 @@ phys_addr_t iommu_iova_to_phys(struct iommu_domain 
*domain, dma_addr_t iova)
 }
 EXPORT_SYMBOL_GPL(iommu_iova_to_phys);
 
-static size_t iommu_pgsize(struct iommu_domain *domain,
-  unsigned long addr_merge, size_t size)
+static size_t iommu_pgsize(struct iommu_domain *domain, unsigned long iova,
+  phys_addr_t paddr, size_t size)
 {
unsigned int pgsize_idx;
unsigned long pgsizes;
size_t pgsize;
+   phys_addr_t addr_merge = paddr | iova;
 
/* Page sizes supported by the hardware and small enough for @size */
pgsizes = domain->pgsize_bitmap & GENMASK(__fls(size), 0);
@@ -2415,7 +2416,7 @@ static int __iommu_map(struct iommu_domain *domain, 
unsigned long iova,
pr_debug("map: iova 0x%lx pa %pa size 0x%zx\n", iova, &paddr, size);
 
while (size) {
-   size_t pgsize = iommu_pgsize(domain, iova | paddr, size);
+   size_t pgsize = iommu_pgsize(domain, iova, paddr, size);
 
pr_debug("mapping: iova 0x%lx pa %pa pgsize 0x%zx\n",
 iova, &paddr, pgsize);
@@ -2503,8 +2504,9 @@ static size_t __iommu_unmap(struct iommu_domain *domain,
 * or we hit an area that isn't mapped.
 */
while (unmapped < size) {
-   size_t pgsize = iommu_pgsize(domain, iova, size - unmapped);
+   size_t pgsize;
 
+   pgsize = iommu_pgsize(domain, iova, iova, size - unmapped);
unmapped_page = ops->unmap(domain, iova, pgsize, iotlb_gather);
if (!unmapped_page)
break;
-- 
2.31.0.291.g576ba9dcdaf-goog

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[RFC PATCH 2/6] iommu: Add an unmap_pages() op for IOMMU drivers

2021-04-01 Thread Will Deacon
From: "Isaac J. Manjarres" 

Add a callback for IOMMU drivers to provide a path for the
IOMMU framework to call into an IOMMU driver, which can call
into the io-pgtable code, to unmap a virtually contiguous
range of pages of the same size.

For IOMMU drivers that do not specify an unmap_pages() callback,
the existing logic of unmapping memory one page block at a time
will be used.

Signed-off-by: Isaac J. Manjarres 
Suggested-by: Will Deacon 
Signed-off-by: Will Deacon 
---
 include/linux/iommu.h | 4 
 1 file changed, 4 insertions(+)

diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index 5e7fe519430a..9cf81242581a 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -193,6 +193,7 @@ struct iommu_iotlb_gather {
  * @detach_dev: detach device from an iommu domain
  * @map: map a physically contiguous memory region to an iommu domain
  * @unmap: unmap a physically contiguous memory region from an iommu domain
+ * @unmap_pages: unmap a number of pages of the same size from an iommu domain
  * @flush_iotlb_all: Synchronously flush all hardware TLBs for this domain
  * @iotlb_sync_map: Sync mappings created recently using @map to the hardware
  * @iotlb_sync: Flush all queued ranges from the hardware TLBs and empty flush
@@ -245,6 +246,9 @@ struct iommu_ops {
   phys_addr_t paddr, size_t size, int prot, gfp_t gfp);
size_t (*unmap)(struct iommu_domain *domain, unsigned long iova,
 size_t size, struct iommu_iotlb_gather *iotlb_gather);
+   size_t (*unmap_pages)(struct iommu_domain *domain, unsigned long iova,
+ size_t pgsize, size_t pgcount,
+ struct iommu_iotlb_gather *iotlb_gather);
void (*flush_iotlb_all)(struct iommu_domain *domain);
void (*iotlb_sync_map)(struct iommu_domain *domain, unsigned long iova,
   size_t size);
-- 
2.31.0.291.g576ba9dcdaf-goog

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[RFC PATCH 0/6] iommu_pgsize() improvements to help towards ->[un]map_pages()

2021-04-01 Thread Will Deacon
Hi Isaac,

I had a go at removing the loop you have in pgsize_bitmap() over at:

https://lore.kernel.org/r/20210331030042.13348-4-isa...@codeaurora.org

and I ended up with this. It's _very_ lightly tested, but I thought it
might be useful to you, especially if you're going to be adding support
for '->map_pages' as well.

Cheers,

Will

Cc: "Isaac J. Manjarres" 
Cc: Pratik Patel 
Cc: Robin Murphy 
Cc: Lu Baolu 

--->8

Isaac J. Manjarres (2):
  iommu/io-pgtable: Introduce unmap_pages() as a page table op
  iommu: Add an unmap_pages() op for IOMMU drivers

Will Deacon (4):
  iommu: Use bitmap to calculate page size in iommu_pgsize()
  iommu: Split 'addr_merge' argument to iommu_pgsize() into separate
parts
  iommu: Hook up '->unmap_pages' driver callback
  iommu: Accomodate larger pages in iommu_pgsize() 'count' calculation

 drivers/iommu/iommu.c  | 87 +++---
 include/linux/io-pgtable.h |  4 ++
 include/linux/iommu.h  |  4 ++
 3 files changed, 70 insertions(+), 25 deletions(-)

-- 
2.31.0.291.g576ba9dcdaf-goog

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[RFC PATCH 1/6] iommu/io-pgtable: Introduce unmap_pages() as a page table op

2021-04-01 Thread Will Deacon
From: "Isaac J. Manjarres" 

The io-pgtable code expects to operate on a single block or
granule of memory that is supported by the IOMMU hardware when
unmapping memory.

This means that when a large buffer that consists of multiple
such blocks is unmapped, the io-pgtable code will walk the page
tables to the correct level to unmap each block, even for blocks
that are virtually contiguous and at the same level, which can
incur an overhead in performance.

Introduce the unmap_pages() page table op to express to the
io-pgtable code that it should unmap a number of blocks of
the same size, instead of a single block. Doing so allows
multiple blocks to be unmapped in one call to the io-pgtable
code, reducing the number of page table walks, and indirect
calls.

Signed-off-by: Isaac J. Manjarres 
Suggested-by: Will Deacon 
Signed-off-by: Will Deacon 
---
 include/linux/io-pgtable.h | 4 
 1 file changed, 4 insertions(+)

diff --git a/include/linux/io-pgtable.h b/include/linux/io-pgtable.h
index a4c9ca2c31f1..2ed0c057d9e7 100644
--- a/include/linux/io-pgtable.h
+++ b/include/linux/io-pgtable.h
@@ -144,6 +144,7 @@ struct io_pgtable_cfg {
  *
  * @map:  Map a physically contiguous memory region.
  * @unmap:Unmap a physically contiguous memory region.
+ * @unmap_pages:  Unmap a range of virtually contiguous pages of the same size.
  * @iova_to_phys: Translate iova to physical address.
  *
  * These functions map directly onto the iommu_ops member functions with
@@ -154,6 +155,9 @@ struct io_pgtable_ops {
   phys_addr_t paddr, size_t size, int prot, gfp_t gfp);
size_t (*unmap)(struct io_pgtable_ops *ops, unsigned long iova,
size_t size, struct iommu_iotlb_gather *gather);
+   size_t (*unmap_pages)(struct io_pgtable_ops *ops, unsigned long iova,
+ size_t pgsize, size_t pgcount,
+ struct iommu_iotlb_gather *gather);
phys_addr_t (*iova_to_phys)(struct io_pgtable_ops *ops,
unsigned long iova);
 };
-- 
2.31.0.291.g576ba9dcdaf-goog

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [RFC PATCH 3/5] iommu: Add support for the unmap_pages IOMMU callback

2021-04-01 Thread Will Deacon
On Thu, Apr 01, 2021 at 04:34:37PM +0100, Robin Murphy wrote:
> On 2021-03-31 04:00, Isaac J. Manjarres wrote:
> > The IOMMU framework currently unmaps memory one page block at a time,
> > per the page block sizes that are supported by the IOMMU hardware.
> > Now that IOMMU drivers can supply a callback for unmapping multiple
> > in one call, add support in the IOMMU framework to calculate how many
> > page mappings of the same size can be unmapped in one shot, and invoke the
> > IOMMU driver's unmap_pages callback if it has one. Otherwise, the
> > existing behavior will be used.
> > 
> > Signed-off-by: Isaac J. Manjarres 
> > Suggested-by: Will Deacon 
> > ---
> >   drivers/iommu/iommu.c | 44 +--
> >   1 file changed, 38 insertions(+), 6 deletions(-)
> > 
> > diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
> > index d0b0a15dba84..dc4295f6bc7f 100644
> > --- a/drivers/iommu/iommu.c
> > +++ b/drivers/iommu/iommu.c
> > @@ -2356,8 +2356,8 @@ phys_addr_t iommu_iova_to_phys(struct iommu_domain 
> > *domain, dma_addr_t iova)
> >   }
> >   EXPORT_SYMBOL_GPL(iommu_iova_to_phys);
> > -static size_t iommu_pgsize(struct iommu_domain *domain,
> > -  unsigned long addr_merge, size_t size)
> > +static size_t __iommu_pgsize(struct iommu_domain *domain,
> > +unsigned long addr_merge, size_t size)
> >   {
> > unsigned int pgsize_idx;
> > size_t pgsize;
> > @@ -2388,6 +2388,24 @@ static size_t iommu_pgsize(struct iommu_domain 
> > *domain,
> > return pgsize;
> >   }
> > +static size_t iommu_pgsize(struct iommu_domain *domain,
> > +  unsigned long addr_merge, size_t size,
> > +  size_t *pgcount)
> > +{
> > +   size_t pgsize = __iommu_pgsize(domain, addr_merge, size);
> > +   size_t pgs = 0;
> > +
> > +   do {
> > +   pgs++;
> > +   size -= pgsize;
> > +   addr_merge += pgsize;
> > +   } while (size && __iommu_pgsize(domain, addr_merge, size) == pgsize);
> 
> This looks horrifically inefficient. As part of calculating the best current
> page size it should then be pretty trivial to calculate "(size &
> next_pgsize_up - 1) >> pgsize_idx" for the number of current-size pages up
> to the next-better-size boundary (with next_pgsize_up being 0 if pgsize is
> already the largest possible for the relative alignment of physical and
> virtual address). A loop is just... yuck :(

Hehe, I'm glad you said that as I was thinking the same thing. It's
surprisingly fiddly to get this right, but I spent some time hacking it
today and I _think_ I have something that Isaac could build on (and
hopefully won't be too hairy for ->map either).

I'll post it as an RFC in a sec...

Will
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH V4 05/18] iommu/ioasid: Redefine IOASID set and allocation APIs

2021-04-01 Thread Jason Gunthorpe
On Thu, Apr 01, 2021 at 02:08:17PM +, Liu, Yi L wrote:

> DMA page faults are delivered to root-complex via page request message and
> it is per-device according to PCIe spec. Page request handling flow is:
> 
> 1) iommu driver receives a page request from device
> 2) iommu driver parses the page request message. Get the RID,PASID, faulted
>page and requested permissions etc.
> 3) iommu driver triggers fault handler registered by device driver with
>iommu_report_device_fault()

This seems confused.

The PASID should define how to handle the page fault, not the driver.

I don't remember any device specific actions in ATS, so what is the
driver supposed to do?

> 4) device driver's fault handler signals an event FD to notify userspace to
>fetch the information about the page fault. If it's VM case, inject the
>page fault to VM and let guest to solve it.

If the PASID is set to 'report page fault to userspace' then some
event should come out of /dev/ioasid, or be reported to a linked
eventfd, or whatever.

If the PASID is set to 'SVM' then the fault should be passed to
handle_mm_fault

And so on.

Userspace chooses what happens based on how they configure the PASID
through /dev/ioasid.

Why would a device driver get involved here?

> Eric has sent below series for the page fault reporting for VM with passthru
> device.
> https://lore.kernel.org/kvm/20210223210625.604517-5-eric.au...@redhat.com/

It certainly should not be in vfio pci. Everything using a PASID needs
this infrastructure, VDPA, mdev, PCI, CXL, etc.

Jason
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v14 06/10] iommu: Add a page fault handler

2021-04-01 Thread Jean-Philippe Brucker
Some systems allow devices to handle I/O Page Faults in the core mm. For
example systems implementing the PCIe PRI extension or Arm SMMU stall
model. Infrastructure for reporting these recoverable page faults was
added to the IOMMU core by commit 0c830e6b3282 ("iommu: Introduce device
fault report API"). Add a page fault handler for host SVA.

IOMMU driver can now instantiate several fault workqueues and link them
to IOPF-capable devices. Drivers can choose between a single global
workqueue, one per IOMMU device, one per low-level fault queue, one per
domain, etc.

When it receives a fault event, most commonly in an IRQ handler, the
IOMMU driver reports the fault using iommu_report_device_fault(), which
calls the registered handler. The page fault handler then calls the mm
fault handler, and reports either success or failure with
iommu_page_response(). After the handler succeeds, the hardware retries
the access.

The iopf_param pointer could be embedded into iommu_fault_param. But
putting iopf_param into the iommu_param structure allows us not to care
about ordering between calls to iopf_queue_add_device() and
iommu_register_device_fault_handler().

Tested-by: Lu Baolu 
Reviewed-by: Eric Auger 
Reviewed-by: Jacob Pan 
Reviewed-by: Jonathan Cameron 
Reviewed-by: Lu Baolu 
Signed-off-by: Jean-Philippe Brucker 
---
 drivers/iommu/Makefile|   1 +
 drivers/iommu/iommu-sva-lib.h |  53 
 include/linux/iommu.h |   2 +
 drivers/iommu/io-pgfault.c| 461 ++
 4 files changed, 517 insertions(+)
 create mode 100644 drivers/iommu/io-pgfault.c

diff --git a/drivers/iommu/Makefile b/drivers/iommu/Makefile
index 61bd30cd8369..60fafc23dee6 100644
--- a/drivers/iommu/Makefile
+++ b/drivers/iommu/Makefile
@@ -28,3 +28,4 @@ obj-$(CONFIG_S390_IOMMU) += s390-iommu.o
 obj-$(CONFIG_HYPERV_IOMMU) += hyperv-iommu.o
 obj-$(CONFIG_VIRTIO_IOMMU) += virtio-iommu.o
 obj-$(CONFIG_IOMMU_SVA_LIB) += iommu-sva-lib.o
+obj-$(CONFIG_IOMMU_SVA_LIB) += io-pgfault.o
diff --git a/drivers/iommu/iommu-sva-lib.h b/drivers/iommu/iommu-sva-lib.h
index b40990aef3fd..031155010ca8 100644
--- a/drivers/iommu/iommu-sva-lib.h
+++ b/drivers/iommu/iommu-sva-lib.h
@@ -12,4 +12,57 @@ int iommu_sva_alloc_pasid(struct mm_struct *mm, ioasid_t 
min, ioasid_t max);
 void iommu_sva_free_pasid(struct mm_struct *mm);
 struct mm_struct *iommu_sva_find(ioasid_t pasid);
 
+/* I/O Page fault */
+struct device;
+struct iommu_fault;
+struct iopf_queue;
+
+#ifdef CONFIG_IOMMU_SVA_LIB
+int iommu_queue_iopf(struct iommu_fault *fault, void *cookie);
+
+int iopf_queue_add_device(struct iopf_queue *queue, struct device *dev);
+int iopf_queue_remove_device(struct iopf_queue *queue,
+struct device *dev);
+int iopf_queue_flush_dev(struct device *dev);
+struct iopf_queue *iopf_queue_alloc(const char *name);
+void iopf_queue_free(struct iopf_queue *queue);
+int iopf_queue_discard_partial(struct iopf_queue *queue);
+
+#else /* CONFIG_IOMMU_SVA_LIB */
+static inline int iommu_queue_iopf(struct iommu_fault *fault, void *cookie)
+{
+   return -ENODEV;
+}
+
+static inline int iopf_queue_add_device(struct iopf_queue *queue,
+   struct device *dev)
+{
+   return -ENODEV;
+}
+
+static inline int iopf_queue_remove_device(struct iopf_queue *queue,
+  struct device *dev)
+{
+   return -ENODEV;
+}
+
+static inline int iopf_queue_flush_dev(struct device *dev)
+{
+   return -ENODEV;
+}
+
+static inline struct iopf_queue *iopf_queue_alloc(const char *name)
+{
+   return NULL;
+}
+
+static inline void iopf_queue_free(struct iopf_queue *queue)
+{
+}
+
+static inline int iopf_queue_discard_partial(struct iopf_queue *queue)
+{
+   return -ENODEV;
+}
+#endif /* CONFIG_IOMMU_SVA_LIB */
 #endif /* _IOMMU_SVA_LIB_H */
diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index 45c4eb372f56..86d688c4418f 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -367,6 +367,7 @@ struct iommu_fault_param {
  * struct dev_iommu - Collection of per-device IOMMU data
  *
  * @fault_param: IOMMU detected device fault reporting data
+ * @iopf_param: I/O Page Fault queue and data
  * @fwspec: IOMMU fwspec data
  * @iommu_dev:  IOMMU device this device is linked to
  * @priv:   IOMMU Driver private data
@@ -377,6 +378,7 @@ struct iommu_fault_param {
 struct dev_iommu {
struct mutex lock;
struct iommu_fault_param*fault_param;
+   struct iopf_device_param*iopf_param;
struct iommu_fwspec *fwspec;
struct iommu_device *iommu_dev;
void*priv;
diff --git a/drivers/iommu/io-pgfault.c b/drivers/iommu/io-pgfault.c
new file mode 100644
index ..1df8c1dcae77
--- /dev/null
+++ b/drivers/iommu/io-pgfault.c
@@ -0,0 +1,461 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Handle device page faults
+ *
+ * Copyr

[PATCH v14 10/10] iommu/arm-smmu-v3: Add stall support for platform devices

2021-04-01 Thread Jean-Philippe Brucker
The SMMU provides a Stall model for handling page faults in platform
devices. It is similar to PCIe PRI, but doesn't require devices to have
their own translation cache. Instead, faulting transactions are parked
and the OS is given a chance to fix the page tables and retry the
transaction.

Enable stall for devices that support it (opt-in by firmware). When an
event corresponds to a translation error, call the IOMMU fault handler.
If the fault is recoverable, it will call us back to terminate or
continue the stall.

To use stall device drivers need to enable IOMMU_DEV_FEAT_IOPF, which
initializes the fault queue for the device.

Tested-by: Zhangfei Gao 
Reviewed-by: Eric Auger 
Reviewed-by: Jonathan Cameron 
Signed-off-by: Jean-Philippe Brucker 
---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h   |  43 
 .../iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c   |  59 +-
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c   | 196 +-
 3 files changed, 283 insertions(+), 15 deletions(-)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h 
b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
index 1b463e27bca1..6ce1a7a7e44d 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
@@ -354,6 +354,13 @@
 #define CMDQ_PRI_1_GRPID   GENMASK_ULL(8, 0)
 #define CMDQ_PRI_1_RESPGENMASK_ULL(13, 12)
 
+#define CMDQ_RESUME_0_RESP_TERM0UL
+#define CMDQ_RESUME_0_RESP_RETRY   1UL
+#define CMDQ_RESUME_0_RESP_ABORT   2UL
+#define CMDQ_RESUME_0_RESP GENMASK_ULL(13, 12)
+#define CMDQ_RESUME_0_SID  GENMASK_ULL(63, 32)
+#define CMDQ_RESUME_1_STAG GENMASK_ULL(15, 0)
+
 #define CMDQ_SYNC_0_CS GENMASK_ULL(13, 12)
 #define CMDQ_SYNC_0_CS_NONE0
 #define CMDQ_SYNC_0_CS_IRQ 1
@@ -370,6 +377,25 @@
 
 #define EVTQ_0_ID  GENMASK_ULL(7, 0)
 
+#define EVT_ID_TRANSLATION_FAULT   0x10
+#define EVT_ID_ADDR_SIZE_FAULT 0x11
+#define EVT_ID_ACCESS_FAULT0x12
+#define EVT_ID_PERMISSION_FAULT0x13
+
+#define EVTQ_0_SSV (1UL << 11)
+#define EVTQ_0_SSIDGENMASK_ULL(31, 12)
+#define EVTQ_0_SID GENMASK_ULL(63, 32)
+#define EVTQ_1_STAGGENMASK_ULL(15, 0)
+#define EVTQ_1_STALL   (1UL << 31)
+#define EVTQ_1_PnU (1UL << 33)
+#define EVTQ_1_InD (1UL << 34)
+#define EVTQ_1_RnW (1UL << 35)
+#define EVTQ_1_S2  (1UL << 39)
+#define EVTQ_1_CLASS   GENMASK_ULL(41, 40)
+#define EVTQ_1_TT_READ (1UL << 44)
+#define EVTQ_2_ADDRGENMASK_ULL(63, 0)
+#define EVTQ_3_IPA GENMASK_ULL(51, 12)
+
 /* PRI queue */
 #define PRIQ_ENT_SZ_SHIFT  4
 #define PRIQ_ENT_DWORDS((1 << PRIQ_ENT_SZ_SHIFT) >> 3)
@@ -464,6 +490,13 @@ struct arm_smmu_cmdq_ent {
enum pri_resp   resp;
} pri;
 
+   #define CMDQ_OP_RESUME  0x44
+   struct {
+   u32 sid;
+   u16 stag;
+   u8  resp;
+   } resume;
+
#define CMDQ_OP_CMD_SYNC0x46
struct {
u64 msiaddr;
@@ -522,6 +555,7 @@ struct arm_smmu_cmdq_batch {
 
 struct arm_smmu_evtq {
struct arm_smmu_queue   q;
+   struct iopf_queue   *iopf;
u32 max_stalls;
 };
 
@@ -659,7 +693,9 @@ struct arm_smmu_master {
struct arm_smmu_stream  *streams;
unsigned intnum_streams;
boolats_enabled;
+   boolstall_enabled;
boolsva_enabled;
+   booliopf_enabled;
struct list_headbonds;
unsigned intssid_bits;
 };
@@ -678,6 +714,7 @@ struct arm_smmu_domain {
 
struct io_pgtable_ops   *pgtbl_ops;
boolnon_strict;
+   boolstall_enabled;
atomic_tnr_ats_masters;
 
enum arm_smmu_domain_stage  stage;
@@ -719,6 +756,7 @@ bool arm_smmu_master_sva_supported(struct arm_smmu_master 
*master);
 bool arm_smmu_master_sva_enabled(struct arm_smmu_master *master);
 int arm_smmu_master_enable_sva(struct arm_smmu_master *master);
 int arm_smmu_master_disable_sva(struct arm_smmu_master *master);
+bool arm_smmu_master_iopf_supported(struct arm_smmu_master *master);
 struct iommu_sva *arm_smmu_sva_bind(struct device *dev, struct mm_struct *mm,
v

[PATCH v14 09/10] ACPI/IORT: Enable stall support for platform devices

2021-04-01 Thread Jean-Philippe Brucker
Copy the "Stall supported" bit, that tells whether a named component
supports stall, into the dma-can-stall device property.

Acked-by: Jonathan Cameron 
Signed-off-by: Jean-Philippe Brucker 
---
 drivers/acpi/arm64/iort.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index 3912a1f6058e..0828f70cb782 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -968,13 +968,15 @@ static int iort_pci_iommu_init(struct pci_dev *pdev, u16 
alias, void *data)
 static void iort_named_component_init(struct device *dev,
  struct acpi_iort_node *node)
 {
-   struct property_entry props[2] = {};
+   struct property_entry props[3] = {};
struct acpi_iort_named_component *nc;
 
nc = (struct acpi_iort_named_component *)node->node_data;
props[0] = PROPERTY_ENTRY_U32("pasid-num-bits",
  FIELD_GET(ACPI_IORT_NC_PASID_BITS,
nc->node_flags));
+   if (nc->node_flags & ACPI_IORT_NC_STALL_SUPPORTED)
+   props[1] = PROPERTY_ENTRY_BOOL("dma-can-stall");
 
if (device_add_properties(dev, props))
dev_warn(dev, "Could not add device properties\n");
-- 
2.31.1

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v14 08/10] dt-bindings: document stall property for IOMMU masters

2021-04-01 Thread Jean-Philippe Brucker
On ARM systems, some platform devices behind an IOMMU may support stall,
which is the ability to recover from page faults. Let the firmware tell us
when a device supports stall.

Reviewed-by: Eric Auger 
Reviewed-by: Rob Herring 
Signed-off-by: Jean-Philippe Brucker 
---
 .../devicetree/bindings/iommu/iommu.txt| 18 ++
 1 file changed, 18 insertions(+)

diff --git a/Documentation/devicetree/bindings/iommu/iommu.txt 
b/Documentation/devicetree/bindings/iommu/iommu.txt
index 3c36334e4f94..26ba9e530f13 100644
--- a/Documentation/devicetree/bindings/iommu/iommu.txt
+++ b/Documentation/devicetree/bindings/iommu/iommu.txt
@@ -92,6 +92,24 @@ Optional properties:
   tagging DMA transactions with an address space identifier. By default,
   this is 0, which means that the device only has one address space.
 
+- dma-can-stall: When present, the master can wait for a transaction to
+  complete for an indefinite amount of time. Upon translation fault some
+  IOMMUs, instead of aborting the translation immediately, may first
+  notify the driver and keep the transaction in flight. This allows the OS
+  to inspect the fault and, for example, make physical pages resident
+  before updating the mappings and completing the transaction. Such IOMMU
+  accepts a limited number of simultaneous stalled transactions before
+  having to either put back-pressure on the master, or abort new faulting
+  transactions.
+
+  Firmware has to opt-in stalling, because most buses and masters don't
+  support it. In particular it isn't compatible with PCI, where
+  transactions have to complete before a time limit. More generally it
+  won't work in systems and masters that haven't been designed for
+  stalling. For example the OS, in order to handle a stalled transaction,
+  may attempt to retrieve pages from secondary storage in a stalled
+  domain, leading to a deadlock.
+
 
 Notes:
 ==
-- 
2.31.1

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v14 07/10] iommu/arm-smmu-v3: Maintain a SID->device structure

2021-04-01 Thread Jean-Philippe Brucker
When handling faults from the event or PRI queue, we need to find the
struct device associated with a SID. Add a rb_tree to keep track of
SIDs.

Acked-by: Jonathan Cameron 
Reviewed-by: Eric Auger 
Reviewed-by: Keqian Zhu 
Signed-off-by: Jean-Philippe Brucker 
---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h |  13 +-
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 158 
 2 files changed, 141 insertions(+), 30 deletions(-)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h 
b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
index 230b6f6b3901..1b463e27bca1 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
@@ -639,6 +639,15 @@ struct arm_smmu_device {
 
/* IOMMU core code handle */
struct iommu_device iommu;
+
+   struct rb_root  streams;
+   struct mutexstreams_mutex;
+};
+
+struct arm_smmu_stream {
+   u32 id;
+   struct arm_smmu_master  *master;
+   struct rb_node  node;
 };
 
 /* SMMU private data for each master */
@@ -647,8 +656,8 @@ struct arm_smmu_master {
struct device   *dev;
struct arm_smmu_domain  *domain;
struct list_headdomain_head;
-   u32 *sids;
-   unsigned intnum_sids;
+   struct arm_smmu_stream  *streams;
+   unsigned intnum_streams;
boolats_enabled;
boolsva_enabled;
struct list_headbonds;
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c 
b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index bd77495023c8..8279291660b2 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -909,8 +909,8 @@ static void arm_smmu_sync_cd(struct arm_smmu_domain 
*smmu_domain,
 
spin_lock_irqsave(&smmu_domain->devices_lock, flags);
list_for_each_entry(master, &smmu_domain->devices, domain_head) {
-   for (i = 0; i < master->num_sids; i++) {
-   cmd.cfgi.sid = master->sids[i];
+   for (i = 0; i < master->num_streams; i++) {
+   cmd.cfgi.sid = master->streams[i].id;
arm_smmu_cmdq_batch_add(smmu, &cmds, &cmd);
}
}
@@ -1355,6 +1355,29 @@ static int arm_smmu_init_l2_strtab(struct 
arm_smmu_device *smmu, u32 sid)
return 0;
 }
 
+__maybe_unused
+static struct arm_smmu_master *
+arm_smmu_find_master(struct arm_smmu_device *smmu, u32 sid)
+{
+   struct rb_node *node;
+   struct arm_smmu_stream *stream;
+
+   lockdep_assert_held(&smmu->streams_mutex);
+
+   node = smmu->streams.rb_node;
+   while (node) {
+   stream = rb_entry(node, struct arm_smmu_stream, node);
+   if (stream->id < sid)
+   node = node->rb_right;
+   else if (stream->id > sid)
+   node = node->rb_left;
+   else
+   return stream->master;
+   }
+
+   return NULL;
+}
+
 /* IRQ and event handlers */
 static irqreturn_t arm_smmu_evtq_thread(int irq, void *dev)
 {
@@ -1588,8 +1611,8 @@ static int arm_smmu_atc_inv_master(struct arm_smmu_master 
*master)
 
arm_smmu_atc_inv_to_cmd(0, 0, 0, &cmd);
 
-   for (i = 0; i < master->num_sids; i++) {
-   cmd.atc.sid = master->sids[i];
+   for (i = 0; i < master->num_streams; i++) {
+   cmd.atc.sid = master->streams[i].id;
arm_smmu_cmdq_issue_cmd(master->smmu, &cmd);
}
 
@@ -1632,8 +1655,8 @@ int arm_smmu_atc_inv_domain(struct arm_smmu_domain 
*smmu_domain, int ssid,
if (!master->ats_enabled)
continue;
 
-   for (i = 0; i < master->num_sids; i++) {
-   cmd.atc.sid = master->sids[i];
+   for (i = 0; i < master->num_streams; i++) {
+   cmd.atc.sid = master->streams[i].id;
arm_smmu_cmdq_batch_add(smmu_domain->smmu, &cmds, &cmd);
}
}
@@ -2065,13 +2088,13 @@ static void arm_smmu_install_ste_for_dev(struct 
arm_smmu_master *master)
int i, j;
struct arm_smmu_device *smmu = master->smmu;
 
-   for (i = 0; i < master->num_sids; ++i) {
-   u32 sid = master->sids[i];
+   for (i = 0; i < master->num_streams; ++i) {
+   u32 sid = master->streams[i].id;
__le64 *step = arm_smmu_get_step_for_sid(smmu, sid);
 
/* Bridged PCI devices may end up with duplicated IDs */
for (j = 0; j < i; j++)
-   if (master->sids[j] == sid)
+   if (master->streams[j].id == sid)
break;

[PATCH v14 04/10] iommu/vt-d: Support IOMMU_DEV_FEAT_IOPF

2021-04-01 Thread Jean-Philippe Brucker
Allow drivers to query and enable IOMMU_DEV_FEAT_IOPF, which amounts to
checking whether PRI is enabled.

Reviewed-by: Lu Baolu 
Signed-off-by: Jean-Philippe Brucker 
---
Cc: David Woodhouse 
Cc: Lu Baolu 
---
 drivers/iommu/intel/iommu.c | 11 ---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
index ee0932307d64..c5c5fd444779 100644
--- a/drivers/iommu/intel/iommu.c
+++ b/drivers/iommu/intel/iommu.c
@@ -5343,6 +5343,8 @@ static int siov_find_pci_dvsec(struct pci_dev *pdev)
 static bool
 intel_iommu_dev_has_feat(struct device *dev, enum iommu_dev_features feat)
 {
+   struct device_domain_info *info = get_domain_info(dev);
+
if (feat == IOMMU_DEV_FEAT_AUX) {
int ret;
 
@@ -5357,13 +5359,13 @@ intel_iommu_dev_has_feat(struct device *dev, enum 
iommu_dev_features feat)
return !!siov_find_pci_dvsec(to_pci_dev(dev));
}
 
-   if (feat == IOMMU_DEV_FEAT_SVA) {
-   struct device_domain_info *info = get_domain_info(dev);
+   if (feat == IOMMU_DEV_FEAT_IOPF)
+   return info && info->pri_supported;
 
+   if (feat == IOMMU_DEV_FEAT_SVA)
return info && (info->iommu->flags & VTD_FLAG_SVM_CAPABLE) &&
info->pasid_supported && info->pri_supported &&
info->ats_supported;
-   }
 
return false;
 }
@@ -5374,6 +5376,9 @@ intel_iommu_dev_enable_feat(struct device *dev, enum 
iommu_dev_features feat)
if (feat == IOMMU_DEV_FEAT_AUX)
return intel_iommu_enable_auxd(dev);
 
+   if (feat == IOMMU_DEV_FEAT_IOPF)
+   return intel_iommu_dev_has_feat(dev, feat) ? 0 : -ENODEV;
+
if (feat == IOMMU_DEV_FEAT_SVA) {
struct device_domain_info *info = get_domain_info(dev);
 
-- 
2.31.1

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v14 03/10] iommu: Separate IOMMU_DEV_FEAT_IOPF from IOMMU_DEV_FEAT_SVA

2021-04-01 Thread Jean-Philippe Brucker
Some devices manage I/O Page Faults (IOPF) themselves instead of relying
on PCIe PRI or Arm SMMU stall. Allow their drivers to enable SVA without
mandating IOMMU-managed IOPF. The other device drivers now need to first
enable IOMMU_DEV_FEAT_IOPF before enabling IOMMU_DEV_FEAT_SVA. Enabling
IOMMU_DEV_FEAT_IOPF on its own doesn't have any effect visible to the
device driver, it is used in combination with other features.

Reviewed-by: Eric Auger 
Reviewed-by: Lu Baolu 
Signed-off-by: Jean-Philippe Brucker 
---
Cc: Arnd Bergmann 
Cc: David Woodhouse 
Cc: Greg Kroah-Hartman 
Cc: Joerg Roedel 
Cc: Lu Baolu 
Cc: Will Deacon 
Cc: Zhangfei Gao 
Cc: Zhou Wang 
---
 include/linux/iommu.h | 20 +---
 1 file changed, 17 insertions(+), 3 deletions(-)

diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index 16ce75693d83..45c4eb372f56 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -156,10 +156,24 @@ struct iommu_resv_region {
enum iommu_resv_typetype;
 };
 
-/* Per device IOMMU features */
+/**
+ * enum iommu_dev_features - Per device IOMMU features
+ * @IOMMU_DEV_FEAT_AUX: Auxiliary domain feature
+ * @IOMMU_DEV_FEAT_SVA: Shared Virtual Addresses
+ * @IOMMU_DEV_FEAT_IOPF: I/O Page Faults such as PRI or Stall. Generally
+ *  enabling %IOMMU_DEV_FEAT_SVA requires
+ *  %IOMMU_DEV_FEAT_IOPF, but some devices manage I/O Page
+ *  Faults themselves instead of relying on the IOMMU. When
+ *  supported, this feature must be enabled before and
+ *  disabled after %IOMMU_DEV_FEAT_SVA.
+ *
+ * Device drivers query whether a feature is supported using
+ * iommu_dev_has_feature(), and enable it using iommu_dev_enable_feature().
+ */
 enum iommu_dev_features {
-   IOMMU_DEV_FEAT_AUX, /* Aux-domain feature */
-   IOMMU_DEV_FEAT_SVA, /* Shared Virtual Addresses */
+   IOMMU_DEV_FEAT_AUX,
+   IOMMU_DEV_FEAT_SVA,
+   IOMMU_DEV_FEAT_IOPF,
 };
 
 #define IOMMU_PASID_INVALID(-1U)
-- 
2.31.1

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v14 05/10] uacce: Enable IOMMU_DEV_FEAT_IOPF

2021-04-01 Thread Jean-Philippe Brucker
The IOPF (I/O Page Fault) feature is now enabled independently from the
SVA feature, because some IOPF implementations are device-specific and
do not require IOMMU support for PCIe PRI or Arm SMMU stall.

Enable IOPF unconditionally when enabling SVA for now. In the future, if
a device driver implementing a uacce interface doesn't need IOPF
support, it will need to tell the uacce module, for example with a new
flag.

Acked-by: Zhangfei Gao 
Signed-off-by: Jean-Philippe Brucker 
---
Cc: Arnd Bergmann 
Cc: Greg Kroah-Hartman 
Cc: Zhangfei Gao 
Cc: Zhou Wang 
---
 drivers/misc/uacce/uacce.c | 39 +-
 1 file changed, 30 insertions(+), 9 deletions(-)

diff --git a/drivers/misc/uacce/uacce.c b/drivers/misc/uacce/uacce.c
index d07af4edfcac..6db7a98486ec 100644
--- a/drivers/misc/uacce/uacce.c
+++ b/drivers/misc/uacce/uacce.c
@@ -385,6 +385,33 @@ static void uacce_release(struct device *dev)
kfree(uacce);
 }
 
+static unsigned int uacce_enable_sva(struct device *parent, unsigned int flags)
+{
+   if (!(flags & UACCE_DEV_SVA))
+   return flags;
+
+   flags &= ~UACCE_DEV_SVA;
+
+   if (iommu_dev_enable_feature(parent, IOMMU_DEV_FEAT_IOPF))
+   return flags;
+
+   if (iommu_dev_enable_feature(parent, IOMMU_DEV_FEAT_SVA)) {
+   iommu_dev_disable_feature(parent, IOMMU_DEV_FEAT_IOPF);
+   return flags;
+   }
+
+   return flags | UACCE_DEV_SVA;
+}
+
+static void uacce_disable_sva(struct uacce_device *uacce)
+{
+   if (!(uacce->flags & UACCE_DEV_SVA))
+   return;
+
+   iommu_dev_disable_feature(uacce->parent, IOMMU_DEV_FEAT_SVA);
+   iommu_dev_disable_feature(uacce->parent, IOMMU_DEV_FEAT_IOPF);
+}
+
 /**
  * uacce_alloc() - alloc an accelerator
  * @parent: pointer of uacce parent device
@@ -404,11 +431,7 @@ struct uacce_device *uacce_alloc(struct device *parent,
if (!uacce)
return ERR_PTR(-ENOMEM);
 
-   if (flags & UACCE_DEV_SVA) {
-   ret = iommu_dev_enable_feature(parent, IOMMU_DEV_FEAT_SVA);
-   if (ret)
-   flags &= ~UACCE_DEV_SVA;
-   }
+   flags = uacce_enable_sva(parent, flags);
 
uacce->parent = parent;
uacce->flags = flags;
@@ -432,8 +455,7 @@ struct uacce_device *uacce_alloc(struct device *parent,
return uacce;
 
 err_with_uacce:
-   if (flags & UACCE_DEV_SVA)
-   iommu_dev_disable_feature(uacce->parent, IOMMU_DEV_FEAT_SVA);
+   uacce_disable_sva(uacce);
kfree(uacce);
return ERR_PTR(ret);
 }
@@ -487,8 +509,7 @@ void uacce_remove(struct uacce_device *uacce)
mutex_unlock(&uacce->queues_lock);
 
/* disable sva now since no opened queues */
-   if (uacce->flags & UACCE_DEV_SVA)
-   iommu_dev_disable_feature(uacce->parent, IOMMU_DEV_FEAT_SVA);
+   uacce_disable_sva(uacce);
 
if (uacce->cdev)
cdev_device_del(uacce->cdev, &uacce->dev);
-- 
2.31.1

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v14 01/10] iommu: Fix comment for struct iommu_fwspec

2021-04-01 Thread Jean-Philippe Brucker
Commit 986d5ecc5699 ("iommu: Move fwspec->iommu_priv to struct
dev_iommu") removed iommu_priv from fwspec and commit 5702ee24182f
("ACPI/IORT: Check ATS capability in root complex nodes") added @flags.
Update the struct doc.

Acked-by: Jonathan Cameron 
Acked-by: Will Deacon 
Signed-off-by: Jean-Philippe Brucker 
---
 include/linux/iommu.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index 5e7fe519430a..1d422bf722a1 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -571,7 +571,7 @@ struct iommu_group *fsl_mc_device_group(struct device *dev);
  * struct iommu_fwspec - per-device IOMMU instance data
  * @ops: ops for this device's IOMMU
  * @iommu_fwnode: firmware handle for this device's IOMMU
- * @iommu_priv: IOMMU driver private data for this device
+ * @flags: IOMMU_FWSPEC_* flags
  * @num_pasid_bits: number of PASID bits supported by this device
  * @num_ids: number of associated device IDs
  * @ids: IDs which this device may present to the IOMMU
-- 
2.31.1

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v14 02/10] iommu/arm-smmu-v3: Use device properties for pasid-num-bits

2021-04-01 Thread Jean-Philippe Brucker
The pasid-num-bits property shouldn't need a dedicated fwspec field,
it's a job for device properties. Add properties for IORT, and access
the number of PASID bits using device_property_read_u32().

Suggested-by: Robin Murphy 
Acked-by: Jonathan Cameron 
Acked-by: Will Deacon 
Reviewed-by: Eric Auger 
Signed-off-by: Jean-Philippe Brucker 
---
 include/linux/iommu.h   |  2 --
 drivers/acpi/arm64/iort.c   | 13 +++--
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c |  3 ++-
 drivers/iommu/of_iommu.c|  5 -
 4 files changed, 9 insertions(+), 14 deletions(-)

diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index 1d422bf722a1..16ce75693d83 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -572,7 +572,6 @@ struct iommu_group *fsl_mc_device_group(struct device *dev);
  * @ops: ops for this device's IOMMU
  * @iommu_fwnode: firmware handle for this device's IOMMU
  * @flags: IOMMU_FWSPEC_* flags
- * @num_pasid_bits: number of PASID bits supported by this device
  * @num_ids: number of associated device IDs
  * @ids: IDs which this device may present to the IOMMU
  */
@@ -580,7 +579,6 @@ struct iommu_fwspec {
const struct iommu_ops  *ops;
struct fwnode_handle*iommu_fwnode;
u32 flags;
-   u32 num_pasid_bits;
unsigned intnum_ids;
u32 ids[];
 };
diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index 2494138a6905..3912a1f6058e 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -968,15 +968,16 @@ static int iort_pci_iommu_init(struct pci_dev *pdev, u16 
alias, void *data)
 static void iort_named_component_init(struct device *dev,
  struct acpi_iort_node *node)
 {
+   struct property_entry props[2] = {};
struct acpi_iort_named_component *nc;
-   struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
-
-   if (!fwspec)
-   return;
 
nc = (struct acpi_iort_named_component *)node->node_data;
-   fwspec->num_pasid_bits = FIELD_GET(ACPI_IORT_NC_PASID_BITS,
-  nc->node_flags);
+   props[0] = PROPERTY_ENTRY_U32("pasid-num-bits",
+ FIELD_GET(ACPI_IORT_NC_PASID_BITS,
+   nc->node_flags));
+
+   if (device_add_properties(dev, props))
+   dev_warn(dev, "Could not add device properties\n");
 }
 
 static int iort_nc_iommu_map(struct device *dev, struct acpi_iort_node *node)
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c 
b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index 941ba5484731..bd77495023c8 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -2395,7 +2395,8 @@ static struct iommu_device *arm_smmu_probe_device(struct 
device *dev)
}
}
 
-   master->ssid_bits = min(smmu->ssid_bits, fwspec->num_pasid_bits);
+   device_property_read_u32(dev, "pasid-num-bits", &master->ssid_bits);
+   master->ssid_bits = min(smmu->ssid_bits, master->ssid_bits);
 
/*
 * Note that PASID must be enabled before, and disabled after ATS:
diff --git a/drivers/iommu/of_iommu.c b/drivers/iommu/of_iommu.c
index e505b9130a1c..a9d2df001149 100644
--- a/drivers/iommu/of_iommu.c
+++ b/drivers/iommu/of_iommu.c
@@ -210,11 +210,6 @@ const struct iommu_ops *of_iommu_configure(struct device 
*dev,
 of_pci_iommu_init, &info);
} else {
err = of_iommu_configure_device(master_np, dev, id);
-
-   fwspec = dev_iommu_fwspec_get(dev);
-   if (!err && fwspec)
-   of_property_read_u32(master_np, "pasid-num-bits",
-&fwspec->num_pasid_bits);
}
 
/*
-- 
2.31.1

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v14 00/10] iommu: I/O page faults for SMMUv3

2021-04-01 Thread Jean-Philippe Brucker
Add stall support to the SMMUv3 driver, along with a common I/O Page
Fault handler.

Since [v13] I added review and ack tags (Thanks!), and a lockdep_assert.
It would be good to have all of it in v5.13, since patch 10 introduces
the first user for the IOPF interface from patch 6.  But if that's not
possible, please pick patches 1-6 so the Vt-d driver can start using
them.

[v13] 
https://lore.kernel.org/linux-iommu/20210302092644.2553014-1-jean-phili...@linaro.org/

Jean-Philippe Brucker (10):
  iommu: Fix comment for struct iommu_fwspec
  iommu/arm-smmu-v3: Use device properties for pasid-num-bits
  iommu: Separate IOMMU_DEV_FEAT_IOPF from IOMMU_DEV_FEAT_SVA
  iommu/vt-d: Support IOMMU_DEV_FEAT_IOPF
  uacce: Enable IOMMU_DEV_FEAT_IOPF
  iommu: Add a page fault handler
  iommu/arm-smmu-v3: Maintain a SID->device structure
  dt-bindings: document stall property for IOMMU masters
  ACPI/IORT: Enable stall support for platform devices
  iommu/arm-smmu-v3: Add stall support for platform devices

 drivers/iommu/Makefile|   1 +
 .../devicetree/bindings/iommu/iommu.txt   |  18 +
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h   |  56 ++-
 drivers/iommu/iommu-sva-lib.h |  53 ++
 include/linux/iommu.h |  26 +-
 drivers/acpi/arm64/iort.c |  15 +-
 .../iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c   |  59 ++-
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c   | 355 --
 drivers/iommu/intel/iommu.c   |  11 +-
 drivers/iommu/io-pgfault.c| 461 ++
 drivers/iommu/of_iommu.c  |   5 -
 drivers/misc/uacce/uacce.c|  39 +-
 12 files changed, 1025 insertions(+), 74 deletions(-)
 create mode 100644 drivers/iommu/io-pgfault.c

-- 
2.31.1

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [RFC PATCH 3/5] iommu: Add support for the unmap_pages IOMMU callback

2021-04-01 Thread Robin Murphy

On 2021-03-31 04:00, Isaac J. Manjarres wrote:

The IOMMU framework currently unmaps memory one page block at a time,
per the page block sizes that are supported by the IOMMU hardware.
Now that IOMMU drivers can supply a callback for unmapping multiple
in one call, add support in the IOMMU framework to calculate how many
page mappings of the same size can be unmapped in one shot, and invoke the
IOMMU driver's unmap_pages callback if it has one. Otherwise, the
existing behavior will be used.

Signed-off-by: Isaac J. Manjarres 
Suggested-by: Will Deacon 
---
  drivers/iommu/iommu.c | 44 +--
  1 file changed, 38 insertions(+), 6 deletions(-)

diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index d0b0a15dba84..dc4295f6bc7f 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -2356,8 +2356,8 @@ phys_addr_t iommu_iova_to_phys(struct iommu_domain 
*domain, dma_addr_t iova)
  }
  EXPORT_SYMBOL_GPL(iommu_iova_to_phys);
  
-static size_t iommu_pgsize(struct iommu_domain *domain,

-  unsigned long addr_merge, size_t size)
+static size_t __iommu_pgsize(struct iommu_domain *domain,
+unsigned long addr_merge, size_t size)
  {
unsigned int pgsize_idx;
size_t pgsize;
@@ -2388,6 +2388,24 @@ static size_t iommu_pgsize(struct iommu_domain *domain,
return pgsize;
  }
  
+static size_t iommu_pgsize(struct iommu_domain *domain,

+  unsigned long addr_merge, size_t size,
+  size_t *pgcount)
+{
+   size_t pgsize = __iommu_pgsize(domain, addr_merge, size);
+   size_t pgs = 0;
+
+   do {
+   pgs++;
+   size -= pgsize;
+   addr_merge += pgsize;
+   } while (size && __iommu_pgsize(domain, addr_merge, size) == pgsize);


This looks horrifically inefficient. As part of calculating the best 
current page size it should then be pretty trivial to calculate "(size & 
next_pgsize_up - 1) >> pgsize_idx" for the number of current-size pages 
up to the next-better-size boundary (with next_pgsize_up being 0 if 
pgsize is already the largest possible for the relative alignment of 
physical and virtual address). A loop is just... yuck :(



+
+   *pgcount = pgs;
+
+   return pgsize;
+}
+
  static int __iommu_map(struct iommu_domain *domain, unsigned long iova,
   phys_addr_t paddr, size_t size, int prot, gfp_t gfp)
  {
@@ -2422,7 +2440,7 @@ static int __iommu_map(struct iommu_domain *domain, 
unsigned long iova,
pr_debug("map: iova 0x%lx pa %pa size 0x%zx\n", iova, &paddr, size);
  
  	while (size) {

-   size_t pgsize = iommu_pgsize(domain, iova | paddr, size);
+   size_t pgsize = __iommu_pgsize(domain, iova | paddr, size);
  
  		pr_debug("mapping: iova 0x%lx pa %pa pgsize 0x%zx\n",

 iova, &paddr, pgsize);
@@ -2473,6 +2491,21 @@ int iommu_map_atomic(struct iommu_domain *domain, 
unsigned long iova,
  }
  EXPORT_SYMBOL_GPL(iommu_map_atomic);
  
+static size_t __iommu_unmap_pages(struct iommu_domain *domain, unsigned long iova,

+ size_t size, struct iommu_iotlb_gather 
*iotlb_gather)
+{
+   const struct iommu_ops *ops = domain->ops;
+   size_t pgsize, pgcount;
+
+   if (ops->unmap_pages) {
+   pgsize = iommu_pgsize(domain, iova, size, &pgcount);
+   return ops->unmap_pages(domain, iova, pgsize, pgcount, 
iotlb_gather);
+   }
+
+   pgsize = __iommu_pgsize(domain, iova, size);
+   return ops->unmap(domain, iova, pgsize, iotlb_gather);
+}
+
  static size_t __iommu_unmap(struct iommu_domain *domain,
unsigned long iova, size_t size,
struct iommu_iotlb_gather *iotlb_gather)
@@ -2510,9 +2543,8 @@ static size_t __iommu_unmap(struct iommu_domain *domain,
 * or we hit an area that isn't mapped.
 */
while (unmapped < size) {
-   size_t pgsize = iommu_pgsize(domain, iova, size - unmapped);
-
-   unmapped_page = ops->unmap(domain, iova, pgsize, iotlb_gather);
+   unmapped_page = __iommu_unmap_pages(domain, iova, size - 
unmapped,
+   iotlb_gather);


I think it would make more sense to restructure the basic function 
around handling a page range, then just have a little inner loop to 
iterate over the individual pages if the driver doesn't provide the new 
callback.


Robin.


if (!unmapped_page)
break;
  


___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [RFC PATCH 0/5] Optimization for unmapping iommu mapped buffers

2021-04-01 Thread Robin Murphy

On 2021-03-31 04:00, Isaac J. Manjarres wrote:

When unmapping a buffer from an IOMMU domain, the IOMMU framework unmaps
the buffer at a granule of the largest page size that is supported by
the IOMMU hardware and fits within the buffer. For every block that
is unmapped, the IOMMU framework will call into the IOMMU driver, and
then the io-pgtable framework to walk the page tables to find the entry
that corresponds to the IOVA, and then unmaps the entry.

This can be suboptimal in scenarios where a buffer or a piece of a
buffer can be split into several contiguous page blocks of the same size.
For example, consider an IOMMU that supports 4 KB page blocks, 2 MB page
blocks, and 1 GB page blocks, and a buffer that is 4 MB in size is being
unmapped at IOVA 0. The current call-flow will result in 4 indirect calls,
and 2 page table walks, to unmap 2 entries that are next to each other in
the page-tables, when both entries could have been unmapped in one shot
by clearing both page table entries in the same call.


s/unmap/map/ and s/clear/set/ and those two paragraphs are still just as 
valid. I'd say If it's worth doing anything at all then it's worth doing 
more than just half the job ;)



These patches implement a callback called unmap_pages to the io-pgtable
code and IOMMU drivers which unmaps an IOVA range that consists of a
number of pages of the same page size that is supported by the IOMMU
hardware, and allows for clearing multiple entries in the same set of
indirect calls. The reason for introducing unmap_pages is to give
other IOMMU drivers/io-pgtable formats time to change to using the new
unmap_pages callback, so that the transition to using this approach can be
done piecemeal.

The same optimization is applicable for mapping buffers, however, the
error handling in the io-pgtable layer couldn't be handled cleanly, as we
would need to invoke iommu_unmap to unmap the parts of the buffer that
were mapped, and then do any TLB maintenance. However, that seemed like a
layering violation.


Why couldn't it just return the partial mapping and let the caller roll 
it back?


Note that having a weird asymmetric interface was how things started out 
way back when - see bd13969b9524 ("iommu: Split iommu_unmaps") for context.



Any feedback is very much appreciated.


Do you have any real-world performance figures? I proposed this as an 
approach because it was clear it could give *some* benefit for 
relatively low impact, but I'm curious to find out exactly how much, and 
in particular whether it appears to leave anything on the table vs. 
punting the entire operation down into the drivers.


Robin.


Thanks,
Isaac

Isaac J. Manjarres (5):
   iommu/io-pgtable: Introduce unmap_pages() as a page table op
   iommu: Add an unmap_pages() op for IOMMU drivers
   iommu: Add support for the unmap_pages IOMMU callback
   iommu/io-pgtable-arm: Implement arm_lpae_unmap_pages()
   iommu/arm-smmu: Implement the unmap_pages IOMMU driver callback

  drivers/iommu/arm/arm-smmu/arm-smmu.c |  19 +
  drivers/iommu/io-pgtable-arm.c| 114 +-
  drivers/iommu/iommu.c |  44 --
  include/linux/io-pgtable.h|   4 +
  include/linux/iommu.h |   4 +
  5 files changed, 159 insertions(+), 26 deletions(-)


___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


RE: [PATCH V4 05/18] iommu/ioasid: Redefine IOASID set and allocation APIs

2021-04-01 Thread Liu, Yi L
> From: Jason Gunthorpe 
> Sent: Thursday, April 1, 2021 9:43 PM
> 
> On Thu, Apr 01, 2021 at 01:38:46PM +, Liu, Yi L wrote:
> > > From: Jean-Philippe Brucker 
> > > Sent: Thursday, April 1, 2021 8:05 PM
> > [...]
> > >
> > > Also wondering about:
> > >
> > > * Querying IOMMU nesting capabilities before binding page tables
> (which
> > >   page table formats are supported?). We were planning to have a VFIO
> cap,
> > >   but I'm guessing we need to go back to the sysfs solution?
> >
> > I think it can also be with /dev/ioasid.
> 
> Sure, anything to do with page table formats and setting page tables
> should go through ioasid.
> 
> > > * Invalidation, probably an ioasid_fd ioctl?
> >
> > yeah, if we are doing bind/unbind_pagtable via ioasid_fd, then yes,
> > invalidation should go this way as well. This is why I worried it may
> > fail to meet the requirement from you and Eric.
> 
> Yes, all manipulation of page tables, including removing memory ranges, or
> setting memory ranges to trigger a page fault behavior should go
> through here.
> 
> > > * Page faults, page response. From and to devices, and don't necessarily
> > >   have a PASID. But needed by vdpa as well, so that's also going through
> > >   /dev/ioasid?
> >
> > page faults should still be per-device, but the fault event fd may be stored
> > in /dev/ioasid. page response would be in /dev/ioasid just like 
> > invalidation.
> 
> Here you mean non-SVA page faults that are delegated to userspace to
> handle?

no, just SVA page faults. otherwise, no need to let userspace handle.

> 
> Why would that be per-device?
>
> Can you show the flow you imagine?

DMA page faults are delivered to root-complex via page request message and
it is per-device according to PCIe spec. Page request handling flow is:

1) iommu driver receives a page request from device
2) iommu driver parses the page request message. Get the RID,PASID, faulted
   page and requested permissions etc.
3) iommu driver triggers fault handler registered by device driver with
   iommu_report_device_fault()
4) device driver's fault handler signals an event FD to notify userspace to
   fetch the information about the page fault. If it's VM case, inject the
   page fault to VM and let guest to solve it.

Eric has sent below series for the page fault reporting for VM with passthru
device.
https://lore.kernel.org/kvm/20210223210625.604517-5-eric.au...@redhat.com/

Regards,
Yi Liu

> Jason
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v2 2/2] iommu: Streamline registration interface

2021-04-01 Thread Robin Murphy
Rather than have separate opaque setter functions that are easy to
overlook and lead to repetitive boilerplate in drivers, let's pass the
relevant initialisation parameters directly to iommu_device_register().

Acked-by: Will Deacon 
Signed-off-by: Robin Murphy 

---

v2: Add some kerneldoc and an attempt to sanity-check modules

FWIW I'm hoping to fold the sysfs registration in here too, such that
@hwdev can also represent the sysfs parent, but I haven't yet figured
out why virtio-iommu is the odd one out in that regard.
---
 drivers/iommu/amd/init.c|  3 +--
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c |  5 +---
 drivers/iommu/arm/arm-smmu/arm-smmu.c   |  5 +---
 drivers/iommu/arm/arm-smmu/qcom_iommu.c |  5 +---
 drivers/iommu/exynos-iommu.c|  5 +---
 drivers/iommu/fsl_pamu_domain.c |  4 +--
 drivers/iommu/intel/dmar.c  |  4 +--
 drivers/iommu/intel/iommu.c |  3 +--
 drivers/iommu/iommu.c   | 19 -
 drivers/iommu/ipmmu-vmsa.c  |  6 +
 drivers/iommu/msm_iommu.c   |  5 +---
 drivers/iommu/mtk_iommu.c   |  5 +---
 drivers/iommu/mtk_iommu_v1.c|  4 +--
 drivers/iommu/omap-iommu.c  |  5 +---
 drivers/iommu/rockchip-iommu.c  |  5 +---
 drivers/iommu/s390-iommu.c  |  4 +--
 drivers/iommu/sprd-iommu.c  |  5 +---
 drivers/iommu/sun50i-iommu.c|  5 +---
 drivers/iommu/tegra-gart.c  |  5 +---
 drivers/iommu/tegra-smmu.c  |  5 +---
 drivers/iommu/virtio-iommu.c|  5 +---
 include/linux/iommu.h   | 30 +
 22 files changed, 44 insertions(+), 98 deletions(-)

diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c
index 321f5906e6ed..e1ef922d9f8f 100644
--- a/drivers/iommu/amd/init.c
+++ b/drivers/iommu/amd/init.c
@@ -1935,8 +1935,7 @@ static int __init iommu_init_pci(struct amd_iommu *iommu)
 
iommu_device_sysfs_add(&iommu->iommu, &iommu->dev->dev,
   amd_iommu_groups, "ivhd%d", iommu->index);
-   iommu_device_set_ops(&iommu->iommu, &amd_iommu_ops);
-   iommu_device_register(&iommu->iommu);
+   iommu_device_register(&iommu->iommu, &amd_iommu_ops, NULL);
 
return pci_enable_device(iommu->dev);
 }
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c 
b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index b82000519af6..ecc6cfe3ae90 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -3621,10 +3621,7 @@ static int arm_smmu_device_probe(struct platform_device 
*pdev)
if (ret)
return ret;
 
-   iommu_device_set_ops(&smmu->iommu, &arm_smmu_ops);
-   iommu_device_set_fwnode(&smmu->iommu, dev->fwnode);
-
-   ret = iommu_device_register(&smmu->iommu);
+   ret = iommu_device_register(&smmu->iommu, &arm_smmu_ops, dev);
if (ret) {
dev_err(dev, "Failed to register iommu\n");
return ret;
diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu.c 
b/drivers/iommu/arm/arm-smmu/arm-smmu.c
index 11ca963c4b93..0a697cb0d2f8 100644
--- a/drivers/iommu/arm/arm-smmu/arm-smmu.c
+++ b/drivers/iommu/arm/arm-smmu/arm-smmu.c
@@ -,10 +,7 @@ static int arm_smmu_device_probe(struct platform_device 
*pdev)
return err;
}
 
-   iommu_device_set_ops(&smmu->iommu, &arm_smmu_ops);
-   iommu_device_set_fwnode(&smmu->iommu, dev->fwnode);
-
-   err = iommu_device_register(&smmu->iommu);
+   err = iommu_device_register(&smmu->iommu, &arm_smmu_ops, dev);
if (err) {
dev_err(dev, "Failed to register iommu\n");
return err;
diff --git a/drivers/iommu/arm/arm-smmu/qcom_iommu.c 
b/drivers/iommu/arm/arm-smmu/qcom_iommu.c
index 7f280c8d5c53..4294abe389b2 100644
--- a/drivers/iommu/arm/arm-smmu/qcom_iommu.c
+++ b/drivers/iommu/arm/arm-smmu/qcom_iommu.c
@@ -847,10 +847,7 @@ static int qcom_iommu_device_probe(struct platform_device 
*pdev)
return ret;
}
 
-   iommu_device_set_ops(&qcom_iommu->iommu, &qcom_iommu_ops);
-   iommu_device_set_fwnode(&qcom_iommu->iommu, dev->fwnode);
-
-   ret = iommu_device_register(&qcom_iommu->iommu);
+   ret = iommu_device_register(&qcom_iommu->iommu, &qcom_iommu_ops, dev);
if (ret) {
dev_err(dev, "Failed to register iommu\n");
return ret;
diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
index de324b4eedfe..f887c3e111c1 100644
--- a/drivers/iommu/exynos-iommu.c
+++ b/drivers/iommu/exynos-iommu.c
@@ -630,10 +630,7 @@ static int exynos_sysmmu_probe(struct platform_device 
*pdev)
if (ret)
return ret;
 
-   iommu_device_set_ops(&data->iommu, &exynos_iommu_ops);
-   iommu_device_set_fwnode(&da

[PATCH v2 1/2] iommu: Statically set module owner

2021-04-01 Thread Robin Murphy
It happens that the 3 drivers which first supported being modular are
also ones which play games with their pgsize_bitmap, so have non-const
iommu_ops where dynamically setting the owner manages to work out OK.
However, it's less than ideal to force that upon all drivers which want
to be modular - like the new sprd-iommu driver which now has a potential
bug in that regard - so let's just statically set the module owner and
let ops remain const wherever possible.

Reviewed-by: Christoph Hellwig 
Acked-by: Will Deacon 
Signed-off-by: Robin Murphy 
---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 1 +
 drivers/iommu/arm/arm-smmu/arm-smmu.c   | 1 +
 drivers/iommu/sprd-iommu.c  | 1 +
 drivers/iommu/virtio-iommu.c| 1 +
 include/linux/iommu.h   | 9 +
 5 files changed, 5 insertions(+), 8 deletions(-)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c 
b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index 8594b4a83043..b82000519af6 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -2632,6 +2632,7 @@ static struct iommu_ops arm_smmu_ops = {
.sva_unbind = arm_smmu_sva_unbind,
.sva_get_pasid  = arm_smmu_sva_get_pasid,
.pgsize_bitmap  = -1UL, /* Restricted during device attach */
+   .owner  = THIS_MODULE,
 };
 
 /* Probing and initialisation functions */
diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu.c 
b/drivers/iommu/arm/arm-smmu/arm-smmu.c
index d8c6bfde6a61..11ca963c4b93 100644
--- a/drivers/iommu/arm/arm-smmu/arm-smmu.c
+++ b/drivers/iommu/arm/arm-smmu/arm-smmu.c
@@ -1638,6 +1638,7 @@ static struct iommu_ops arm_smmu_ops = {
.put_resv_regions   = generic_iommu_put_resv_regions,
.def_domain_type= arm_smmu_def_domain_type,
.pgsize_bitmap  = -1UL, /* Restricted during device attach */
+   .owner  = THIS_MODULE,
 };
 
 static void arm_smmu_device_reset(struct arm_smmu_device *smmu)
diff --git a/drivers/iommu/sprd-iommu.c b/drivers/iommu/sprd-iommu.c
index e1dc2f7d5639..b5edf0e82176 100644
--- a/drivers/iommu/sprd-iommu.c
+++ b/drivers/iommu/sprd-iommu.c
@@ -436,6 +436,7 @@ static const struct iommu_ops sprd_iommu_ops = {
.device_group   = sprd_iommu_device_group,
.of_xlate   = sprd_iommu_of_xlate,
.pgsize_bitmap  = ~0UL << SPRD_IOMMU_PAGE_SHIFT,
+   .owner  = THIS_MODULE,
 };
 
 static const struct of_device_id sprd_iommu_of_match[] = {
diff --git a/drivers/iommu/virtio-iommu.c b/drivers/iommu/virtio-iommu.c
index 2bfdd5734844..594ed827e944 100644
--- a/drivers/iommu/virtio-iommu.c
+++ b/drivers/iommu/virtio-iommu.c
@@ -945,6 +945,7 @@ static struct iommu_ops viommu_ops = {
.get_resv_regions   = viommu_get_resv_regions,
.put_resv_regions   = generic_iommu_put_resv_regions,
.of_xlate   = viommu_of_xlate,
+   .owner  = THIS_MODULE,
 };
 
 static int viommu_init_vqs(struct viommu_dev *viommu)
diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index 5e7fe519430a..dce8c5e12ea0 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -379,19 +379,12 @@ int  iommu_device_link(struct iommu_device   *iommu, 
struct device *link);
 void iommu_device_unlink(struct iommu_device *iommu, struct device *link);
 int iommu_deferred_attach(struct device *dev, struct iommu_domain *domain);
 
-static inline void __iommu_device_set_ops(struct iommu_device *iommu,
+static inline void iommu_device_set_ops(struct iommu_device *iommu,
  const struct iommu_ops *ops)
 {
iommu->ops = ops;
 }
 
-#define iommu_device_set_ops(iommu, ops)   \
-do {   \
-   struct iommu_ops *__ops = (struct iommu_ops *)(ops);\
-   __ops->owner = THIS_MODULE; \
-   __iommu_device_set_ops(iommu, __ops);   \
-} while (0)
-
 static inline void iommu_device_set_fwnode(struct iommu_device *iommu,
   struct fwnode_handle *fwnode)
 {
-- 
2.21.0.dirty

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH V4 05/18] iommu/ioasid: Redefine IOASID set and allocation APIs

2021-04-01 Thread Jason Gunthorpe
On Thu, Apr 01, 2021 at 01:43:36PM +, Liu, Yi L wrote:
> > From: Jason Gunthorpe 
> > Sent: Thursday, April 1, 2021 9:16 PM
> > 
> > On Thu, Apr 01, 2021 at 01:10:48PM +, Liu, Yi L wrote:
> > > > From: Jason Gunthorpe 
> > > > Sent: Thursday, April 1, 2021 7:47 PM
> > > [...]
> > > > I'm worried Intel views the only use of PASID in a guest is with
> > > > ENQCMD, but that is not consistent with the industry. We need to see
> > > > normal nested PASID support with assigned PCI VFs.
> > >
> > > I'm not quire flow here. Intel also allows PASID usage in guest without
> > > ENQCMD. e.g. Passthru a PF to guest, and use PASID on it without
> > ENQCMD.
> > 
> > Then you need all the parts, the hypervisor calls from the vIOMMU, and
> > you can't really use a vPASID.
> 
> This is a diagram shows the vSVA setup.

I'm not talking only about vSVA. Generic PASID support with arbitary
mappings.

And how do you deal with the vPASID vs pPASID issue if the system has
a mix of physical devices and mdevs?

Jason
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


RE: [PATCH V4 05/18] iommu/ioasid: Redefine IOASID set and allocation APIs

2021-04-01 Thread Liu, Yi L
> From: Jason Gunthorpe 
> Sent: Thursday, April 1, 2021 9:16 PM
> 
> On Thu, Apr 01, 2021 at 01:10:48PM +, Liu, Yi L wrote:
> > > From: Jason Gunthorpe 
> > > Sent: Thursday, April 1, 2021 7:47 PM
> > [...]
> > > I'm worried Intel views the only use of PASID in a guest is with
> > > ENQCMD, but that is not consistent with the industry. We need to see
> > > normal nested PASID support with assigned PCI VFs.
> >
> > I'm not quire flow here. Intel also allows PASID usage in guest without
> > ENQCMD. e.g. Passthru a PF to guest, and use PASID on it without
> ENQCMD.
> 
> Then you need all the parts, the hypervisor calls from the vIOMMU, and
> you can't really use a vPASID.

This is a diagram shows the vSVA setup.

.-.  .---.
|   vIOMMU|  | Guest process CR3, FL only|
| |  '---'
./
| PASID Entry |--- PASID cache flush -
'-'   |
| |   V
| |CR3 in GPA
'-'
Guest
--| Shadow |--|
  vv  v
Host
.-.  .--.
|   pIOMMU|  | Bind FL for GVA-GPA  |
| |  '--'
./  |
| PASID Entry | V (Nested xlate)
'\.--.
| |   |SL for GPA-HPA, default domain|
| |   '--'
'-'
Where:
 - FL = First level/stage one page tables
 - SL = Second level/stage two page tables

https://lore.kernel.org/linux-iommu/20210302203545.436623-1-yi.l@intel.com/

> 
> I'm not sure how Intel intends to resolve all of this.
> 
> > > > - this per-ioasid SVA operations is not aligned with the native SVA
> usage
> > > >   model. Native SVA bind is per-device.
> > >
> > > Seems like that is an error in native SVA.
> > >
> > > SVA is a particular mode of the PASID's memory mapping table, it has
> > > nothing to do with a device.
> >
> > I think it still has relationship with device. This is determined by the
> > DMA remapping hierarchy in hardware. e.g. Intel VT-d, the DMA isolation
> is
> > enforced first in device granularity and then PASID granularity. SVA makes
> > usage of both PASID and device granularity isolation.
> 
> When the device driver authorizes a PASID the VT-d stuff should setup
> the isolation parameters for the give pci_device and PASID.

yes, both device and PASID is needed to setup VT-d stuff.

> Do not leak implementation details like this as uAPI. Authorization
> and memory map are distinct ideas with distinct interfaces. Do not mix
> them.

got you. Let's focus on the uAPI things here and leave implementation details
in RFC patches.

Thanks,
Yi Liu

> Jason
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH V4 05/18] iommu/ioasid: Redefine IOASID set and allocation APIs

2021-04-01 Thread Jason Gunthorpe
On Thu, Apr 01, 2021 at 01:38:46PM +, Liu, Yi L wrote:
> > From: Jean-Philippe Brucker 
> > Sent: Thursday, April 1, 2021 8:05 PM
> [...]
> > 
> > Also wondering about:
> > 
> > * Querying IOMMU nesting capabilities before binding page tables (which
> >   page table formats are supported?). We were planning to have a VFIO cap,
> >   but I'm guessing we need to go back to the sysfs solution?
> 
> I think it can also be with /dev/ioasid.

Sure, anything to do with page table formats and setting page tables
should go through ioasid.

> > * Invalidation, probably an ioasid_fd ioctl?
> 
> yeah, if we are doing bind/unbind_pagtable via ioasid_fd, then yes,
> invalidation should go this way as well. This is why I worried it may
> fail to meet the requirement from you and Eric.

Yes, all manipulation of page tables, including removing memory ranges, or
setting memory ranges to trigger a page fault behavior should go
through here.

> > * Page faults, page response. From and to devices, and don't necessarily
> >   have a PASID. But needed by vdpa as well, so that's also going through
> >   /dev/ioasid?
> 
> page faults should still be per-device, but the fault event fd may be stored
> in /dev/ioasid. page response would be in /dev/ioasid just like invalidation.

Here you mean non-SVA page faults that are delegated to userspace to handle?

Why would that be per-device?

Can you show the flow you imagine?

Jason
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


RE: [PATCH V4 05/18] iommu/ioasid: Redefine IOASID set and allocation APIs

2021-04-01 Thread Liu, Yi L
> From: Jean-Philippe Brucker 
> Sent: Thursday, April 1, 2021 8:05 PM
[...]
> 
> Also wondering about:
> 
> * Querying IOMMU nesting capabilities before binding page tables (which
>   page table formats are supported?). We were planning to have a VFIO cap,
>   but I'm guessing we need to go back to the sysfs solution?

I think it can also be with /dev/ioasid.

> 
> * Invalidation, probably an ioasid_fd ioctl?

yeah, if we are doing bind/unbind_pagtable via ioasid_fd, then yes,
invalidation should go this way as well. This is why I worried it may
fail to meet the requirement from you and Eric.

> * Page faults, page response. From and to devices, and don't necessarily
>   have a PASID. But needed by vdpa as well, so that's also going through
>   /dev/ioasid?

page faults should still be per-device, but the fault event fd may be stored
in /dev/ioasid. page response would be in /dev/ioasid just like invalidation.

Regards,
Yi Liu

> 
> Thanks,
> Jean
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH 16/18] iommu: remove DOMAIN_ATTR_DMA_USE_FLUSH_QUEUE

2021-04-01 Thread Will Deacon
On Thu, Apr 01, 2021 at 11:59:45AM +0200, Christoph Hellwig wrote:
> For now I'll just pass the iommu_domain to iommu_get_dma_strict,
> so that we can check for it.  We can do additional cleanups on top
> of that later.

Sounds good to me, cheers!

Will
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH v14 13/13] iommu/smmuv3: Accept configs with more than one context descriptor

2021-04-01 Thread Auger Eric
Hi Shameer,
On 4/1/21 2:38 PM, Shameerali Kolothum Thodi wrote:
> 
> 
>> -Original Message-
>> From: Auger Eric [mailto:eric.au...@redhat.com]
>> Sent: 01 April 2021 12:49
>> To: yuzenghui 
>> Cc: eric.auger@gmail.com; iommu@lists.linux-foundation.org;
>> linux-ker...@vger.kernel.org; k...@vger.kernel.org;
>> kvm...@lists.cs.columbia.edu; w...@kernel.org; m...@kernel.org;
>> robin.mur...@arm.com; j...@8bytes.org; alex.william...@redhat.com;
>> t...@semihalf.com; zhukeqian ;
>> jacob.jun@linux.intel.com; yi.l@intel.com; wangxingang
>> ; jiangkunkun ;
>> jean-phili...@linaro.org; zhangfei@linaro.org; zhangfei@gmail.com;
>> vivek.gau...@arm.com; Shameerali Kolothum Thodi
>> ; nicoleots...@gmail.com;
>> lushenming ; vse...@nvidia.com; Wanghaibin (D)
>> 
>> Subject: Re: [PATCH v14 13/13] iommu/smmuv3: Accept configs with more than
>> one context descriptor
>>
>> Hi Zenghui,
>>
>> On 3/30/21 11:23 AM, Zenghui Yu wrote:
>>> Hi Eric,
>>>
>>> On 2021/2/24 4:56, Eric Auger wrote:
 In preparation for vSVA, let's accept userspace provided configs
 with more than one CD. We check the max CD against the host iommu
 capability and also the format (linear versus 2 level).

 Signed-off-by: Eric Auger 
 Signed-off-by: Shameer Kolothum
>> 
 ---
   drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 13 -
   1 file changed, 8 insertions(+), 5 deletions(-)

 diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
 b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
 index 332d31c0680f..ab74a0289893 100644
 --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
 +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
 @@ -3038,14 +3038,17 @@ static int
>> arm_smmu_attach_pasid_table(struct
 iommu_domain *domain,
   if (smmu_domain->s1_cfg.set)
   goto out;
   -    /*
 - * we currently support a single CD so s1fmt and s1dss
 - * fields are also ignored
 - */
 -    if (cfg->pasid_bits)
 +    list_for_each_entry(master, &smmu_domain->devices,
 domain_head) {
 +    if (cfg->pasid_bits > master->ssid_bits)
 +    goto out;
 +    }
 +    if (cfg->vendor_data.smmuv3.s1fmt ==
 STRTAB_STE_0_S1FMT_64K_L2 &&
 +    !(smmu->features &
>> ARM_SMMU_FEAT_2_LVL_CDTAB))
   goto out;
     smmu_domain->s1_cfg.cdcfg.cdtab_dma = cfg->base_ptr;
 +    smmu_domain->s1_cfg.s1cdmax = cfg->pasid_bits;
 +    smmu_domain->s1_cfg.s1fmt =
>> cfg->vendor_data.smmuv3.s1fmt;
>>>
>>> And what about the SIDSS field?
>>>
>> I added this patch upon Shameer's request, to be more vSVA friendly.
>> Hower this series does not really target multiple CD support. At the
>> moment the driver only supports STRTAB_STE_1_S1DSS_SSID0 (0x2) I think.
>> At this moment maybe I can only check the s1dss field is 0x2. Or simply
>> removes this patch?
>>
>> Thoughts?
> 
> Right. This was useful for vSVA tests. But yes, to properly support multiple 
> CDs
> we need to pass the S1DSS from Qemu. And that requires further changes.
> So I think it's better to remove this patch and reject S1CDMAX != 0 cases.
OK I will remove it

Thanks

Eric
> 
> Thanks,
> Shameer
>
>>
>> Eric
> 

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

Re: [PATCH V4 05/18] iommu/ioasid: Redefine IOASID set and allocation APIs

2021-04-01 Thread Jason Gunthorpe
On Thu, Apr 01, 2021 at 01:10:48PM +, Liu, Yi L wrote:
> > From: Jason Gunthorpe 
> > Sent: Thursday, April 1, 2021 7:47 PM
> [...]
> > I'm worried Intel views the only use of PASID in a guest is with
> > ENQCMD, but that is not consistent with the industry. We need to see
> > normal nested PASID support with assigned PCI VFs.
> 
> I'm not quire flow here. Intel also allows PASID usage in guest without
> ENQCMD. e.g. Passthru a PF to guest, and use PASID on it without ENQCMD.

Then you need all the parts, the hypervisor calls from the vIOMMU, and
you can't really use a vPASID.

I'm not sure how Intel intends to resolve all of this.

> > > - this per-ioasid SVA operations is not aligned with the native SVA usage
> > >   model. Native SVA bind is per-device.
> > 
> > Seems like that is an error in native SVA.
> > 
> > SVA is a particular mode of the PASID's memory mapping table, it has
> > nothing to do with a device.
> 
> I think it still has relationship with device. This is determined by the
> DMA remapping hierarchy in hardware. e.g. Intel VT-d, the DMA isolation is
> enforced first in device granularity and then PASID granularity. SVA makes
> usage of both PASID and device granularity isolation.

When the device driver authorizes a PASID the VT-d stuff should setup
the isolation parameters for the give pci_device and PASID.

Do not leak implementation details like this as uAPI. Authorization
and memory map are distinct ideas with distinct interfaces. Do not mix
them.

Jason
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


RE: [PATCH V4 05/18] iommu/ioasid: Redefine IOASID set and allocation APIs

2021-04-01 Thread Liu, Yi L
> From: Jason Gunthorpe 
> Sent: Thursday, April 1, 2021 7:47 PM
[...]
> I'm worried Intel views the only use of PASID in a guest is with
> ENQCMD, but that is not consistent with the industry. We need to see
> normal nested PASID support with assigned PCI VFs.

I'm not quire flow here. Intel also allows PASID usage in guest without
ENQCMD. e.g. Passthru a PF to guest, and use PASID on it without ENQCMD.

[...]

> I'm sure there will be some small differences, and you should clearly
> explain the entire uAPI surface so that soneone from AMD and ARM can
> review it.

good suggestion, will do.

> > - this per-ioasid SVA operations is not aligned with the native SVA usage
> >   model. Native SVA bind is per-device.
> 
> Seems like that is an error in native SVA.
> 
> SVA is a particular mode of the PASID's memory mapping table, it has
> nothing to do with a device.

I think it still has relationship with device. This is determined by the
DMA remapping hierarchy in hardware. e.g. Intel VT-d, the DMA isolation is
enforced first in device granularity and then PASID granularity. SVA makes
usage of both PASID and device granularity isolation.

Regards,
Yi Liu

> Jason
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


RE: [PATCH v14 13/13] iommu/smmuv3: Accept configs with more than one context descriptor

2021-04-01 Thread Shameerali Kolothum Thodi


> -Original Message-
> From: Auger Eric [mailto:eric.au...@redhat.com]
> Sent: 01 April 2021 12:49
> To: yuzenghui 
> Cc: eric.auger@gmail.com; iommu@lists.linux-foundation.org;
> linux-ker...@vger.kernel.org; k...@vger.kernel.org;
> kvm...@lists.cs.columbia.edu; w...@kernel.org; m...@kernel.org;
> robin.mur...@arm.com; j...@8bytes.org; alex.william...@redhat.com;
> t...@semihalf.com; zhukeqian ;
> jacob.jun@linux.intel.com; yi.l@intel.com; wangxingang
> ; jiangkunkun ;
> jean-phili...@linaro.org; zhangfei@linaro.org; zhangfei@gmail.com;
> vivek.gau...@arm.com; Shameerali Kolothum Thodi
> ; nicoleots...@gmail.com;
> lushenming ; vse...@nvidia.com; Wanghaibin (D)
> 
> Subject: Re: [PATCH v14 13/13] iommu/smmuv3: Accept configs with more than
> one context descriptor
> 
> Hi Zenghui,
> 
> On 3/30/21 11:23 AM, Zenghui Yu wrote:
> > Hi Eric,
> >
> > On 2021/2/24 4:56, Eric Auger wrote:
> >> In preparation for vSVA, let's accept userspace provided configs
> >> with more than one CD. We check the max CD against the host iommu
> >> capability and also the format (linear versus 2 level).
> >>
> >> Signed-off-by: Eric Auger 
> >> Signed-off-by: Shameer Kolothum
> 
> >> ---
> >>   drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 13 -
> >>   1 file changed, 8 insertions(+), 5 deletions(-)
> >>
> >> diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> >> b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> >> index 332d31c0680f..ab74a0289893 100644
> >> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> >> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> >> @@ -3038,14 +3038,17 @@ static int
> arm_smmu_attach_pasid_table(struct
> >> iommu_domain *domain,
> >>   if (smmu_domain->s1_cfg.set)
> >>   goto out;
> >>   -    /*
> >> - * we currently support a single CD so s1fmt and s1dss
> >> - * fields are also ignored
> >> - */
> >> -    if (cfg->pasid_bits)
> >> +    list_for_each_entry(master, &smmu_domain->devices,
> >> domain_head) {
> >> +    if (cfg->pasid_bits > master->ssid_bits)
> >> +    goto out;
> >> +    }
> >> +    if (cfg->vendor_data.smmuv3.s1fmt ==
> >> STRTAB_STE_0_S1FMT_64K_L2 &&
> >> +    !(smmu->features &
> ARM_SMMU_FEAT_2_LVL_CDTAB))
> >>   goto out;
> >>     smmu_domain->s1_cfg.cdcfg.cdtab_dma = cfg->base_ptr;
> >> +    smmu_domain->s1_cfg.s1cdmax = cfg->pasid_bits;
> >> +    smmu_domain->s1_cfg.s1fmt =
> cfg->vendor_data.smmuv3.s1fmt;
> >
> > And what about the SIDSS field?
> >
> I added this patch upon Shameer's request, to be more vSVA friendly.
> Hower this series does not really target multiple CD support. At the
> moment the driver only supports STRTAB_STE_1_S1DSS_SSID0 (0x2) I think.
> At this moment maybe I can only check the s1dss field is 0x2. Or simply
> removes this patch?
> 
> Thoughts?

Right. This was useful for vSVA tests. But yes, to properly support multiple CDs
we need to pass the S1DSS from Qemu. And that requires further changes.
So I think it's better to remove this patch and reject S1CDMAX != 0 cases.

Thanks,
Shameer
   
> 
> Eric

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

Re: [PATCH v14 06/13] iommu/smmuv3: Allow stage 1 invalidation with unmanaged ASIDs

2021-04-01 Thread Kunkun Jiang

Hi Eric,

On 2021/2/24 4:56, Eric Auger wrote:

With nested stage support, soon we will need to invalidate
S1 contexts and ranges tagged with an unmanaged asid, this
latter being managed by the guest. So let's introduce 2 helpers
that allow to invalidate with externally managed ASIDs

Signed-off-by: Eric Auger 

---

v13 -> v14
- Actually send the NH_ASID command (reported by Xingang Wang)
---
  drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 38 -
  1 file changed, 29 insertions(+), 9 deletions(-)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c 
b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index 5579ec4fccc8..4c19a1114de4 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -1843,9 +1843,9 @@ int arm_smmu_atc_inv_domain(struct arm_smmu_domain 
*smmu_domain, int ssid,
  }
  
  /* IO_PGTABLE API */

-static void arm_smmu_tlb_inv_context(void *cookie)
+static void __arm_smmu_tlb_inv_context(struct arm_smmu_domain *smmu_domain,
+  int ext_asid)
  {
-   struct arm_smmu_domain *smmu_domain = cookie;
struct arm_smmu_device *smmu = smmu_domain->smmu;
struct arm_smmu_cmdq_ent cmd;
  
@@ -1856,7 +1856,13 @@ static void arm_smmu_tlb_inv_context(void *cookie)

 * insertion to guarantee those are observed before the TLBI. Do be
 * careful, 007.
 */
-   if (smmu_domain->stage == ARM_SMMU_DOMAIN_S1) {
+   if (ext_asid >= 0) { /* guest stage 1 invalidation */
+   cmd.opcode  = CMDQ_OP_TLBI_NH_ASID;
+   cmd.tlbi.asid   = ext_asid;
+   cmd.tlbi.vmid   = smmu_domain->s2_cfg.vmid;
+   arm_smmu_cmdq_issue_cmd(smmu, &cmd);
+   arm_smmu_cmdq_issue_sync(smmu);
+   } else if (smmu_domain->stage == ARM_SMMU_DOMAIN_S1) {
arm_smmu_tlb_inv_asid(smmu, smmu_domain->s1_cfg.cd.asid);
} else {
cmd.opcode  = CMDQ_OP_TLBI_S12_VMALL;
@@ -1867,6 +1873,13 @@ static void arm_smmu_tlb_inv_context(void *cookie)
arm_smmu_atc_inv_domain(smmu_domain, 0, 0, 0);
  }
  
+static void arm_smmu_tlb_inv_context(void *cookie)

+{
+   struct arm_smmu_domain *smmu_domain = cookie;
+
+   __arm_smmu_tlb_inv_context(smmu_domain, -1);
+}
+
  static void __arm_smmu_tlb_inv_range(struct arm_smmu_cmdq_ent *cmd,
 unsigned long iova, size_t size,
 size_t granule,
@@ -1926,9 +1939,10 @@ static void __arm_smmu_tlb_inv_range(struct 
arm_smmu_cmdq_ent *cmd,
arm_smmu_cmdq_batch_submit(smmu, &cmds);
  }
  

Here is the part of code in __arm_smmu_tlb_inv_range():

    if (smmu->features & ARM_SMMU_FEAT_RANGE_INV) {
    /* Get the leaf page size */
    tg = __ffs(smmu_domain->domain.pgsize_bitmap);

    /* Convert page size of 12,14,16 (log2) to 1,2,3 */
    cmd->tlbi.tg = (tg - 10) / 2;

    /* Determine what level the granule is at */
    cmd->tlbi.ttl = 4 - ((ilog2(granule) - 3) / (tg - 3));

    num_pages = size >> tg;
    }

When pSMMU supports RIL, we get the leaf page size by __ffs(smmu_domain->
domain.pgsize_bitmap). In nested mode, it is determined by host 
PAGE_SIZE. If
the host kernel and guest kernel has different translation granule (e.g. 
host 16K,

guest 4K), __arm_smmu_tlb_inv_range() will issue an incorrect tlbi command.

Do you have any idea about this issue?

Best Regards,
Kunkun Jiang

-static void arm_smmu_tlb_inv_range_domain(unsigned long iova, size_t size,
- size_t granule, bool leaf,
- struct arm_smmu_domain *smmu_domain)
+static void
+arm_smmu_tlb_inv_range_domain(unsigned long iova, size_t size,
+ size_t granule, bool leaf, int ext_asid,
+ struct arm_smmu_domain *smmu_domain)
  {
struct arm_smmu_cmdq_ent cmd = {
.tlbi = {
@@ -1936,7 +1950,12 @@ static void arm_smmu_tlb_inv_range_domain(unsigned long 
iova, size_t size,
},
};
  
-	if (smmu_domain->stage == ARM_SMMU_DOMAIN_S1) {

+   if (ext_asid >= 0) {  /* guest stage 1 invalidation */
+   cmd.opcode  = smmu_domain->smmu->features & 
ARM_SMMU_FEAT_E2H ?
+ CMDQ_OP_TLBI_EL2_VA : CMDQ_OP_TLBI_NH_VA;
+   cmd.tlbi.asid   = ext_asid;
+   cmd.tlbi.vmid   = smmu_domain->s2_cfg.vmid;
+   } else if (smmu_domain->stage == ARM_SMMU_DOMAIN_S1) {
cmd.opcode  = smmu_domain->smmu->features & 
ARM_SMMU_FEAT_E2H ?
  CMDQ_OP_TLBI_EL2_VA : CMDQ_OP_TLBI_NH_VA;
cmd.tlbi.asid   = smmu_domain->s1_cfg.cd.asid;
@@ -1944,6 +1963,7 @@ static void arm_smmu_tlb_inv_range_domain(unsigned long 
iova, size_t size,
cmd.opcode 

Re: [PATCH V4 05/18] iommu/ioasid: Redefine IOASID set and allocation APIs

2021-04-01 Thread Jason Gunthorpe
On Thu, Apr 01, 2021 at 02:05:00PM +0200, Jean-Philippe Brucker wrote:
> On Thu, Apr 01, 2021 at 07:04:01AM +, Liu, Yi L wrote:
> > > - how about AMD and ARM's vSVA support? Their PASID allocation and page
> > > table
> > >   happens within guest. They only need to bind the guest PASID table to
> > > host.
> 
> In this case each VM has its own IOASID space, and the host IOASID
> allocator doesn't participate. Plus this only makes sense when assigning a
> whole VF to a guest, and VFIO is the tool for this. So I wouldn't shoehorn
> those ops into /dev/ioasid, though we do need a transport for invalidate
> commands.

How does security work? Devices still have to be authorized to use the
PASID and this approach seems like it completely excludes mdev/vdpa
from ever using a PASID, and those are the most logical users.

> > >   Above model seems unable to fit them. (Jean, Eric, Jacob please feel 
> > > free
> > >   to correct me)
> > > - this per-ioasid SVA operations is not aligned with the native SVA usage
> > >   model. Native SVA bind is per-device.
> 
> Bare-metal SVA doesn't need /dev/ioasid either. 

It depends what you are doing. /dev/ioasid would provide fine grained
control over the memory mapping. It is not strict SVA, but I can see
applications where using a GPU with a pre-configured optimized mapping
could be interesting.

> A program uses a device handle to either ask whether SVA is enabled,
> or to enable it explicitly.  With or without /dev/ioasid, that step
> is required. OpenCL uses the first method - automatically enable
> "fine-grain system SVM" if available, and provide a flag to
> userspace.

SVA can be done with ioasid, we can decide if it makes sense to have
shortcuts in every driver

> So userspace does not need to know about PASID. It's only one method for
> doing SVA (some GPUs are context-switching page tables instead).

Sure, there are lots of approaches. Here we are only talking about
PASID enablement. PASID has more options.
 
> * Page faults, page response. From and to devices, and don't necessarily
>   have a PASID. But needed by vdpa as well, so that's also going through
>   /dev/ioasid?

Only real PASID's should use this interface. All the not-PASID stuff
is on its own.

VPDA should accept a PASID from here and configure&authorize the real
HW to attach the PASID to all DMA's connected to the virtio queues.

Jason
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH v14 07/13] iommu/smmuv3: Implement cache_invalidate

2021-04-01 Thread Auger Eric
Hi Zenghui,

On 4/1/21 8:11 AM, Zenghui Yu wrote:
> Hi Eric,
> 
> On 2021/2/24 4:56, Eric Auger wrote:
>> +static int
>> +arm_smmu_cache_invalidate(struct iommu_domain *domain, struct device
>> *dev,
>> +  struct iommu_cache_invalidate_info *inv_info)
>> +{
>> +    struct arm_smmu_cmdq_ent cmd = {.opcode = CMDQ_OP_TLBI_NSNH_ALL};
>> +    struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
>> +    struct arm_smmu_device *smmu = smmu_domain->smmu;
>> +
>> +    if (smmu_domain->stage != ARM_SMMU_DOMAIN_NESTED)
>> +    return -EINVAL;
>> +
>> +    if (!smmu)
>> +    return -EINVAL;
>> +
>> +    if (inv_info->version != IOMMU_CACHE_INVALIDATE_INFO_VERSION_1)
>> +    return -EINVAL;
>> +
>> +    if (inv_info->cache & IOMMU_CACHE_INV_TYPE_PASID ||
> 
> I didn't find any code where we would emulate the CFGI_CD{_ALL} commands
> for guest and invalidate the stale CD entries on the physical side. Is
> PASID-cache type designed for that effect?
Yes it is. PASID-cache matches the CD table.
> 
>> +    inv_info->cache & IOMMU_CACHE_INV_TYPE_DEV_IOTLB) {
>> +    return -ENOENT;
>> +    }
>> +
>> +    if (!(inv_info->cache & IOMMU_CACHE_INV_TYPE_IOTLB))
>> +    return -EINVAL;
>> +
>> +    /* IOTLB invalidation */
>> +
>> +    switch (inv_info->granularity) {
>> +    case IOMMU_INV_GRANU_PASID:
>> +    {
>> +    struct iommu_inv_pasid_info *info =
>> +    &inv_info->granu.pasid_info;
>> +
>> +    if (info->flags & IOMMU_INV_ADDR_FLAGS_PASID)
>> +    return -ENOENT;
>> +    if (!(info->flags & IOMMU_INV_PASID_FLAGS_ARCHID))
>> +    return -EINVAL;
>> +
>> +    __arm_smmu_tlb_inv_context(smmu_domain, info->archid);
>> +    return 0;
>> +    }
>> +    case IOMMU_INV_GRANU_ADDR:
>> +    {
>> +    struct iommu_inv_addr_info *info = &inv_info->granu.addr_info;
>> +    size_t size = info->nb_granules * info->granule_size;
>> +    bool leaf = info->flags & IOMMU_INV_ADDR_FLAGS_LEAF;
>> +
>> +    if (info->flags & IOMMU_INV_ADDR_FLAGS_PASID)
>> +    return -ENOENT;
>> +
>> +    if (!(info->flags & IOMMU_INV_ADDR_FLAGS_ARCHID))
>> +    break;
>> +
>> +    arm_smmu_tlb_inv_range_domain(info->addr, size,
>> +  info->granule_size, leaf,
>> +  info->archid, smmu_domain);
>> +
>> +    arm_smmu_cmdq_issue_sync(smmu);
> 
> There is no need to issue one more SYNC.
Hum yes I did not notice it was made by the arm_smmu_cmdq_issue_cmdlist()

Thanks!

Eric
> 

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

Re: [PATCH V4 05/18] iommu/ioasid: Redefine IOASID set and allocation APIs

2021-04-01 Thread Jean-Philippe Brucker
On Thu, Apr 01, 2021 at 07:04:01AM +, Liu, Yi L wrote:
> > - how about AMD and ARM's vSVA support? Their PASID allocation and page
> > table
> >   happens within guest. They only need to bind the guest PASID table to
> > host.

In this case each VM has its own IOASID space, and the host IOASID
allocator doesn't participate. Plus this only makes sense when assigning a
whole VF to a guest, and VFIO is the tool for this. So I wouldn't shoehorn
those ops into /dev/ioasid, though we do need a transport for invalidate
commands.

> >   Above model seems unable to fit them. (Jean, Eric, Jacob please feel free
> >   to correct me)
> > - this per-ioasid SVA operations is not aligned with the native SVA usage
> >   model. Native SVA bind is per-device.

Bare-metal SVA doesn't need /dev/ioasid either. A program uses a device
handle to either ask whether SVA is enabled, or to enable it explicitly.
With or without /dev/ioasid, that step is required. OpenCL uses the first
method - automatically enable "fine-grain system SVM" if available, and
provide a flag to userspace.

So userspace does not need to know about PASID. It's only one method for
doing SVA (some GPUs are context-switching page tables instead).

> After reading your reply in 
> https://lore.kernel.org/linux-iommu/20210331123801.gd1463...@nvidia.com/#t
> So you mean /dev/ioasid FD is per-VM instead of per-ioasid, so above skeleton
> doesn't suit your idea. I draft below skeleton to see if our mind is the
> same. But I still believe there is an open on how to fit ARM and AMD's
> vSVA support in this the per-ioasid SVA operation model. thoughts?
> 
> +-+---+
> |  userspace  |   kernel space
> |
> +-+---+
> | ioasid_fd = | /dev/ioasid does below:   
> |
> | open("/dev/ioasid", O_RDWR);|   struct ioasid_fd_ctx {  
> |
> | |   struct list_head ioasid_list;   
> |
> | |   ... 
> |
> | |   } ifd_ctx; // ifd_ctx is per ioasid_fd  
> |
> +-+---+
> | ioctl(ioasid_fd,| /dev/ioasid does below:   
> |
> |   ALLOC, &ioasid);  |   struct ioasid_data {
> |
> | |   ioasid_t ioasid;
> |
> | |   struct list_head device_list;   
> |
> | |   struct list_head next;  
> |
> | |   ... 
> |
> | |   } id_data; // id_data is per ioasid 
> |
> | |   
> |
> | |   list_add(&id_data.next, 
> |
> | |&ifd_ctx.ioasid_list); 
> |
> +-+---+
> | ioctl(device_fd,| VFIO does below:  
> |
> |   DEVICE_ALLOW_IOASID,  | 1) get ioasid_fd, check if ioasid_fd is valid 
> |
> |   ioasid_fd,| 2) check if ioasid is allocated from 
> ioasid_fd|
> |   ioasid);  | 3) register device/domain info to /dev/ioasid 
> |
> | |tracked in id_data.device_list 
> |
> | | 4) record the ioasid in VFIO's per-device 
> |
> | |ioasid list for future security check  
> |
> +-+---+
> | ioctl(ioasid_fd,| /dev/ioasid does below:   
> |
> |   BIND_PGTBL,   | 1) find ioasid's id_data  
> |
> |   pgtbl_data,   | 2) loop the id_data.device_list and tell 
> iommu|
> |   ioasid);  |give ioasid access to the devices  
> |
> +-+---+
> | ioctl(ioasid_fd,| /dev/ioasid does below:   
> |
> |   UNBIND_PGTBL, | 1) find ioasid's id_data  
> |
> |   ioasid);  | 2) loop the id_data.device_list and tell 
> iommu|
> | |clear ioasid access to the devices 
> |
> +-+---+
> | ioctl(device_fd,| VFIO does below:  
> |
> |  DEVICE_DISALLOW_IOASID,| 1) check if ioasid is associated in VFIO's

Re: [PATCH V4 05/18] iommu/ioasid: Redefine IOASID set and allocation APIs

2021-04-01 Thread Jason Gunthorpe
On Thu, Apr 01, 2021 at 07:04:01AM +, Liu, Yi L wrote:

> After reading your reply in 
> https://lore.kernel.org/linux-iommu/20210331123801.gd1463...@nvidia.com/#t
> So you mean /dev/ioasid FD is per-VM instead of per-ioasid, so above skeleton
> doesn't suit your idea.

You can do it one PASID per FD or multiple PASID's per FD. Most likely
we will have high numbers of PASID's in a qemu process so I assume
that number of FDs will start to be a contraining factor, thus
multiplexing is reasonable.

It doesn't really change anything about the basic flow.

digging deeply into it either seems like a reasonable choice.

> +-+---+
> |  userspace  |   kernel space
> |
> +-+---+
> | ioasid_fd = | /dev/ioasid does below:   
> |
> | open("/dev/ioasid", O_RDWR);|   struct ioasid_fd_ctx {  
> |
> | |   struct list_head ioasid_list;   
> |
> | |   ... 
> |
> | |   } ifd_ctx; // ifd_ctx is per ioasid_fd  
> |

Sure, possibly an xarray not a list

> +-+---+
> | ioctl(ioasid_fd,| /dev/ioasid does below:   
> |
> |   ALLOC, &ioasid);  |   struct ioasid_data {
> |
> | |   ioasid_t ioasid;
> |
> | |   struct list_head device_list;   
> |
> | |   struct list_head next;  
> |
> | |   ... 
> |
> | |   } id_data; // id_data is per ioasid 
> |
> | |   
> |
> | |   list_add(&id_data.next, 
> |
> | |&ifd_ctx.ioasid_list);
> |

Yes, this should have a kref in it too

> +-+---+
> | ioctl(device_fd,| VFIO does below:  
> |
> |   DEVICE_ALLOW_IOASID,  | 1) get ioasid_fd, check if ioasid_fd is valid 
> |
> |   ioasid_fd,| 2) check if ioasid is allocated from 
> ioasid_fd|
> |   ioasid);  | 3) register device/domain info to /dev/ioasid 
> |
> | |tracked in id_data.device_list 
> |
> | | 4) record the ioasid in VFIO's per-device 
> |
> | |ioasid list for future security check  
> |

You would provide a function that does steps 1&2 look at eventfd for
instance.

I'm not sure we need to register the device with the ioasid. device
should incr the kref on the ioasid_data at this point.

> +-+---+
> | ioctl(ioasid_fd,| /dev/ioasid does below:   
> |
> |   BIND_PGTBL,   | 1) find ioasid's id_data  
> |
> |   pgtbl_data,   | 2) loop the id_data.device_list and tell 
> iommu|
> |   ioasid);  |give ioasid access to the devices
> |

This seems backwards, DEVICE_ALLOW_IOASID should tell the iommu to
give the ioasid to the device.

Here the ioctl should be about assigning a memory map from the the current
mm_struct to the pasid

> +-+---+
> | ioctl(ioasid_fd,| /dev/ioasid does below:   
> |
> |   UNBIND_PGTBL, | 1) find ioasid's id_data  
> |
> |   ioasid);  | 2) loop the id_data.device_list and tell 
> iommu|
> | |clear ioasid access to the devices 
> |

Also seems backwards. The ioctl here should be 'destroy ioasid' which
wipes out the page table, halts DMA access and parks the PASID until
all users are done.

> +-+---+
> | ioctl(device_fd,| VFIO does below:  
> |
> |  DEVICE_DISALLOW_IOASID,| 1) check if ioasid is associated in VFIO's
> |
> |   ioasid_fd,|device ioasid list.
> |
> |   ioasid);  | 2) unregister device/domain info from 
> |
> | |/dev/ioasid, clear in id_data.device_list  
> |

This should disconnect the iommu and kref_put the ioasid_data

Remember the layering, only the device_fd knows what th

Re: [PATCH v14 13/13] iommu/smmuv3: Accept configs with more than one context descriptor

2021-04-01 Thread Auger Eric
Hi Zenghui,

On 3/30/21 11:23 AM, Zenghui Yu wrote:
> Hi Eric,
> 
> On 2021/2/24 4:56, Eric Auger wrote:
>> In preparation for vSVA, let's accept userspace provided configs
>> with more than one CD. We check the max CD against the host iommu
>> capability and also the format (linear versus 2 level).
>>
>> Signed-off-by: Eric Auger 
>> Signed-off-by: Shameer Kolothum 
>> ---
>>   drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 13 -
>>   1 file changed, 8 insertions(+), 5 deletions(-)
>>
>> diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
>> b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
>> index 332d31c0680f..ab74a0289893 100644
>> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
>> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
>> @@ -3038,14 +3038,17 @@ static int arm_smmu_attach_pasid_table(struct
>> iommu_domain *domain,
>>   if (smmu_domain->s1_cfg.set)
>>   goto out;
>>   -    /*
>> - * we currently support a single CD so s1fmt and s1dss
>> - * fields are also ignored
>> - */
>> -    if (cfg->pasid_bits)
>> +    list_for_each_entry(master, &smmu_domain->devices,
>> domain_head) {
>> +    if (cfg->pasid_bits > master->ssid_bits)
>> +    goto out;
>> +    }
>> +    if (cfg->vendor_data.smmuv3.s1fmt ==
>> STRTAB_STE_0_S1FMT_64K_L2 &&
>> +    !(smmu->features & ARM_SMMU_FEAT_2_LVL_CDTAB))
>>   goto out;
>>     smmu_domain->s1_cfg.cdcfg.cdtab_dma = cfg->base_ptr;
>> +    smmu_domain->s1_cfg.s1cdmax = cfg->pasid_bits;
>> +    smmu_domain->s1_cfg.s1fmt = cfg->vendor_data.smmuv3.s1fmt;
> 
> And what about the SIDSS field?
> 
I added this patch upon Shameer's request, to be more vSVA friendly.
Hower this series does not really target multiple CD support. At the
moment the driver only supports STRTAB_STE_1_S1DSS_SSID0 (0x2) I think.
At this moment maybe I can only check the s1dss field is 0x2. Or simply
removes this patch?

Thoughts?

Eric

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

Re: [PATCH V4 05/18] iommu/ioasid: Redefine IOASID set and allocation APIs

2021-04-01 Thread Jason Gunthorpe
On Thu, Apr 01, 2021 at 04:38:44AM +, Liu, Yi L wrote:
> > From: Jason Gunthorpe 
> > Sent: Wednesday, March 31, 2021 8:41 PM
> > 
> > On Wed, Mar 31, 2021 at 07:38:36AM +, Liu, Yi L wrote:
> > 
> > > The reason is /dev/ioasid FD is per-VM since the ioasid allocated to
> > > the VM should be able to be shared by all assigned device for the VM.
> > > But the SVA operations (bind/unbind page table, cache_invalidate) should
> > > be per-device.
> > 
> > It is not *per-device* it is *per-ioasid*
> >
> > And as /dev/ioasid is an interface for controlling multiple ioasid's
> > there is no issue to also multiplex the page table manipulation for
> > multiple ioasids as well.
> > 
> > What you should do next is sketch out in some RFC the exactl ioctls
> > each FD would have and show how the parts I outlined would work and
> > point out any remaining gaps.
> > 
> > The device FD is something like the vfio_device FD from VFIO, it has
> > *nothing* to do with PASID beyond having a single ioctl to authorize
> > the device to use the PASID. All control of the PASID is in
> > /dev/ioasid.
> 
> good to see this reply. Your idea is much clearer to me now. If I'm getting
> you correctly. I think the skeleton is something like below:
> 
> 1) userspace opens a /dev/ioasid, meanwhile there will be an ioasid
>allocated and a per-ioasid context which can be used to do bind page
>table and cache invalidate, an ioasid FD returned to userspace.
> 2) userspace passes the ioasid FD to VFIO, let it associated with a device
>FD (like vfio_device FD).
> 3) userspace binds page table on the ioasid FD with the page table info.
> 4) userspace unbinds the page table on the ioasid FD
> 5) userspace de-associates the ioasid FD and device FD
> 
> Does above suit your outline?

Seems so

> If yes, I still have below concern and wish to see your opinion.
> - the ioasid FD and device association will happen at runtime instead of
>   just happen in the setup phase.

Of course, this is required for security. The vIOMMU must perform the
device association when the guest requires it. Otherwise a guest
cannot isolate a PASID to a single process/device pair.

I'm worried Intel views the only use of PASID in a guest is with
ENQCMD, but that is not consistent with the industry. We need to see
normal nested PASID support with assigned PCI VFs.

> - how about AMD and ARM's vSVA support? Their PASID allocation and page table
>   happens within guest. They only need to bind the guest PASID table to host.
>   Above model seems unable to fit them. (Jean, Eric, Jacob please feel free
>   to correct me)

No, everything needs the device association step or it is not
secure. 

You can give a PASID to a guest and allow it to manipulate it's memory
map directly, nested under the guest's CPU page tables.

However the guest cannot authorize a PCI BDF to utilize that PASID
without going through some kind of step in the hypervisor. A Guest
should not be able to authorize a PASID for a BDF it doesn't have
access to - only the hypervisor can enforce this.

This all must also fit into the mdev model where only the
device-specific mdev driver can do the device specific PASID
authorization. A hypercall is essential, or we need to stop pretending
mdev is a good idea.

I'm sure there will be some small differences, and you should clearly
explain the entire uAPI surface so that soneone from AMD and ARM can
review it.

> - this per-ioasid SVA operations is not aligned with the native SVA usage
>   model. Native SVA bind is per-device.

Seems like that is an error in native SVA.

SVA is a particular mode of the PASID's memory mapping table, it has
nothing to do with a device.

Jason
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH 2/3] tracing: Use pr_crit() instead of long fancy messages

2021-04-01 Thread Robin Murphy

On 2021-04-01 10:39, Geert Uytterhoeven wrote:

Hi Steven,

On Wed, Mar 31, 2021 at 3:40 PM Steven Rostedt  wrote:

On Wed, 31 Mar 2021 11:31:03 +0200
Geert Uytterhoeven  wrote:


This reduces kernel size by ca. 0.5 KiB.


If you are worried about size, disable tracing and it will go away
entirely. 0.5KiB is a drop in the bucket compared to what tracing adds in
size overhead.


Fair enough for this particular case, as tracing can be disabled.


I think the same argument can be applied to patch #1 - it's hard to 
imaging anyone debugging an IOMMU driver on a system where a few hundred 
bytes makes the slightest bit of difference, and for people not 
debugging IOMMU drivers it should be moot (per the message itself).


Robin.
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH 16/18] iommu: remove DOMAIN_ATTR_DMA_USE_FLUSH_QUEUE

2021-04-01 Thread Christoph Hellwig
For now I'll just pass the iommu_domain to iommu_get_dma_strict,
so that we can check for it.  We can do additional cleanups on top
of that later.
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH 2/3] tracing: Use pr_crit() instead of long fancy messages

2021-04-01 Thread Geert Uytterhoeven
Hi Steven,

On Wed, Mar 31, 2021 at 3:40 PM Steven Rostedt  wrote:
> On Wed, 31 Mar 2021 11:31:03 +0200
> Geert Uytterhoeven  wrote:
>
> > This reduces kernel size by ca. 0.5 KiB.
>
> If you are worried about size, disable tracing and it will go away
> entirely. 0.5KiB is a drop in the bucket compared to what tracing adds in
> size overhead.

Fair enough for this particular case, as tracing can be disabled.

Gr{oetje,eeting}s,

Geert

-- 
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- ge...@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH v14 06/13] iommu/smmuv3: Allow stage 1 invalidation with unmanaged ASIDs

2021-04-01 Thread Auger Eric
Hi Zenghui,

On 3/30/21 11:17 AM, Zenghui Yu wrote:
> On 2021/2/24 4:56, Eric Auger wrote:
>> @@ -1936,7 +1950,12 @@ static void
>> arm_smmu_tlb_inv_range_domain(unsigned long iova, size_t size,
>>   },
>>   };
>>   -    if (smmu_domain->stage == ARM_SMMU_DOMAIN_S1) {
>> +    if (ext_asid >= 0) {  /* guest stage 1 invalidation */
>> +    cmd.opcode    = smmu_domain->smmu->features &
>> ARM_SMMU_FEAT_E2H ?
>> +  CMDQ_OP_TLBI_EL2_VA : CMDQ_OP_TLBI_NH_VA;
> 
> If I understand it correctly, the true nested mode effectively gives us
> a *NS-EL1* StreamWorld. We should therefore use CMDQ_OP_TLBI_NH_VA to
> invalidate the stage-1 NS-EL1 entries, no matter E2H is selected or not.
> 

Yes at the moment you're right. Support for nested virt may induce some
changes here but we are not there. I will fix it and add a comment.
Thank you!

Best Regards

Eric

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

Re: [PATCH 11/18] iommu/fsl_pamu: remove the snoop_id field

2021-04-01 Thread Christoph Hellwig
On Tue, Mar 30, 2021 at 01:58:17PM +0100, Will Deacon wrote:
> pamu_config_ppaace() takes quite a few useless parameters at this stage,
> but anyway:

I'll see it it makes sense to throw in another patch at the end to cut
it down a bit more.

> Acked-by: Will Deacon 
> 
> Do you know if this driver is actually useful? Once the complexity has been
> stripped back, the stubs and default values really stand out.

Yeah.  No idea what the usefulness of this driver is.  Bascially all it
seems to do is to setup a few registers to allow access to the whole
physical memory.  But maybe that is required on this hardware to allow
for any DMA access?
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH 08/18] iommu/fsl_pamu: merge pamu_set_liodn and map_liodn

2021-04-01 Thread Christoph Hellwig
On Tue, Mar 30, 2021 at 01:46:51PM +0100, Will Deacon wrote:
> > +   ret = pamu_config_ppaace(liodn, geom->aperture_start,
> > +geom->aperture_end - 1, ~(u32)0,
> > +0, dma_domain->snoop_id, dma_domain->stash_id,
> > +PAACE_AP_PERMS_QUERY | PAACE_AP_PERMS_UPDATE);
> 
> There's more '+1' / '-1' confusion here with aperture_end which I'm not
> managing to follow. What am I missing?

You did not missing anything, I messed this up.   Fixed.
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH 06/18] iommu/fsl_pamu: remove ->domain_window_enable

2021-04-01 Thread Christoph Hellwig
On Tue, Mar 30, 2021 at 01:40:09PM +0100, Will Deacon wrote:
> > +   ret = pamu_config_ppaace(liodn, geom->aperture_start,
> > +geom->aperture_end - 1, ~(u32)0,
> 
> You're passing 'geom->aperture_end - 1' as the size here, but the old code
> seemed to _add_ 1:
> 

> > -   win_size = (domain->geometry.aperture_end + 1) >> ilog2(1);
> 
> here ^^ when calculating the exclusive upper bound. In other words, I think
> '1ULL << 36' used to get passed to pamu_config_ppaace(). Is that an
> intentional change?

No, I've fixed it up.
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


  1   2   >