Re: [PATCH v2] drm/tegra: Stop using iommu_present()

2022-05-03 Thread Dmitry Osipenko
On 4/11/22 16:46, Robin Murphy wrote:
> @@ -1092,6 +1092,19 @@ static bool host1x_drm_wants_iommu(struct 
> host1x_device *dev)
>   struct host1x *host1x = dev_get_drvdata(dev->dev.parent);
>   struct iommu_domain *domain;
>  
> + /* For starters, this is moot if no IOMMU is available */
> + if (!device_iommu_mapped(>dev))
> + return false;

Unfortunately this returns false on T30 with enabled IOMMU because we
don't use IOMMU for Host1x on T30 [1] to optimize performance. We can't
change it until we will update drivers to support Host1x-dedicated buffers.

[1]
https://elixir.bootlin.com/linux/latest/source/drivers/gpu/host1x/dev.c#L258

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


[PATCH] iommu: iommu_group_claim_dma_owner() must always assign a domain

2022-05-03 Thread Jason Gunthorpe via iommu
Once the group enters 'owned' mode it can never be assigned back to the
default_domain or to a NULL domain. It must always be actively assigned to
a current domain. If the caller hasn't provided a domain then the core
must provide an explicit DMA blocking domain that has no DMA map.

Lazily create a group-global blocking DMA domain when
iommu_group_claim_dma_owner is first called and immediately assign the
group to it. This ensures that DMA is immediately fully isolated on all
IOMMU drivers.

If the user attaches/detaches while owned then detach will set the group
back to the blocking domain.

Slightly reorganize the call chains so that
__iommu_group_attach_core_domain() is the function that removes any caller
configured domain and sets the domains back a core owned domain with an
appropriate lifetime.

__iommu_group_attach_domain() is the worker function that can change the
domain assigned to a group to any target domain, including NULL.

Add comments clarifying how the NULL vs detach_dev vs default_domain works
based on Robin's remarks.

This fixes an oops with VFIO and SMMUv3 because VFIO will call
iommu_detach_group() and then immediately iommu_domain_free(), but
SMMUv3 has no way to know that the domain it is holding a pointer to
has been freed. Now the iommu_detach_group() will assign the blocking
domain and SMMUv3 will no longer hold a stale domain reference.

Fixes: 1ea2a07a532b ("iommu: Add DMA ownership management interfaces")
Reported-by: Qian Cai 
Signed-off-by: Robin Murphy 
Signed-off-by: Jason Gunthorpe 
---
 drivers/iommu/iommu.c | 112 +++---
 1 file changed, 82 insertions(+), 30 deletions(-)

This is based on Robins draft here:

https://lore.kernel.org/linux-iommu/18831161-473f-e04f-4a81-1c7062ad1...@arm.com/

With some rework. I re-organized the call chains instead of introducing
iommu_group_user_attached(), fixed a recursive locking for
iommu_group_get_purgatory(), and made a proper commit message.

Still only compile tested, so RFCish.

Nicolin/Lu? What do you think, can you check it?

Jason

diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 0c42ece2585406..94d99768023c94 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -44,6 +44,7 @@ struct iommu_group {
char *name;
int id;
struct iommu_domain *default_domain;
+   struct iommu_domain *blocking_domain;
struct iommu_domain *domain;
struct list_head entry;
unsigned int owner_cnt;
@@ -82,8 +83,7 @@ static int __iommu_attach_device(struct iommu_domain *domain,
 struct device *dev);
 static int __iommu_attach_group(struct iommu_domain *domain,
struct iommu_group *group);
-static void __iommu_detach_group(struct iommu_domain *domain,
-struct iommu_group *group);
+static void __iommu_group_attach_core_domain(struct iommu_group *group);
 static int iommu_create_device_direct_mappings(struct iommu_group *group,
   struct device *dev);
 static struct iommu_group *iommu_group_get_for_dev(struct device *dev);
@@ -596,6 +596,8 @@ static void iommu_group_release(struct kobject *kobj)
 
if (group->default_domain)
iommu_domain_free(group->default_domain);
+   if (group->blocking_domain)
+   iommu_domain_free(group->blocking_domain);
 
kfree(group->name);
kfree(group);
@@ -1979,12 +1981,10 @@ void iommu_detach_device(struct iommu_domain *domain, 
struct device *dev)
return;
 
mutex_lock(>mutex);
-   if (iommu_group_device_count(group) != 1) {
-   WARN_ON(1);
+   if (WARN_ON(domain != group->domain) ||
+   WARN_ON(iommu_group_device_count(group) != 1))
goto out_unlock;
-   }
-
-   __iommu_detach_group(domain, group);
+   __iommu_group_attach_core_domain(group);
 
 out_unlock:
mutex_unlock(>mutex);
@@ -2072,38 +2072,66 @@ static int iommu_group_do_detach_device(struct device 
*dev, void *data)
return 0;
 }
 
-static void __iommu_detach_group(struct iommu_domain *domain,
-struct iommu_group *group)
+static int __iommu_group_attach_domain(struct iommu_group *group,
+  struct iommu_domain *new_domain)
 {
int ret;
 
+   if (group->domain == new_domain)
+   return 0;
+
/*
-* If the group has been claimed already, do not re-attach the default
-* domain.
+* A NULL domain means to call the detach_dev() op. New drivers should
+* use a IOMMU_DOMAIN_IDENTITY domain instead of a NULL default_domain
+* and detatch_dev().
 */
-   if (!group->default_domain || group->owner) {
-   __iommu_group_for_each_dev(group, domain,
+   if (!new_domain) {
+   WARN_ON(!group->domain->ops->detach_dev);

[PATCH v2 01/26] dma-direct: take dma-ranges/offsets into account in resource mapping

2022-05-03 Thread Serge Semin
A basic device-specific linear memory mapping was introduced back in
commit ("dma: Take into account dma_pfn_offset") as a single-valued offset
preserved in the device.dma_pfn_offset field, which was initialized for
instance by means of the "dma-ranges" DT property. Afterwards the
functionality was extended to support more than one device-specific region
defined in the device.dma_range_map list of maps. But all of these
improvements concerned a single pointer, page or sg DMA-mapping methods,
while the system resource mapping function turned to miss the
corresponding modification. Thus the dma_direct_map_resource() method now
just casts the CPU physical address to the device DMA address with no
dma-ranges-based mapping taking into account, which is obviously wrong.
Let's fix it by using the phys_to_dma_direct() method to get the
device-specific bus address from the passed memory resource for the case
of the directly mapped DMA.

Fixes: 25f1e1887088 ("dma: Take into account dma_pfn_offset")
Signed-off-by: Serge Semin 
---
 kernel/dma/direct.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/kernel/dma/direct.c b/kernel/dma/direct.c
index 9743c6ccce1a..bc06db74dfdb 100644
--- a/kernel/dma/direct.c
+++ b/kernel/dma/direct.c
@@ -497,7 +497,7 @@ int dma_direct_map_sg(struct device *dev, struct 
scatterlist *sgl, int nents,
 dma_addr_t dma_direct_map_resource(struct device *dev, phys_addr_t paddr,
size_t size, enum dma_data_direction dir, unsigned long attrs)
 {
-   dma_addr_t dma_addr = paddr;
+   dma_addr_t dma_addr = phys_to_dma_direct(dev, paddr);
 
if (unlikely(!dma_capable(dev, dma_addr, size, false))) {
dev_err_once(dev,
-- 
2.35.1

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


Re: [PATCH v5 12/12] iommu: Rename iommu-sva-lib.{c,h}

2022-05-03 Thread Jean-Philippe Brucker
On Mon, May 02, 2022 at 09:48:42AM +0800, Lu Baolu wrote:
> Rename iommu-sva-lib.c[h] to iommu-sva.c[h] as it contains all code
> for SVA implementation in iommu core.
> 
> Signed-off-by: Lu Baolu 

Reviewed-by: Jean-Philippe Brucker 

> ---
>  drivers/iommu/{iommu-sva-lib.h => iommu-sva.h}  | 0
>  drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c | 2 +-
>  drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 2 +-
>  drivers/iommu/intel/iommu.c | 2 +-
>  drivers/iommu/intel/svm.c   | 2 +-
>  drivers/iommu/io-pgfault.c  | 2 +-
>  drivers/iommu/{iommu-sva-lib.c => iommu-sva.c}  | 2 +-
>  drivers/iommu/Makefile  | 2 +-
>  8 files changed, 7 insertions(+), 7 deletions(-)
>  rename drivers/iommu/{iommu-sva-lib.h => iommu-sva.h} (100%)
>  rename drivers/iommu/{iommu-sva-lib.c => iommu-sva.c} (99%)
> 
> diff --git a/drivers/iommu/iommu-sva-lib.h b/drivers/iommu/iommu-sva.h
> similarity index 100%
> rename from drivers/iommu/iommu-sva-lib.h
> rename to drivers/iommu/iommu-sva.h
> diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c 
> b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
> index 0ace04b27d4b..73a336e17dc8 100644
> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
> @@ -9,7 +9,7 @@
>  #include 
>  
>  #include "arm-smmu-v3.h"
> -#include "../../iommu-sva-lib.h"
> +#include "../../iommu-sva.h"
>  #include "../../io-pgtable-arm.h"
>  
>  struct arm_smmu_mmu_notifier {
> 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 543d3ef1c102..ca2bd17eec41 100644
> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> @@ -31,7 +31,7 @@
>  #include 
>  
>  #include "arm-smmu-v3.h"
> -#include "../../iommu-sva-lib.h"
> +#include "../../iommu-sva.h"
>  
>  static bool disable_bypass = true;
>  module_param(disable_bypass, bool, 0444);
> diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
> index 46e2eb15197b..b38f50810459 100644
> --- a/drivers/iommu/intel/iommu.c
> +++ b/drivers/iommu/intel/iommu.c
> @@ -27,7 +27,7 @@
>  #include 
>  
>  #include "../irq_remapping.h"
> -#include "../iommu-sva-lib.h"
> +#include "../iommu-sva.h"
>  #include "pasid.h"
>  #include "cap_audit.h"
>  
> diff --git a/drivers/iommu/intel/svm.c b/drivers/iommu/intel/svm.c
> index 6084f960ba27..38c33cde177e 100644
> --- a/drivers/iommu/intel/svm.c
> +++ b/drivers/iommu/intel/svm.c
> @@ -25,7 +25,7 @@
>  
>  #include "pasid.h"
>  #include "perf.h"
> -#include "../iommu-sva-lib.h"
> +#include "../iommu-sva.h"
>  
>  static irqreturn_t prq_event_thread(int irq, void *d);
>  static void intel_svm_drain_prq(struct device *dev, u32 pasid);
> diff --git a/drivers/iommu/io-pgfault.c b/drivers/iommu/io-pgfault.c
> index 8a2bb56e1474..a9ecf6bf5500 100644
> --- a/drivers/iommu/io-pgfault.c
> +++ b/drivers/iommu/io-pgfault.c
> @@ -11,7 +11,7 @@
>  #include 
>  #include 
>  
> -#include "iommu-sva-lib.h"
> +#include "iommu-sva.h"
>  
>  /**
>   * struct iopf_queue - IO Page Fault queue
> diff --git a/drivers/iommu/iommu-sva-lib.c b/drivers/iommu/iommu-sva.c
> similarity index 99%
> rename from drivers/iommu/iommu-sva-lib.c
> rename to drivers/iommu/iommu-sva.c
> index ae3595d60f38..b631765fa8c0 100644
> --- a/drivers/iommu/iommu-sva-lib.c
> +++ b/drivers/iommu/iommu-sva.c
> @@ -7,7 +7,7 @@
>  #include 
>  #include 
>  
> -#include "iommu-sva-lib.h"
> +#include "iommu-sva.h"
>  
>  static DEFINE_MUTEX(iommu_sva_lock);
>  static DECLARE_IOASID_SET(iommu_sva_pasid);
> diff --git a/drivers/iommu/Makefile b/drivers/iommu/Makefile
> index 44475a9b3eea..c1763476162b 100644
> --- a/drivers/iommu/Makefile
> +++ b/drivers/iommu/Makefile
> @@ -27,6 +27,6 @@ obj-$(CONFIG_FSL_PAMU) += fsl_pamu.o fsl_pamu_domain.o
>  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) += iommu-sva-lib.o io-pgfault.o
> +obj-$(CONFIG_IOMMU_SVA) += iommu-sva.o io-pgfault.o
>  obj-$(CONFIG_SPRD_IOMMU) += sprd-iommu.o
>  obj-$(CONFIG_APPLE_DART) += apple-dart.o
> -- 
> 2.25.1
> 
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH v5 11/12] iommu: Per-domain I/O page fault handling

2022-05-03 Thread Jean-Philippe Brucker
On Mon, May 02, 2022 at 09:48:41AM +0800, Lu Baolu wrote:
> Tweak the I/O page fault handling framework to route the page faults to
> the domain and call the page fault handler retrieved from the domain.
> This makes the I/O page fault handling framework possible to serve more
> usage scenarios as long as they have an IOMMU domain and install a page
> fault handler in it. Some unused functions are also removed to avoid
> dead code.
> 
> Signed-off-by: Lu Baolu 

Reviewed-by: Jean-Philippe Brucker 

> ---
>  drivers/iommu/iommu-sva-lib.h |  1 -
>  drivers/iommu/io-pgfault.c| 64 ---
>  drivers/iommu/iommu-sva-lib.c | 20 ---
>  3 files changed, 7 insertions(+), 78 deletions(-)
> 
> diff --git a/drivers/iommu/iommu-sva-lib.h b/drivers/iommu/iommu-sva-lib.h
> index 5776b4c80cc1..e7813c6706fb 100644
> --- a/drivers/iommu/iommu-sva-lib.h
> +++ b/drivers/iommu/iommu-sva-lib.h
> @@ -8,7 +8,6 @@
>  #include 
>  #include 
>  
> -struct mm_struct *iommu_sva_find(ioasid_t pasid);
>  struct mm_struct *iommu_sva_domain_mm(struct iommu_domain *domain);
>  
>  /* I/O Page fault */
> diff --git a/drivers/iommu/io-pgfault.c b/drivers/iommu/io-pgfault.c
> index 1df8c1dcae77..8a2bb56e1474 100644
> --- a/drivers/iommu/io-pgfault.c
> +++ b/drivers/iommu/io-pgfault.c
> @@ -69,69 +69,18 @@ static int iopf_complete_group(struct device *dev, struct 
> iopf_fault *iopf,
>   return iommu_page_response(dev, );
>  }
>  
> -static enum iommu_page_response_code
> -iopf_handle_single(struct iopf_fault *iopf)
> -{
> - vm_fault_t ret;
> - struct mm_struct *mm;
> - struct vm_area_struct *vma;
> - unsigned int access_flags = 0;
> - unsigned int fault_flags = FAULT_FLAG_REMOTE;
> - struct iommu_fault_page_request *prm = >fault.prm;
> - enum iommu_page_response_code status = IOMMU_PAGE_RESP_INVALID;
> -
> - if (!(prm->flags & IOMMU_FAULT_PAGE_REQUEST_PASID_VALID))
> - return status;
> -
> - mm = iommu_sva_find(prm->pasid);
> - if (IS_ERR_OR_NULL(mm))
> - return status;
> -
> - mmap_read_lock(mm);
> -
> - vma = find_extend_vma(mm, prm->addr);
> - if (!vma)
> - /* Unmapped area */
> - goto out_put_mm;
> -
> - if (prm->perm & IOMMU_FAULT_PERM_READ)
> - access_flags |= VM_READ;
> -
> - if (prm->perm & IOMMU_FAULT_PERM_WRITE) {
> - access_flags |= VM_WRITE;
> - fault_flags |= FAULT_FLAG_WRITE;
> - }
> -
> - if (prm->perm & IOMMU_FAULT_PERM_EXEC) {
> - access_flags |= VM_EXEC;
> - fault_flags |= FAULT_FLAG_INSTRUCTION;
> - }
> -
> - if (!(prm->perm & IOMMU_FAULT_PERM_PRIV))
> - fault_flags |= FAULT_FLAG_USER;
> -
> - if (access_flags & ~vma->vm_flags)
> - /* Access fault */
> - goto out_put_mm;
> -
> - ret = handle_mm_fault(vma, prm->addr, fault_flags, NULL);
> - status = ret & VM_FAULT_ERROR ? IOMMU_PAGE_RESP_INVALID :
> - IOMMU_PAGE_RESP_SUCCESS;
> -
> -out_put_mm:
> - mmap_read_unlock(mm);
> - mmput(mm);
> -
> - return status;
> -}
> -
>  static void iopf_handle_group(struct work_struct *work)
>  {
>   struct iopf_group *group;
> + struct iommu_domain *domain;
>   struct iopf_fault *iopf, *next;
>   enum iommu_page_response_code status = IOMMU_PAGE_RESP_SUCCESS;
>  
>   group = container_of(work, struct iopf_group, work);
> + domain = iommu_get_domain_for_dev_pasid(group->dev,
> + group->last_fault.fault.prm.pasid);
> + if (!domain || !domain->iopf_handler)
> + status = IOMMU_PAGE_RESP_INVALID;
>  
>   list_for_each_entry_safe(iopf, next, >faults, list) {
>   /*
> @@ -139,7 +88,8 @@ static void iopf_handle_group(struct work_struct *work)
>* faults in the group if there is an error.
>*/
>   if (status == IOMMU_PAGE_RESP_SUCCESS)
> - status = iopf_handle_single(iopf);
> + status = domain->iopf_handler(>fault,
> +   domain->fault_data);
>  
>   if (!(iopf->fault.prm.flags &
> IOMMU_FAULT_PAGE_REQUEST_LAST_PAGE))
> diff --git a/drivers/iommu/iommu-sva-lib.c b/drivers/iommu/iommu-sva-lib.c
> index 05a7d2f0e46f..ae3595d60f38 100644
> --- a/drivers/iommu/iommu-sva-lib.c
> +++ b/drivers/iommu/iommu-sva-lib.c
> @@ -69,26 +69,6 @@ static int iommu_sva_alloc_pasid(struct mm_struct *mm,
>   return ret;
>  }
>  
> -/* ioasid_find getter() requires a void * argument */
> -static bool __mmget_not_zero(void *mm)
> -{
> - return mmget_not_zero(mm);
> -}
> -
> -/**
> - * iommu_sva_find() - Find mm associated to the given PASID
> - * @pasid: Process Address Space ID assigned to the mm
> - *
> - * On success a reference to the mm is taken, and must be released with 
> mmput().
> - *
> - * Returns the mm corresponding to this 

Re: [PATCH v5 10/12] iommu: Prepare IOMMU domain for IOPF

2022-05-03 Thread Jean-Philippe Brucker
On Mon, May 02, 2022 at 09:48:40AM +0800, Lu Baolu wrote:
> This adds some mechanisms around the iommu_domain so that the I/O page
> fault handling framework could route a page fault to the domain and
> call the fault handler from it.
> 
> Add pointers to the page fault handler and its private data in struct
> iommu_domain. The fault handler will be called with the private data
> as a parameter once a page fault is routed to the domain. Any kernel
> component which owns an iommu domain could install handler and its
> private parameter so that the page fault could be further routed and
> handled.
> 
> A new helper iommu_get_domain_for_dev_pasid() which retrieves attached
> domain for a {device, PASID} is added. It will be used by the page fault
> handling framework which knows {device, PASID} reported from the iommu
> driver. We have a guarantee that the SVA domain doesn't go away during
> IOPF handling, because unbind() waits for pending faults with
> iopf_queue_flush_dev() before freeing the domain. Hence, there's no need
> to synchronize life cycle of the iommu domains between the unbind() and
> the interrupt threads.
> 
> This also prepares the SVA implementation to be the first consumer of
> the per-domain page fault handling model.
> 
> Signed-off-by: Lu Baolu 
> ---
>  include/linux/iommu.h | 12 +++
>  drivers/iommu/iommu-sva-lib.c | 65 +++
>  drivers/iommu/iommu.c | 21 +++
>  3 files changed, 98 insertions(+)
> 
> diff --git a/include/linux/iommu.h b/include/linux/iommu.h
> index 19718939d9df..1164524814cb 100644
> --- a/include/linux/iommu.h
> +++ b/include/linux/iommu.h
> @@ -102,6 +102,9 @@ struct iommu_domain {
>   struct iommu_domain_geometry geometry;
>   struct iommu_dma_cookie *iova_cookie;
>   struct iommu_sva_ioas *sva_ioas;
> + enum iommu_page_response_code (*iopf_handler)(struct iommu_fault *fault,
> +   void *data);
> + void *fault_data;
>  };
>  
>  static inline bool iommu_is_dma_domain(struct iommu_domain *domain)
> @@ -686,6 +689,9 @@ int iommu_attach_device_pasid(struct iommu_domain *domain,
> struct device *dev, ioasid_t pasid);
>  void iommu_detach_device_pasid(struct iommu_domain *domain,
>  struct device *dev, ioasid_t pasid);
> +struct iommu_domain *
> +iommu_get_domain_for_dev_pasid(struct device *dev, ioasid_t pasid);
> +
>  #else /* CONFIG_IOMMU_API */
>  
>  struct iommu_ops {};
> @@ -1055,6 +1061,12 @@ static inline void iommu_detach_device_pasid(struct 
> iommu_domain *domain,
>struct device *dev, ioasid_t pasid)
>  {
>  }
> +
> +static inline struct iommu_domain *
> +iommu_get_domain_for_dev_pasid(struct device *dev, ioasid_t pasid)
> +{
> + return NULL;
> +}
>  #endif /* CONFIG_IOMMU_API */
>  
>  #ifdef CONFIG_IOMMU_SVA
> diff --git a/drivers/iommu/iommu-sva-lib.c b/drivers/iommu/iommu-sva-lib.c
> index 992388106da0..05a7d2f0e46f 100644
> --- a/drivers/iommu/iommu-sva-lib.c
> +++ b/drivers/iommu/iommu-sva-lib.c
> @@ -135,6 +135,69 @@ static void iommu_sva_ioas_put(struct iommu_sva_ioas 
> *ioas)
>   }
>  }
>  
> +/*
> + * I/O page fault handler for SVA
> + *
> + * Copied from io-pgfault.c with mmget_not_zero() added before
> + * mmap_read_lock().
> + */
> +static enum iommu_page_response_code
> +iommu_sva_handle_iopf(struct iommu_fault *fault, void *data)
> +{
> + vm_fault_t ret;
> + struct mm_struct *mm;
> + struct vm_area_struct *vma;
> + unsigned int access_flags = 0;
> + struct iommu_domain *domain = data;
> + unsigned int fault_flags = FAULT_FLAG_REMOTE;
> + struct iommu_fault_page_request *prm = >prm;
> + enum iommu_page_response_code status = IOMMU_PAGE_RESP_INVALID;
> +
> + if (!(prm->flags & IOMMU_FAULT_PAGE_REQUEST_PASID_VALID))
> + return status;
> +
> + mm = iommu_sva_domain_mm(domain);
> + if (IS_ERR_OR_NULL(mm) || !mmget_not_zero(mm))
> + return status;
> +
> + mmap_read_lock(mm);
> +
> + vma = find_extend_vma(mm, prm->addr);
> + if (!vma)
> + /* Unmapped area */
> + goto out_put_mm;
> +
> + if (prm->perm & IOMMU_FAULT_PERM_READ)
> + access_flags |= VM_READ;
> +
> + if (prm->perm & IOMMU_FAULT_PERM_WRITE) {
> + access_flags |= VM_WRITE;
> + fault_flags |= FAULT_FLAG_WRITE;
> + }
> +
> + if (prm->perm & IOMMU_FAULT_PERM_EXEC) {
> + access_flags |= VM_EXEC;
> + fault_flags |= FAULT_FLAG_INSTRUCTION;
> + }
> +
> + if (!(prm->perm & IOMMU_FAULT_PERM_PRIV))
> + fault_flags |= FAULT_FLAG_USER;
> +
> + if (access_flags & ~vma->vm_flags)
> + /* Access fault */
> + goto out_put_mm;
> +
> + ret = handle_mm_fault(vma, prm->addr, fault_flags, NULL);
> + status = ret & VM_FAULT_ERROR ? 

Re: [PATCH v5 09/12] iommu: Remove SVA related callbacks from iommu ops

2022-05-03 Thread Jean-Philippe Brucker
On Mon, May 02, 2022 at 09:48:39AM +0800, Lu Baolu wrote:
> These ops'es have been replaced with the dev_attach/detach_pasid domain
> ops'es. There's no need for them anymore. Remove them to avoid dead
> code.
> 
> Signed-off-by: Lu Baolu 

Reviewed-by: Jean-Philippe Brucker 

> ---
>  include/linux/intel-iommu.h   |  4 --
>  include/linux/iommu.h |  8 ---
>  drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h   | 17 ---
>  drivers/iommu/iommu-sva-lib.h |  1 -
>  .../iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c   | 41 
>  drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c   |  3 --
>  drivers/iommu/intel/iommu.c   |  3 --
>  drivers/iommu/intel/svm.c | 49 ---
>  drivers/iommu/iommu-sva-lib.c |  4 +-
>  9 files changed, 2 insertions(+), 128 deletions(-)
> 
> diff --git a/include/linux/intel-iommu.h b/include/linux/intel-iommu.h
> index 3b4ca16f53e2..5af24befc9f1 100644
> --- a/include/linux/intel-iommu.h
> +++ b/include/linux/intel-iommu.h
> @@ -738,10 +738,6 @@ struct intel_iommu *device_to_iommu(struct device *dev, 
> u8 *bus, u8 *devfn);
>  extern void intel_svm_check(struct intel_iommu *iommu);
>  extern int intel_svm_enable_prq(struct intel_iommu *iommu);
>  extern int intel_svm_finish_prq(struct intel_iommu *iommu);
> -struct iommu_sva *intel_svm_bind(struct device *dev, struct mm_struct *mm,
> -  void *drvdata);
> -void intel_svm_unbind(struct iommu_sva *handle);
> -u32 intel_svm_get_pasid(struct iommu_sva *handle);
>  int intel_svm_page_response(struct device *dev, struct iommu_fault_event 
> *evt,
>   struct iommu_page_response *msg);
>  extern const struct iommu_domain_ops intel_svm_domain_ops;
> diff --git a/include/linux/iommu.h b/include/linux/iommu.h
> index c5a16b47cae8..19718939d9df 100644
> --- a/include/linux/iommu.h
> +++ b/include/linux/iommu.h
> @@ -214,9 +214,6 @@ struct iommu_iotlb_gather {
>   * @dev_has/enable/disable_feat: per device entries to check/enable/disable
>   *   iommu specific features.
>   * @dev_feat_enabled: check enabled feature
> - * @sva_bind: Bind process address space to device
> - * @sva_unbind: Unbind process address space from device
> - * @sva_get_pasid: Get PASID associated to a SVA handle
>   * @page_response: handle page request response
>   * @def_domain_type: device default domain type, return value:
>   *   - IOMMU_DOMAIN_IDENTITY: must use an identity domain
> @@ -250,11 +247,6 @@ struct iommu_ops {
>   int (*dev_enable_feat)(struct device *dev, enum iommu_dev_features f);
>   int (*dev_disable_feat)(struct device *dev, enum iommu_dev_features f);
>  
> - struct iommu_sva *(*sva_bind)(struct device *dev, struct mm_struct *mm,
> -   void *drvdata);
> - void (*sva_unbind)(struct iommu_sva *handle);
> - u32 (*sva_get_pasid)(struct iommu_sva *handle);
> -
>   int (*page_response)(struct device *dev,
>struct iommu_fault_event *evt,
>struct iommu_page_response *msg);
> 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 7631c00fdcbd..2513309ec0db 100644
> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
> @@ -754,10 +754,6 @@ 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,
> - void *drvdata);
> -void arm_smmu_sva_unbind(struct iommu_sva *handle);
> -u32 arm_smmu_sva_get_pasid(struct iommu_sva *handle);
>  void arm_smmu_sva_notifier_synchronize(void);
>  int arm_smmu_sva_attach_dev_pasid(struct iommu_domain *domain,
> struct device *dev, ioasid_t id);
> @@ -794,19 +790,6 @@ static inline bool arm_smmu_master_iopf_supported(struct 
> arm_smmu_master *master
>   return false;
>  }
>  
> -static inline struct iommu_sva *
> -arm_smmu_sva_bind(struct device *dev, struct mm_struct *mm, void *drvdata)
> -{
> - return ERR_PTR(-ENODEV);
> -}
> -
> -static inline void arm_smmu_sva_unbind(struct iommu_sva *handle) {}
> -
> -static inline u32 arm_smmu_sva_get_pasid(struct iommu_sva *handle)
> -{
> - return IOMMU_PASID_INVALID;
> -}
> -
>  static inline void arm_smmu_sva_notifier_synchronize(void) {}
>  
>  static inline int arm_smmu_sva_attach_dev_pasid(struct iommu_domain *domain,
> diff --git a/drivers/iommu/iommu-sva-lib.h b/drivers/iommu/iommu-sva-lib.h
> index 9c5e108e2c8a..5776b4c80cc1 100644
> --- a/drivers/iommu/iommu-sva-lib.h
> +++ 

Re: [PATCH v5 07/12] arm-smmu-v3/sva: Add SVA domain support

2022-05-03 Thread Jean-Philippe Brucker
On Mon, May 02, 2022 at 09:48:37AM +0800, Lu Baolu wrote:
> Add support for SVA domain allocation and provide an SVA-specific
> iommu_domain_ops.
> 
> Signed-off-by: Lu Baolu 
> ---
>  drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h   | 14 +++
>  .../iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c   | 42 +++
>  drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c   | 21 ++
>  3 files changed, 77 insertions(+)
> 
> 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 cd48590ada30..7631c00fdcbd 100644
> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
> @@ -759,6 +759,10 @@ struct iommu_sva *arm_smmu_sva_bind(struct device *dev, 
> struct mm_struct *mm,
>  void arm_smmu_sva_unbind(struct iommu_sva *handle);
>  u32 arm_smmu_sva_get_pasid(struct iommu_sva *handle);
>  void arm_smmu_sva_notifier_synchronize(void);
> +int arm_smmu_sva_attach_dev_pasid(struct iommu_domain *domain,
> +   struct device *dev, ioasid_t id);
> +void arm_smmu_sva_detach_dev_pasid(struct iommu_domain *domain,
> +struct device *dev, ioasid_t id);
>  #else /* CONFIG_ARM_SMMU_V3_SVA */
>  static inline bool arm_smmu_sva_supported(struct arm_smmu_device *smmu)
>  {
> @@ -804,5 +808,15 @@ static inline u32 arm_smmu_sva_get_pasid(struct 
> iommu_sva *handle)
>  }
>  
>  static inline void arm_smmu_sva_notifier_synchronize(void) {}
> +
> +static inline int arm_smmu_sva_attach_dev_pasid(struct iommu_domain *domain,
> + struct device *dev, ioasid_t id)
> +{
> + return -ENODEV;
> +}
> +
> +static inline void arm_smmu_sva_detach_dev_pasid(struct iommu_domain *domain,
> +  struct device *dev,
> +  ioasid_t id) {}
>  #endif /* CONFIG_ARM_SMMU_V3_SVA */
>  #endif /* _ARM_SMMU_V3_H */
> diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c 
> b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
> index c623dae1e115..3b843cd3ed67 100644
> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
> @@ -541,3 +541,45 @@ void arm_smmu_sva_notifier_synchronize(void)
>*/
>   mmu_notifier_synchronize();
>  }
> +
> +int arm_smmu_sva_attach_dev_pasid(struct iommu_domain *domain,
> +   struct device *dev, ioasid_t id)
> +{
> + int ret = 0;
> + struct iommu_sva *handle;
> + struct mm_struct *mm = iommu_sva_domain_mm(domain);
> +
> + if (domain->type != IOMMU_DOMAIN_SVA || !mm)

We wouldn't get that far with a non-SVA domain since iommu_sva_domain_mm()
would dereference a NULL pointer. Could you move it after the domain->type
check, and maybe add a WARN_ON()?  It could help catch issues in future
API changes.

> + return -EINVAL;
> +
> + mutex_lock(_lock);
> + handle = __arm_smmu_sva_bind(dev, mm);
> + if (IS_ERR(handle))
> + ret = PTR_ERR(handle);
> + mutex_unlock(_lock);
> +
> + return ret;
> +}
> +
> +void arm_smmu_sva_detach_dev_pasid(struct iommu_domain *domain,
> +struct device *dev, ioasid_t id)
> +{
> + struct arm_smmu_bond *bond = NULL, *t;
> + struct mm_struct *mm = iommu_sva_domain_mm(domain);
> + struct arm_smmu_master *master = dev_iommu_priv_get(dev);
> +
> + mutex_lock(_lock);
> + list_for_each_entry(t, >bonds, list) {
> + if (t->mm == mm) {
> + bond = t;
> + break;
> + }
> + }
> +
> + if (!WARN_ON(!bond) && refcount_dec_and_test(>refs)) {
> + list_del(>list);
> + arm_smmu_mmu_notifier_put(bond->smmu_mn);
> + kfree(bond);
> + }
> + mutex_unlock(_lock);
> +}
> 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 afc63fce6107..bd80de0bad98 100644
> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> @@ -1995,10 +1995,31 @@ static bool arm_smmu_capable(enum iommu_cap cap)
>   }
>  }
>  
> +static void arm_smmu_sva_domain_free(struct iommu_domain *domain)
> +{
> + kfree(domain);
> +}
> +
> +static const struct iommu_domain_ops arm_smmu_sva_domain_ops = {
> + .attach_dev_pasid   = arm_smmu_sva_attach_dev_pasid,
> + .detach_dev_pasid   = arm_smmu_sva_detach_dev_pasid,
> + .free   = arm_smmu_sva_domain_free,
> +};
> +
>  static struct iommu_domain *arm_smmu_domain_alloc(unsigned type)
>  {
>   struct arm_smmu_domain *smmu_domain;
>  
> + if (type == IOMMU_DOMAIN_SVA) {
> + struct iommu_domain *domain;
> +
> + domain = kzalloc(sizeof(*domain), GFP_KERNEL);
> + if (domain)
> + domain->ops = 

Re: [PATCH v5 04/12] iommu/sva: Basic data structures for SVA

2022-05-03 Thread Jean-Philippe Brucker
On Mon, May 02, 2022 at 09:48:34AM +0800, Lu Baolu wrote:
> Use below data structures for SVA implementation in the IOMMU core:
> 
> - struct iommu_sva_ioas
>   Represent the I/O address space shared with an application CPU address
>   space. This structure has a 1:1 relationship with an mm_struct. It
>   grabs a "mm->mm_count" refcount during creation and drop it on release.

Do we actually need this structure?  At the moment it only keeps track of
bonds, which we can move to struct dev_iommu. Replacing it by a mm pointer
in struct iommu_domain simplifies the driver and seems to work

Thanks,
Jean

> 
> - struct iommu_domain (IOMMU_DOMAIN_SVA type)
>   Represent a hardware pagetable that the IOMMU hardware could use for
>   SVA translation. Multiple iommu domains could be bound with an SVA ioas
>   and each grabs a refcount from ioas in order to make sure ioas could
>   only be freed after all domains have been unbound.
> 
> - struct iommu_sva
>   Represent a bond relationship between an SVA ioas and an iommu domain.
>   If a bond already exists, it's reused and a reference is taken.
> 
> Signed-off-by: Lu Baolu 
> ---
>  include/linux/iommu.h | 14 +-
>  drivers/iommu/iommu-sva-lib.h |  1 +
>  drivers/iommu/iommu-sva-lib.c | 18 ++
>  3 files changed, 32 insertions(+), 1 deletion(-)
> 
> diff --git a/include/linux/iommu.h b/include/linux/iommu.h
> index ab36244d4e94..f582f434c513 100644
> --- a/include/linux/iommu.h
> +++ b/include/linux/iommu.h
> @@ -42,6 +42,7 @@ struct notifier_block;
>  struct iommu_sva;
>  struct iommu_fault_event;
>  struct iommu_dma_cookie;
> +struct iommu_sva_ioas;
>  
>  /* iommu fault flags */
>  #define IOMMU_FAULT_READ 0x0
> @@ -64,6 +65,9 @@ struct iommu_domain_geometry {
>  #define __IOMMU_DOMAIN_PT(1U << 2)  /* Domain is identity mapped   */
>  #define __IOMMU_DOMAIN_DMA_FQ(1U << 3)  /* DMA-API uses flush queue  
>   */
>  
> +#define __IOMMU_DOMAIN_SHARED(1U << 4)  /* Page table shared from 
> CPU  */
> +#define __IOMMU_DOMAIN_HOST_VA   (1U << 5)  /* Host CPU virtual address 
> */
> +
>  /*
>   * This are the possible domain-types
>   *
> @@ -86,6 +90,8 @@ struct iommu_domain_geometry {
>  #define IOMMU_DOMAIN_DMA_FQ  (__IOMMU_DOMAIN_PAGING |\
>__IOMMU_DOMAIN_DMA_API |   \
>__IOMMU_DOMAIN_DMA_FQ)
> +#define IOMMU_DOMAIN_SVA (__IOMMU_DOMAIN_SHARED |\
> +  __IOMMU_DOMAIN_HOST_VA)
>  
>  struct iommu_domain {
>   unsigned type;
> @@ -95,6 +101,7 @@ struct iommu_domain {
>   void *handler_token;
>   struct iommu_domain_geometry geometry;
>   struct iommu_dma_cookie *iova_cookie;
> + struct iommu_sva_ioas *sva_ioas;
>  };
>  
>  static inline bool iommu_is_dma_domain(struct iommu_domain *domain)
> @@ -628,7 +635,12 @@ struct iommu_fwspec {
>   * struct iommu_sva - handle to a device-mm bond
>   */
>  struct iommu_sva {
> - struct device   *dev;
> + struct device   *dev;
> + struct iommu_sva_ioas   *sva_ioas;
> + struct iommu_domain *domain;
> + /* Link to sva ioas's bonds list */
> + struct list_headnode;
> + refcount_t  users;
>  };
>  
>  int iommu_fwspec_init(struct device *dev, struct fwnode_handle *iommu_fwnode,
> diff --git a/drivers/iommu/iommu-sva-lib.h b/drivers/iommu/iommu-sva-lib.h
> index 8909ea1094e3..9c5e108e2c8a 100644
> --- a/drivers/iommu/iommu-sva-lib.h
> +++ b/drivers/iommu/iommu-sva-lib.h
> @@ -10,6 +10,7 @@
>  
>  int iommu_sva_alloc_pasid(struct mm_struct *mm, ioasid_t min, ioasid_t max);
>  struct mm_struct *iommu_sva_find(ioasid_t pasid);
> +struct mm_struct *iommu_sva_domain_mm(struct iommu_domain *domain);
>  
>  /* I/O Page fault */
>  struct device;
> diff --git a/drivers/iommu/iommu-sva-lib.c b/drivers/iommu/iommu-sva-lib.c
> index 106506143896..d524a402be3b 100644
> --- a/drivers/iommu/iommu-sva-lib.c
> +++ b/drivers/iommu/iommu-sva-lib.c
> @@ -3,6 +3,8 @@
>   * Helpers for IOMMU drivers implementing SVA
>   */
>  #include 
> +#include 
> +#include 
>  #include 
>  
>  #include "iommu-sva-lib.h"
> @@ -10,6 +12,22 @@
>  static DEFINE_MUTEX(iommu_sva_lock);
>  static DECLARE_IOASID_SET(iommu_sva_pasid);
>  
> +struct iommu_sva_ioas {
> + struct mm_struct *mm;
> + ioasid_t pasid;
> +
> + /* Counter of domains attached to this ioas. */
> + refcount_t users;
> +
> + /* All bindings are linked here. */
> + struct list_head bonds;
> +};
> +
> +struct mm_struct *iommu_sva_domain_mm(struct iommu_domain *domain)
> +{
> + return domain->sva_ioas->mm;
> +}
> +
>  /**
>   * iommu_sva_alloc_pasid - Allocate a PASID for the mm
>   * @mm: the mm
> -- 
> 2.25.1
> 
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH v5 03/12] iommu: Add attach/detach_dev_pasid domain ops

2022-05-03 Thread Jean-Philippe Brucker
On Mon, May 02, 2022 at 09:48:33AM +0800, Lu Baolu wrote:
> Attaching an IOMMU domain to a PASID of a device is a generic operation
> for modern IOMMU drivers which support PASID-granular DMA address
> translation. Currently visible usage scenarios include (but not limited):
> 
>  - SVA (Shared Virtual Address)
>  - kernel DMA with PASID
>  - hardware-assist mediated device
> 
> This adds a pair of common domain ops for this purpose and adds helpers
> to attach/detach a domain to/from a {device, PASID}. Some buses, like
> PCI, route packets without considering the PASID value. Thus a DMA target
> address with PASID might be treated as P2P if the address falls into the
> MMIO BAR of other devices in the group. To make things simple, these
> interfaces only apply to devices belonging to the singleton groups, and
> the singleton is immutable in fabric i.e. not affected by hotplug.
> 
> Signed-off-by: Lu Baolu 

Reviewed-by: Jean-Philippe Brucker 

just a nit below

> ---
>  include/linux/iommu.h | 21 
>  drivers/iommu/iommu.c | 76 +++
>  2 files changed, 97 insertions(+)
> 
> diff --git a/include/linux/iommu.h b/include/linux/iommu.h
> index b8ffaf2cb1d0..ab36244d4e94 100644
> --- a/include/linux/iommu.h
> +++ b/include/linux/iommu.h
> @@ -263,6 +263,8 @@ struct iommu_ops {
>   * struct iommu_domain_ops - domain specific operations
>   * @attach_dev: attach an iommu domain to a device
>   * @detach_dev: detach an iommu domain from a device
> + * @attach_dev_pasid: attach an iommu domain to a pasid of device
> + * @detach_dev_pasid: detach an iommu domain from a pasid of device
>   * @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.
> @@ -283,6 +285,10 @@ struct iommu_ops {
>  struct iommu_domain_ops {
>   int (*attach_dev)(struct iommu_domain *domain, struct device *dev);
>   void (*detach_dev)(struct iommu_domain *domain, struct device *dev);
> + int (*attach_dev_pasid)(struct iommu_domain *domain,
> + struct device *dev, ioasid_t pasid);
> + void (*detach_dev_pasid)(struct iommu_domain *domain,
> +  struct device *dev, ioasid_t pasid);
>  
>   int (*map)(struct iommu_domain *domain, unsigned long iova,
>  phys_addr_t paddr, size_t size, int prot, gfp_t gfp);
> @@ -678,6 +684,10 @@ int iommu_group_claim_dma_owner(struct iommu_group 
> *group, void *owner);
>  void iommu_group_release_dma_owner(struct iommu_group *group);
>  bool iommu_group_dma_owner_claimed(struct iommu_group *group);
>  
> +int iommu_attach_device_pasid(struct iommu_domain *domain,
> +   struct device *dev, ioasid_t pasid);
> +void iommu_detach_device_pasid(struct iommu_domain *domain,
> +struct device *dev, ioasid_t pasid);
>  #else /* CONFIG_IOMMU_API */
>  
>  struct iommu_ops {};
> @@ -1051,6 +1061,17 @@ static inline bool 
> iommu_group_dma_owner_claimed(struct iommu_group *group)
>  {
>   return false;
>  }
> +
> +static inline int iommu_attach_device_pasid(struct iommu_domain *domain,
> + struct device *dev, ioasid_t pasid)
> +{
> + return -ENODEV;
> +}
> +
> +static inline void iommu_detach_device_pasid(struct iommu_domain *domain,
> +  struct device *dev, ioasid_t pasid)
> +{
> +}
>  #endif /* CONFIG_IOMMU_API */
>  
>  /**
> diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
> index 29906bc16371..89c9d19ddb28 100644
> --- a/drivers/iommu/iommu.c
> +++ b/drivers/iommu/iommu.c
> @@ -38,6 +38,7 @@ struct iommu_group {
>   struct kobject kobj;
>   struct kobject *devices_kobj;
>   struct list_head devices;
> + struct xarray pasid_array;
>   struct mutex mutex;
>   void *iommu_data;
>   void (*iommu_data_release)(void *iommu_data);
> @@ -630,6 +631,7 @@ struct iommu_group *iommu_group_alloc(void)
>   mutex_init(>mutex);
>   INIT_LIST_HEAD(>devices);
>   INIT_LIST_HEAD(>entry);
> + xa_init(>pasid_array);
>  
>   ret = ida_simple_get(_group_ida, 0, 0, GFP_KERNEL);
>   if (ret < 0) {
> @@ -3190,3 +3192,77 @@ bool iommu_group_dma_owner_claimed(struct iommu_group 
> *group)
>   return user;
>  }
>  EXPORT_SYMBOL_GPL(iommu_group_dma_owner_claimed);
> +
> +/*
> + * Use standard PCI bus topology and isolation features to check immutable
> + * singleton. Otherwise, assume the bus is static and then singleton can
> + * know from the device count in the group.
> + */

The comment doesn't really add anything that can't be directly understood
from the code.

> +static bool device_group_immutable_singleton(struct device *dev)
> +{
> + struct iommu_group *group = iommu_group_get(dev);
> + int count;
> +
> + if (!group)
> + return false;
> +
> + 

Re: [PATCH v5 02/12] iommu: Add pasid_bits field in struct dev_iommu

2022-05-03 Thread Jean-Philippe Brucker
On Mon, May 02, 2022 at 09:48:32AM +0800, Lu Baolu wrote:
> Use this field to save the pasid/ssid bits that a device is able to
> support with its IOMMU hardware. It is a generic attribute of a device
> and lifting it into the per-device dev_iommu struct makes it possible
> to allocate a PASID for device without calls into the IOMMU drivers.
> Any iommu driver which suports PASID related features should set this
> field before features are enabled on the devices.
> 
> For initialization of this field in the VT-d driver, the
> info->pasid_supported is only set for PCI devices. So the status is
> that non-PCI SVA hasn't been supported yet. Setting this field only for
> PCI devices has no functional change.
> 
> Signed-off-by: Lu Baolu 

Reviewed-by: Jean-Philippe Brucker 

> ---
>  include/linux/iommu.h   | 1 +
>  drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 2 ++
>  drivers/iommu/intel/iommu.c | 5 -
>  3 files changed, 7 insertions(+), 1 deletion(-)
> 
> diff --git a/include/linux/iommu.h b/include/linux/iommu.h
> index 5e1afe169549..b8ffaf2cb1d0 100644
> --- a/include/linux/iommu.h
> +++ b/include/linux/iommu.h
> @@ -373,6 +373,7 @@ struct dev_iommu {
>   struct iommu_fwspec *fwspec;
>   struct iommu_device *iommu_dev;
>   void*priv;
> + unsigned intpasid_bits;
>  };
>  
>  int iommu_device_register(struct iommu_device *iommu,
> 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 627a3ed5ee8f..afc63fce6107 100644
> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> @@ -2681,6 +2681,8 @@ static struct iommu_device 
> *arm_smmu_probe_device(struct device *dev)
>   smmu->features & ARM_SMMU_FEAT_STALL_FORCE)
>   master->stall_enabled = true;
>  
> + dev->iommu->pasid_bits = master->ssid_bits;
> +
>   return >iommu;
>  
>  err_free_master:
> diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
> index cf43e8f9091b..170eb777d57b 100644
> --- a/drivers/iommu/intel/iommu.c
> +++ b/drivers/iommu/intel/iommu.c
> @@ -4611,8 +4611,11 @@ static struct iommu_device 
> *intel_iommu_probe_device(struct device *dev)
>   if (pasid_supported(iommu)) {
>   int features = pci_pasid_features(pdev);
>  
> - if (features >= 0)
> + if (features >= 0) {
>   info->pasid_supported = features | 1;
> + dev->iommu->pasid_bits =
> + fls(pci_max_pasids(pdev)) - 1;
> + }
>   }
>  
>   if (info->ats_supported && ecap_prs(iommu->ecap) &&
> -- 
> 2.25.1
> 
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [RESEND PATCH v8 00/11] Fix BUG_ON in vfio_iommu_group_notifier()

2022-05-03 Thread Robin Murphy

On 2022-05-03 16:23, Jason Gunthorpe wrote:

On Tue, May 03, 2022 at 02:04:37PM +0100, Robin Murphy wrote:


I'm guessing SMMU3 needs to call it's arm_smmu_detach_dev(master) from
the detach_dev op and null it's cached copy of the domain, but I don't
know this driver.. Robin?


The original intent was that .detach_dev is deprecated in favour of default
domains, and when the latter are in use, a device is always attached
*somewhere* once probed (i.e. group->domain is never NULL). At face value,
the neatest fix IMO would probably be for SMMUv3's .domain_free to handle
smmu_domain->devices being non-empty and detach them at that point. However
that wouldn't be viable for virtio-iommu or anyone else keeping an internal
one-way association of devices to their current domains.


Oh wow that is not obvious

Actually, I think it is much worse than this because
iommu_group_claim_dma_owner() does a __iommu_detach_group() with the
expecation that this would actually result in DMA being blocked,
immediately. The idea that __iomuu_detatch_group() is a NOP is kind of
scary.


Scarier than the fact that even where it *is* implemented, .detach_dev
has never had a well-defined behaviour either, and plenty of drivers
treat it as a "remove the IOMMU from the picture altogether" operation
which ends up with the device in bypass rather than blocked?


Leaving the group attached to the kernel DMA domain will allow
userspace to DMA to all kernel memory :\


Note that a fair amount of IOMMU hardware only has two states, thus
could only actually achieve a blocking behaviour by enabling translation
with an empty pagetable anyway. (Trivia: and technically some of them
aren't even capable of blocking invalid accesses *when* translating -
they can only apply a "default" translation targeting some scratch page)


So one approach could be to block use of iommu_group_claim_dma_owner()
if no detatch_dev op is present and then go through and put them back
or do something else. This could be short-term OK if we add an op to
SMMUv3, but long term everything would have to be fixed

Or we can allocate a dummy empty/blocked domain during
iommu_group_claim_dma_owner() and attach it whenever.


How does the compile-tested diff below seem? There's a fair chance it's
still broken, but I don't have the bandwidth to give it much more
thought right now.

Cheers,
Robin.

->8-
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 29906bc16371..597d70ed7007 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -45,6 +45,7 @@ struct iommu_group {
int id;
struct iommu_domain *default_domain;
struct iommu_domain *domain;
+   struct iommu_domain *purgatory;
struct list_head entry;
unsigned int owner_cnt;
void *owner;
@@ -596,6 +597,8 @@ static void iommu_group_release(struct kobject *kobj)
 
 	if (group->default_domain)

iommu_domain_free(group->default_domain);
+   if (group->purgatory)
+   iommu_domain_free(group->purgatory);
 
 	kfree(group->name);

kfree(group);
@@ -2041,6 +2044,12 @@ struct iommu_domain *iommu_get_dma_domain(struct device 
*dev)
return dev->iommu_group->default_domain;
 }
 
+static bool iommu_group_user_attached(struct iommu_group *group)

+{
+   return group->domain && group->domain != group->default_domain &&
+  group->domain != group->purgatory;
+}
+
 /*
  * IOMMU groups are really the natural working unit of the IOMMU, but
  * the IOMMU API works on domains and devices.  Bridge that gap by
@@ -2063,7 +2072,7 @@ static int __iommu_attach_group(struct iommu_domain 
*domain,
 {
int ret;
 
-	if (group->domain && group->domain != group->default_domain)

+   if (iommu_group_user_attached(group))
return -EBUSY;
 
 	ret = __iommu_group_for_each_dev(group, domain,

@@ -2104,7 +2113,12 @@ static void __iommu_detach_group(struct iommu_domain 
*domain,
 * If the group has been claimed already, do not re-attach the default
 * domain.
 */
-   if (!group->default_domain || group->owner) {
+   if (group->owner) {
+   WARN_ON(__iommu_attach_group(group->purgatory, group));
+   return;
+   }
+
+   if (!group->default_domain) {
__iommu_group_for_each_dev(group, domain,
   iommu_group_do_detach_device);
group->domain = NULL;
@@ -3111,6 +3125,25 @@ void iommu_device_unuse_default_domain(struct device 
*dev)
iommu_group_put(group);
 }
 
+static struct iommu_domain *iommu_group_get_purgatory(struct iommu_group *group)

+{
+   struct group_device *dev;
+
+   mutex_lock(>mutex);
+   if (group->purgatory)
+   goto out;
+
+   dev = list_first_entry(>devices, struct group_device, list);
+   group->purgatory = __iommu_domain_alloc(dev->dev->bus,
+   IOMMU_DOMAIN_BLOCKED);

Re: [PATCH 1/2] iommu/io-pgtable-arm-v7s: Add a quirk to support TTBR up to 35bit for MediaTek

2022-05-03 Thread Miles Chen via iommu
Hi YF,

> The calling to kmem_cache_alloc for level 2 page table allocation may
> run in atomic context, and it fails sometimes when DMA32 zone runs out
> of memory.
> 
> Since Mediatek IOMMU hardware support at most 35bit PA in page table,

s/Mediatek/MediaTek/
s/support/supports/

> so add a quirk to allow the PA of level 2 pgtable support bit35.

35bits PA, right?

>
> 

...snip...

>  
>   phys = virt_to_phys(table);
> - if (phys != (arm_v7s_iopte)phys) {
> + if (phys != (arm_v7s_iopte)phys &&
> + !(cfg->quirks & IO_PGTABLE_QUIRK_ARM_MTK_TTBR_EXT)) {

I have one question while reading this.

If IO_PGTABLE_QUIRK_ARM_MTK_TTBR_EXT is set, it means that the phys can be up 
to 35 bits.
In aarch64, kmalloc() could return up to 52 bits PA (e.g., ARM64_PA_BITS_52=y)

How do we guarantee that phys is safe (<= 35 bits) in this case?
For example:
When IO_PGTABLE_QUIRK_ARM_MTK_TTBR_EXT is set, the platform guarantees its PAs 
are at most
35 bits?


Thanks,
Miles
>   /* Doesn't fit in PTE */
>   dev_err(dev, "Page table does not fit in PTE: %pa", );
>   goto out_free;
> @@ -457,9 +464,14 @@ static arm_v7s_iopte arm_v7s_install_table(arm_v7s_iopte 
> *table,
>  arm_v7s_iopte curr,
>  struct io_pgtable_cfg *cfg)
>  {
> + phys_addr_t phys = virt_to_phys(table);
>   arm_v7s_iopte old, new;
>  
> - new = virt_to_phys(table) | ARM_V7S_PTE_TYPE_TABLE;
> + new = phys | ARM_V7S_PTE_TYPE_TABLE;
> +
> + if (cfg->quirks & IO_PGTABLE_QUIRK_ARM_MTK_TTBR_EXT)
> + new = to_iopte_mtk(phys, new, cfg);
> +
>   if (cfg->quirks & IO_PGTABLE_QUIRK_ARM_NS)
>   new |= ARM_V7S_ATTR_NS_TABLE;
>  
> @@ -778,6 +790,7 @@ static phys_addr_t arm_v7s_iova_to_phys(struct 
> io_pgtable_ops *ops,
>  static struct io_pgtable *arm_v7s_alloc_pgtable(struct io_pgtable_cfg *cfg,
>   void *cookie)
>  {
> + slab_flags_t slab_flag = ARM_V7S_TABLE_SLAB_FLAGS;
>   struct arm_v7s_io_pgtable *data;
>  
>   if (cfg->ias > (arm_v7s_is_mtk_enabled(cfg) ? 34 : ARM_V7S_ADDR_BITS))
> @@ -788,7 +801,8 @@ static struct io_pgtable *arm_v7s_alloc_pgtable(struct 
> io_pgtable_cfg *cfg,
>  
>   if (cfg->quirks & ~(IO_PGTABLE_QUIRK_ARM_NS |
>   IO_PGTABLE_QUIRK_NO_PERMS |
> - IO_PGTABLE_QUIRK_ARM_MTK_EXT))
> + IO_PGTABLE_QUIRK_ARM_MTK_EXT |
> + IO_PGTABLE_QUIRK_ARM_MTK_TTBR_EXT))
>   return NULL;
>  
>   /* If ARM_MTK_4GB is enabled, the NO_PERMS is also expected. */
> @@ -801,10 +815,12 @@ static struct io_pgtable *arm_v7s_alloc_pgtable(struct 
> io_pgtable_cfg *cfg,
>   return NULL;
>  
>   spin_lock_init(>split_lock);
> + if (cfg->quirks & IO_PGTABLE_QUIRK_ARM_MTK_TTBR_EXT)
> + slab_flag = 0;
>   data->l2_tables = kmem_cache_create("io-pgtable_armv7s_l2",
>   ARM_V7S_TABLE_SIZE(2, cfg),
>   ARM_V7S_TABLE_SIZE(2, cfg),
> - ARM_V7S_TABLE_SLAB_FLAGS, NULL);
> + slab_flag, NULL);
>   if (!data->l2_tables)
>   goto out_free_data;
>  
> diff --git a/include/linux/io-pgtable.h b/include/linux/io-pgtable.h
> index 86af6f0a00a2..7ed15ad4710c 100644
> --- a/include/linux/io-pgtable.h
> +++ b/include/linux/io-pgtable.h
> @@ -74,17 +74,22 @@ struct io_pgtable_cfg {
>*  to support up to 35 bits PA where the bit32, bit33 and bit34 are
>*  encoded in the bit9, bit4 and bit5 of the PTE respectively.
>*
> +  * IO_PGTABLE_QUIRK_ARM_MTK_TTBR_EXT: (ARM v7s format) MediaTek IOMMUs
> +  *  extend the translation table support up to 35 bits PA, the
> +  *  encoding format is same with IO_PGTABLE_QUIRK_ARM_MTK_EXT.
> +  *
>* IO_PGTABLE_QUIRK_ARM_TTBR1: (ARM LPAE format) Configure the table
>*  for use in the upper half of a split address space.
>*
>* IO_PGTABLE_QUIRK_ARM_OUTER_WBWA: Override the outer-cacheability
>*  attributes set in the TCR for a non-coherent page-table walker.
>*/
> - #define IO_PGTABLE_QUIRK_ARM_NS BIT(0)
> - #define IO_PGTABLE_QUIRK_NO_PERMS   BIT(1)
> - #define IO_PGTABLE_QUIRK_ARM_MTK_EXTBIT(3)
> - #define IO_PGTABLE_QUIRK_ARM_TTBR1  BIT(5)
> - #define IO_PGTABLE_QUIRK_ARM_OUTER_WBWA BIT(6)
> + #define IO_PGTABLE_QUIRK_ARM_NS BIT(0)
> + #define IO_PGTABLE_QUIRK_NO_PERMS   BIT(1)
> + #define IO_PGTABLE_QUIRK_ARM_MTK_EXTBIT(3)
> + #define IO_PGTABLE_QUIRK_ARM_MTK_TTBR_EXT   BIT(4)
> + #define IO_PGTABLE_QUIRK_ARM_TTBR1  BIT(5)
> + #define IO_PGTABLE_QUIRK_ARM_OUTER_WBWA BIT(6)
> 

[PATCH v12 9/9] iommu/arm-smmu: Get associated RMR info and install bypass SMR

2022-05-03 Thread Shameer Kolothum via iommu
From: Jon Nettleton 

Check if there is any RMR info associated with the devices behind
the SMMU and if any, install bypass SMRs for them. This is to
keep any ongoing traffic associated with these devices alive
when we enable/reset SMMU during probe().

Signed-off-by: Jon Nettleton 
Signed-off-by: Steven Price 
Tested-by: Steven Price 
Signed-off-by: Shameer Kolothum 
---
 drivers/iommu/arm/arm-smmu/arm-smmu.c | 52 +++
 1 file changed, 52 insertions(+)

diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu.c 
b/drivers/iommu/arm/arm-smmu/arm-smmu.c
index 568cce590ccc..e02cc2d4fb4e 100644
--- a/drivers/iommu/arm/arm-smmu/arm-smmu.c
+++ b/drivers/iommu/arm/arm-smmu/arm-smmu.c
@@ -2068,6 +2068,54 @@ err_reset_platform_ops: __maybe_unused;
return err;
 }
 
+static void arm_smmu_rmr_install_bypass_smr(struct arm_smmu_device *smmu)
+{
+   struct list_head rmr_list;
+   struct iommu_resv_region *e;
+   int idx, cnt = 0;
+   u32 reg;
+
+   INIT_LIST_HEAD(_list);
+   iort_get_rmr_sids(dev_fwnode(smmu->dev), _list);
+
+   /*
+* Rather than trying to look at existing mappings that
+* are setup by the firmware and then invalidate the ones
+* that do no have matching RMR entries, just disable the
+* SMMU until it gets enabled again in the reset routine.
+*/
+   reg = arm_smmu_gr0_read(smmu, ARM_SMMU_GR0_sCR0);
+   reg |= ARM_SMMU_sCR0_CLIENTPD;
+   arm_smmu_gr0_write(smmu, ARM_SMMU_GR0_sCR0, reg);
+
+   list_for_each_entry(e, _list, list) {
+   struct iommu_iort_rmr_data *rmr;
+   int i;
+
+   rmr = container_of(e, struct iommu_iort_rmr_data, rr);
+   for (i = 0; i < rmr->num_sids; i++) {
+   idx = arm_smmu_find_sme(smmu, rmr->sids[i], ~0);
+   if (idx < 0)
+   continue;
+
+   if (smmu->s2crs[idx].count == 0) {
+   smmu->smrs[idx].id = rmr->sids[i];
+   smmu->smrs[idx].mask = 0;
+   smmu->smrs[idx].valid = true;
+   }
+   smmu->s2crs[idx].count++;
+   smmu->s2crs[idx].type = S2CR_TYPE_BYPASS;
+   smmu->s2crs[idx].privcfg = S2CR_PRIVCFG_DEFAULT;
+
+   cnt++;
+   }
+   }
+
+   dev_notice(smmu->dev, "\tpreserved %d boot mapping%s\n", cnt,
+  cnt == 1 ? "" : "s");
+   iort_put_rmr_sids(dev_fwnode(smmu->dev), _list);
+}
+
 static int arm_smmu_device_probe(struct platform_device *pdev)
 {
struct resource *res;
@@ -2189,6 +2237,10 @@ static int arm_smmu_device_probe(struct platform_device 
*pdev)
}
 
platform_set_drvdata(pdev, smmu);
+
+   /* Check for RMRs and install bypass SMRs if any */
+   arm_smmu_rmr_install_bypass_smr(smmu);
+
arm_smmu_device_reset(smmu);
arm_smmu_test_smr_masks(smmu);
 
-- 
2.17.1

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


[PATCH v12 8/9] iommu/arm-smmu-v3: Get associated RMR info and install bypass STE

2022-05-03 Thread Shameer Kolothum via iommu
Check if there is any RMR info associated with the devices behind
the SMMUv3 and if any, install bypass STEs for them. This is to
keep any ongoing traffic associated with these devices alive
when we enable/reset SMMUv3 during probe().

Signed-off-by: Shameer Kolothum 
---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 33 +
 1 file changed, 33 insertions(+)

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 a939d9e0f747..8a5dfd078e95 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -3754,6 +3754,36 @@ static void __iomem *arm_smmu_ioremap(struct device 
*dev, resource_size_t start,
return devm_ioremap_resource(dev, );
 }
 
+static void arm_smmu_rmr_install_bypass_ste(struct arm_smmu_device *smmu)
+{
+   struct list_head rmr_list;
+   struct iommu_resv_region *e;
+
+   INIT_LIST_HEAD(_list);
+   iort_get_rmr_sids(dev_fwnode(smmu->dev), _list);
+
+   list_for_each_entry(e, _list, list) {
+   __le64 *step;
+   struct iommu_iort_rmr_data *rmr;
+   int ret, i;
+
+   rmr = container_of(e, struct iommu_iort_rmr_data, rr);
+   for (i = 0; i < rmr->num_sids; i++) {
+   ret = arm_smmu_init_sid_strtab(smmu, rmr->sids[i]);
+   if (ret) {
+   dev_err(smmu->dev, "RMR SID(0x%x) bypass 
failed\n",
+   rmr->sids[i]);
+   continue;
+   }
+
+   step = arm_smmu_get_step_for_sid(smmu, rmr->sids[i]);
+   arm_smmu_init_bypass_stes(step, 1, true);
+   }
+   }
+
+   iort_put_rmr_sids(dev_fwnode(smmu->dev), _list);
+}
+
 static int arm_smmu_device_probe(struct platform_device *pdev)
 {
int irq, ret;
@@ -3835,6 +3865,9 @@ static int arm_smmu_device_probe(struct platform_device 
*pdev)
/* Record our private device structure */
platform_set_drvdata(pdev, smmu);
 
+   /* Check for RMRs and install bypass STEs if any */
+   arm_smmu_rmr_install_bypass_ste(smmu);
+
/* Reset the device */
ret = arm_smmu_device_reset(smmu, bypass);
if (ret)
-- 
2.17.1

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


[PATCH v12 7/9] iommu/arm-smmu-v3: Refactor arm_smmu_init_bypass_stes() to force bypass

2022-05-03 Thread Shameer Kolothum via iommu
By default, disable_bypass flag is set and any dev without
an iommu domain installs STE with CFG_ABORT during
arm_smmu_init_bypass_stes(). Introduce a "force" flag and
move the STE update logic to arm_smmu_init_bypass_stes()
so that we can force it to install CFG_BYPASS STE for specific
SIDs.

This will be useful in a follow-up patch to install bypass
for IORT RMR SIDs.

Signed-off-by: Shameer Kolothum 
---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 17 +
 1 file changed, 13 insertions(+), 4 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 df326d8f02c6..a939d9e0f747 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -1380,12 +1380,21 @@ static void arm_smmu_write_strtab_ent(struct 
arm_smmu_master *master, u32 sid,
arm_smmu_cmdq_issue_cmd(smmu, _cmd);
 }
 
-static void arm_smmu_init_bypass_stes(__le64 *strtab, unsigned int nent)
+static void arm_smmu_init_bypass_stes(__le64 *strtab, unsigned int nent, bool 
force)
 {
unsigned int i;
+   u64 val = STRTAB_STE_0_V;
+
+   if (disable_bypass && !force)
+   val |= FIELD_PREP(STRTAB_STE_0_CFG, STRTAB_STE_0_CFG_ABORT);
+   else
+   val |= FIELD_PREP(STRTAB_STE_0_CFG, STRTAB_STE_0_CFG_BYPASS);
 
for (i = 0; i < nent; ++i) {
-   arm_smmu_write_strtab_ent(NULL, -1, strtab);
+   strtab[0] = cpu_to_le64(val);
+   strtab[1] = cpu_to_le64(FIELD_PREP(STRTAB_STE_1_SHCFG,
+  
STRTAB_STE_1_SHCFG_INCOMING));
+   strtab[2] = 0;
strtab += STRTAB_STE_DWORDS;
}
 }
@@ -1413,7 +1422,7 @@ static int arm_smmu_init_l2_strtab(struct arm_smmu_device 
*smmu, u32 sid)
return -ENOMEM;
}
 
-   arm_smmu_init_bypass_stes(desc->l2ptr, 1 << STRTAB_SPLIT);
+   arm_smmu_init_bypass_stes(desc->l2ptr, 1 << STRTAB_SPLIT, false);
arm_smmu_write_strtab_l1_desc(strtab, desc);
return 0;
 }
@@ -3051,7 +3060,7 @@ static int arm_smmu_init_strtab_linear(struct 
arm_smmu_device *smmu)
reg |= FIELD_PREP(STRTAB_BASE_CFG_LOG2SIZE, smmu->sid_bits);
cfg->strtab_base_cfg = reg;
 
-   arm_smmu_init_bypass_stes(strtab, cfg->num_l1_ents);
+   arm_smmu_init_bypass_stes(strtab, cfg->num_l1_ents, false);
return 0;
 }
 
-- 
2.17.1

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


[PATCH v12 6/9] iommu/arm-smmu-v3: Introduce strtab init helper

2022-05-03 Thread Shameer Kolothum via iommu
Introduce a helper to check the sid range and to init the l2 strtab
entries(bypass). This will be useful when we have to initialize the
l2 strtab with bypass for RMR SIDs.

Signed-off-by: Shameer Kolothum 
---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 28 +++--
 1 file changed, 15 insertions(+), 13 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 627a3ed5ee8f..df326d8f02c6 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -2537,6 +2537,19 @@ static bool arm_smmu_sid_in_range(struct arm_smmu_device 
*smmu, u32 sid)
return sid < limit;
 }
 
+static int arm_smmu_init_sid_strtab(struct arm_smmu_device *smmu, u32 sid)
+{
+   /* Check the SIDs are in range of the SMMU and our stream table */
+   if (!arm_smmu_sid_in_range(smmu, sid))
+   return -ERANGE;
+
+   /* Ensure l2 strtab is initialised */
+   if (smmu->features & ARM_SMMU_FEAT_2_LVL_STRTAB)
+   return arm_smmu_init_l2_strtab(smmu, sid);
+
+   return 0;
+}
+
 static int arm_smmu_insert_master(struct arm_smmu_device *smmu,
  struct arm_smmu_master *master)
 {
@@ -2560,20 +2573,9 @@ static int arm_smmu_insert_master(struct arm_smmu_device 
*smmu,
new_stream->id = sid;
new_stream->master = master;
 
-   /*
-* Check the SIDs are in range of the SMMU and our stream table
-*/
-   if (!arm_smmu_sid_in_range(smmu, sid)) {
-   ret = -ERANGE;
+   ret = arm_smmu_init_sid_strtab(smmu, sid);
+   if (ret)
break;
-   }
-
-   /* Ensure l2 strtab is initialised */
-   if (smmu->features & ARM_SMMU_FEAT_2_LVL_STRTAB) {
-   ret = arm_smmu_init_l2_strtab(smmu, sid);
-   if (ret)
-   break;
-   }
 
/* Insert into SID tree */
new_node = &(smmu->streams.rb_node);
-- 
2.17.1

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


[PATCH v12 5/9] ACPI/IORT: Add a helper to retrieve RMR info directly

2022-05-03 Thread Shameer Kolothum via iommu
This will provide a way for SMMU drivers to retrieve StreamIDs
associated with IORT RMR nodes and use that to set bypass settings
for those IDs.

Tested-by: Steven Price 
Signed-off-by: Shameer Kolothum 
---
 drivers/acpi/arm64/iort.c | 28 
 include/linux/acpi_iort.h |  8 
 2 files changed, 36 insertions(+)

diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index b6273af316c6..cd1349d3544e 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -1394,6 +1394,34 @@ int iort_dma_get_ranges(struct device *dev, u64 *size)
return nc_dma_get_range(dev, size);
 }
 
+/**
+ * iort_get_rmr_sids - Retrieve IORT RMR node reserved regions with
+ * associated StreamIDs information.
+ * @iommu_fwnode: fwnode associated with IOMMU
+ * @head: Resereved region list
+ */
+void iort_get_rmr_sids(struct fwnode_handle *iommu_fwnode,
+  struct list_head *head)
+{
+   iort_iommu_rmr_get_resv_regions(iommu_fwnode, NULL, head);
+}
+EXPORT_SYMBOL_GPL(iort_get_rmr_sids);
+
+/**
+ * iort_put_rmr_sids - Free memory allocated for RMR reserved regions.
+ * @iommu_fwnode: fwnode associated with IOMMU
+ * @head: Resereved region list
+ */
+void iort_put_rmr_sids(struct fwnode_handle *iommu_fwnode,
+  struct list_head *head)
+{
+   struct iommu_resv_region *entry, *next;
+
+   list_for_each_entry_safe(entry, next, head, list)
+   entry->free(NULL, entry);
+}
+EXPORT_SYMBOL_GPL(iort_put_rmr_sids);
+
 static void __init acpi_iort_register_irq(int hwirq, const char *name,
  int trigger,
  struct resource *res)
diff --git a/include/linux/acpi_iort.h b/include/linux/acpi_iort.h
index e5d2de9caf7f..b43be0987b19 100644
--- a/include/linux/acpi_iort.h
+++ b/include/linux/acpi_iort.h
@@ -33,6 +33,10 @@ struct irq_domain *iort_get_device_domain(struct device 
*dev, u32 id,
  enum irq_domain_bus_token bus_token);
 void acpi_configure_pmsi_domain(struct device *dev);
 int iort_pmsi_get_dev_id(struct device *dev, u32 *dev_id);
+void iort_get_rmr_sids(struct fwnode_handle *iommu_fwnode,
+  struct list_head *head);
+void iort_put_rmr_sids(struct fwnode_handle *iommu_fwnode,
+  struct list_head *head);
 /* IOMMU interface */
 int iort_dma_get_ranges(struct device *dev, u64 *size);
 int iort_iommu_configure_id(struct device *dev, const u32 *id_in);
@@ -46,6 +50,10 @@ static inline struct irq_domain *iort_get_device_domain(
struct device *dev, u32 id, enum irq_domain_bus_token bus_token)
 { return NULL; }
 static inline void acpi_configure_pmsi_domain(struct device *dev) { }
+static inline
+void iort_get_rmr_sids(struct fwnode_handle *iommu_fwnode, struct list_head 
*head) { }
+static inline
+void iort_put_rmr_sids(struct fwnode_handle *iommu_fwnode, struct list_head 
*head) { }
 /* IOMMU interface */
 static inline int iort_dma_get_ranges(struct device *dev, u64 *size)
 { return -ENODEV; }
-- 
2.17.1

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


[PATCH v12 4/9] ACPI/IORT: Add support to retrieve IORT RMR reserved regions

2022-05-03 Thread Shameer Kolothum via iommu
Parse through the IORT RMR nodes and populate the reserve region list
corresponding to a given IOMMU and device(optional). Also, go through
the ID mappings of the RMR node and retrieve all the SIDs associated
with it.

Reviewed-by: Lorenzo Pieralisi 
Tested-by: Steven Price 
Signed-off-by: Shameer Kolothum 
---
 drivers/acpi/arm64/iort.c | 291 ++
 include/linux/iommu.h |   8 ++
 2 files changed, 299 insertions(+)

diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index cd5d1d7823cb..b6273af316c6 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -788,6 +788,294 @@ void acpi_configure_pmsi_domain(struct device *dev)
 }
 
 #ifdef CONFIG_IOMMU_API
+static void iort_rmr_free(struct device *dev,
+ struct iommu_resv_region *region)
+{
+   struct iommu_iort_rmr_data *rmr_data;
+
+   rmr_data = container_of(region, struct iommu_iort_rmr_data, rr);
+   kfree(rmr_data->sids);
+   kfree(rmr_data);
+}
+
+static struct iommu_iort_rmr_data *iort_rmr_alloc(
+   struct acpi_iort_rmr_desc *rmr_desc,
+   int prot, enum iommu_resv_type type,
+   u32 *sids, u32 num_sids)
+{
+   struct iommu_iort_rmr_data *rmr_data;
+   struct iommu_resv_region *region;
+   u32 *sids_copy;
+   u64 addr = rmr_desc->base_address, size = rmr_desc->length;
+
+   rmr_data = kmalloc(sizeof(*rmr_data), GFP_KERNEL);
+   if (!rmr_data)
+   return NULL;
+
+   /* Create a copy of SIDs array to associate with this rmr_data */
+   sids_copy = kmemdup(sids, num_sids * sizeof(*sids), GFP_KERNEL);
+   if (!sids_copy) {
+   kfree(rmr_data);
+   return NULL;
+   }
+   rmr_data->sids = sids_copy;
+   rmr_data->num_sids = num_sids;
+
+   if (!IS_ALIGNED(addr, SZ_64K) || !IS_ALIGNED(size, SZ_64K)) {
+   /* PAGE align base addr and size */
+   addr &= PAGE_MASK;
+   size = PAGE_ALIGN(size + 
offset_in_page(rmr_desc->base_address));
+
+   pr_err(FW_BUG "RMR descriptor[0x%llx - 0x%llx] not aligned to 
64K, continue with [0x%llx - 0x%llx]\n",
+  rmr_desc->base_address,
+  rmr_desc->base_address + rmr_desc->length - 1,
+  addr, addr + size - 1);
+   }
+
+   region = _data->rr;
+   INIT_LIST_HEAD(>list);
+   region->start = addr;
+   region->length = size;
+   region->prot = prot;
+   region->type = type;
+   region->free = iort_rmr_free;
+
+   return rmr_data;
+}
+
+static void iort_rmr_desc_check_overlap(struct acpi_iort_rmr_desc *desc,
+   u32 count)
+{
+   int i, j;
+
+   for (i = 0; i < count; i++) {
+   u64 end, start = desc[i].base_address, length = desc[i].length;
+
+   if (!length) {
+   pr_err(FW_BUG "RMR descriptor[0x%llx] with zero length, 
continue anyway\n",
+  start);
+   continue;
+   }
+
+   end = start + length - 1;
+
+   /* Check for address overlap */
+   for (j = i + 1; j < count; j++) {
+   u64 e_start = desc[j].base_address;
+   u64 e_end = e_start + desc[j].length - 1;
+
+   if (start <= e_end && end >= e_start)
+   pr_err(FW_BUG "RMR descriptor[0x%llx - 0x%llx] 
overlaps, continue anyway\n",
+  start, end);
+   }
+   }
+}
+
+/*
+ * Please note, we will keep the already allocated RMR reserve
+ * regions in case of a memory allocation failure.
+ */
+static void iort_get_rmrs(struct acpi_iort_node *node,
+ struct acpi_iort_node *smmu,
+ u32 *sids, u32 num_sids,
+ struct list_head *head)
+{
+   struct acpi_iort_rmr *rmr = (struct acpi_iort_rmr *)node->node_data;
+   struct acpi_iort_rmr_desc *rmr_desc;
+   int i;
+
+   rmr_desc = ACPI_ADD_PTR(struct acpi_iort_rmr_desc, node,
+   rmr->rmr_offset);
+
+   iort_rmr_desc_check_overlap(rmr_desc, rmr->rmr_count);
+
+   for (i = 0; i < rmr->rmr_count; i++, rmr_desc++) {
+   struct iommu_iort_rmr_data *rmr_data;
+   enum iommu_resv_type type;
+   int prot = IOMMU_READ | IOMMU_WRITE;
+
+   if (rmr->flags & ACPI_IORT_RMR_REMAP_PERMITTED)
+   type = IOMMU_RESV_DIRECT_RELAXABLE;
+   else
+   type = IOMMU_RESV_DIRECT;
+
+   if (rmr->flags & ACPI_IORT_RMR_ACCESS_PRIVILEGE)
+   prot |= IOMMU_PRIV;
+
+   /* Attributes 0x00 - 0x03 represents device memory */
+   if 

[PATCH v12 3/9] ACPI/IORT: Provide a generic helper to retrieve reserve regions

2022-05-03 Thread Shameer Kolothum via iommu
Currently IORT provides a helper to retrieve HW MSI reserve regions.
Change this to a generic helper to retrieve any IORT related reserve
regions. This will be useful when we add support for RMR nodes in
subsequent patches.

[Lorenzo: For ACPI IORT]
Reviewed-by: Lorenzo Pieralisi 
Reviewed-by: Christoph Hellwig 
Tested-by: Steven Price 
Signed-off-by: Shameer Kolothum 
---
 drivers/acpi/arm64/iort.c | 22 +++---
 drivers/iommu/dma-iommu.c |  2 +-
 include/linux/acpi_iort.h |  4 ++--
 3 files changed, 18 insertions(+), 10 deletions(-)

diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index 213f61cae176..cd5d1d7823cb 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -806,15 +806,13 @@ static struct acpi_iort_node 
*iort_get_msi_resv_iommu(struct device *dev)
return NULL;
 }
 
-/**
- * iort_iommu_msi_get_resv_regions - Reserved region driver helper
- * @dev: Device from iommu_get_resv_regions()
- * @head: Reserved region list from iommu_get_resv_regions()
- *
+/*
+ * Retrieve platform specific HW MSI reserve regions.
  * The ITS interrupt translation spaces (ITS_base + SZ_64K, SZ_64K)
  * associated with the device are the HW MSI reserved regions.
  */
-void iort_iommu_msi_get_resv_regions(struct device *dev, struct list_head 
*head)
+static void iort_iommu_msi_get_resv_regions(struct device *dev,
+   struct list_head *head)
 {
struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
struct acpi_iort_its_group *its;
@@ -863,6 +861,16 @@ void iort_iommu_msi_get_resv_regions(struct device *dev, 
struct list_head *head)
}
 }
 
+/**
+ * iort_iommu_get_resv_regions - Generic helper to retrieve reserved regions.
+ * @dev: Device from iommu_get_resv_regions()
+ * @head: Reserved region list from iommu_get_resv_regions()
+ */
+void iort_iommu_get_resv_regions(struct device *dev, struct list_head *head)
+{
+   iort_iommu_msi_get_resv_regions(dev, head);
+}
+
 static inline bool iort_iommu_driver_enabled(u8 type)
 {
switch (type) {
@@ -1027,7 +1035,7 @@ int iort_iommu_configure_id(struct device *dev, const u32 
*id_in)
 }
 
 #else
-void iort_iommu_msi_get_resv_regions(struct device *dev, struct list_head 
*head)
+void iort_iommu_get_resv_regions(struct device *dev, struct list_head *head)
 { }
 int iort_iommu_configure_id(struct device *dev, const u32 *input_id)
 { return -ENODEV; }
diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c
index 09f6e1c0f9c0..93d76b666888 100644
--- a/drivers/iommu/dma-iommu.c
+++ b/drivers/iommu/dma-iommu.c
@@ -384,7 +384,7 @@ void iommu_dma_get_resv_regions(struct device *dev, struct 
list_head *list)
 {
 
if (!is_of_node(dev_iommu_fwspec_get(dev)->iommu_fwnode))
-   iort_iommu_msi_get_resv_regions(dev, list);
+   iort_iommu_get_resv_regions(dev, list);
 
 }
 EXPORT_SYMBOL(iommu_dma_get_resv_regions);
diff --git a/include/linux/acpi_iort.h b/include/linux/acpi_iort.h
index a8198b83753d..e5d2de9caf7f 100644
--- a/include/linux/acpi_iort.h
+++ b/include/linux/acpi_iort.h
@@ -36,7 +36,7 @@ int iort_pmsi_get_dev_id(struct device *dev, u32 *dev_id);
 /* IOMMU interface */
 int iort_dma_get_ranges(struct device *dev, u64 *size);
 int iort_iommu_configure_id(struct device *dev, const u32 *id_in);
-void iort_iommu_msi_get_resv_regions(struct device *dev, struct list_head 
*head);
+void iort_iommu_get_resv_regions(struct device *dev, struct list_head *head);
 phys_addr_t acpi_iort_dma_get_max_cpu_address(void);
 #else
 static inline void acpi_iort_init(void) { }
@@ -52,7 +52,7 @@ static inline int iort_dma_get_ranges(struct device *dev, u64 
*size)
 static inline int iort_iommu_configure_id(struct device *dev, const u32 *id_in)
 { return -ENODEV; }
 static inline
-void iort_iommu_msi_get_resv_regions(struct device *dev, struct list_head 
*head)
+void iort_iommu_get_resv_regions(struct device *dev, struct list_head *head)
 { }
 
 static inline phys_addr_t acpi_iort_dma_get_max_cpu_address(void)
-- 
2.17.1

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

[PATCH v12 2/9] ACPI/IORT: Make iort_iommu_msi_get_resv_regions() return void

2022-05-03 Thread Shameer Kolothum via iommu
At present iort_iommu_msi_get_resv_regions() returns the number of
MSI reserved regions on success and there are no users for this.
The reserved region list will get populated anyway for platforms
that require the HW MSI region reservation. Hence, change the
function to return void instead.

Reviewed-by: Christoph Hellwig 
Tested-by: Steven Price 
Signed-off-by: Shameer Kolothum 
---
 drivers/acpi/arm64/iort.c | 25 +
 include/linux/acpi_iort.h |  6 +++---
 2 files changed, 12 insertions(+), 19 deletions(-)

diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index f2f8f05662de..213f61cae176 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -811,22 +811,19 @@ static struct acpi_iort_node 
*iort_get_msi_resv_iommu(struct device *dev)
  * @dev: Device from iommu_get_resv_regions()
  * @head: Reserved region list from iommu_get_resv_regions()
  *
- * Returns: Number of msi reserved regions on success (0 if platform
- *  doesn't require the reservation or no associated msi regions),
- *  appropriate error value otherwise. The ITS interrupt translation
- *  spaces (ITS_base + SZ_64K, SZ_64K) associated with the device
- *  are the msi reserved regions.
+ * The ITS interrupt translation spaces (ITS_base + SZ_64K, SZ_64K)
+ * associated with the device are the HW MSI reserved regions.
  */
-int iort_iommu_msi_get_resv_regions(struct device *dev, struct list_head *head)
+void iort_iommu_msi_get_resv_regions(struct device *dev, struct list_head 
*head)
 {
struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
struct acpi_iort_its_group *its;
struct acpi_iort_node *iommu_node, *its_node = NULL;
-   int i, resv = 0;
+   int i;
 
iommu_node = iort_get_msi_resv_iommu(dev);
if (!iommu_node)
-   return 0;
+   return;
 
/*
 * Current logic to reserve ITS regions relies on HW topologies
@@ -846,7 +843,7 @@ int iort_iommu_msi_get_resv_regions(struct device *dev, 
struct list_head *head)
}
 
if (!its_node)
-   return 0;
+   return;
 
/* Move to ITS specific data */
its = (struct acpi_iort_its_group *)its_node->node_data;
@@ -860,14 +857,10 @@ int iort_iommu_msi_get_resv_regions(struct device *dev, 
struct list_head *head)
 
region = iommu_alloc_resv_region(base + SZ_64K, SZ_64K,
 prot, IOMMU_RESV_MSI);
-   if (region) {
+   if (region)
list_add_tail(>list, head);
-   resv++;
-   }
}
}
-
-   return (resv == its->its_count) ? resv : -ENODEV;
 }
 
 static inline bool iort_iommu_driver_enabled(u8 type)
@@ -1034,8 +1027,8 @@ int iort_iommu_configure_id(struct device *dev, const u32 
*id_in)
 }
 
 #else
-int iort_iommu_msi_get_resv_regions(struct device *dev, struct list_head *head)
-{ return 0; }
+void iort_iommu_msi_get_resv_regions(struct device *dev, struct list_head 
*head)
+{ }
 int iort_iommu_configure_id(struct device *dev, const u32 *input_id)
 { return -ENODEV; }
 #endif
diff --git a/include/linux/acpi_iort.h b/include/linux/acpi_iort.h
index f1f0842a2cb2..a8198b83753d 100644
--- a/include/linux/acpi_iort.h
+++ b/include/linux/acpi_iort.h
@@ -36,7 +36,7 @@ int iort_pmsi_get_dev_id(struct device *dev, u32 *dev_id);
 /* IOMMU interface */
 int iort_dma_get_ranges(struct device *dev, u64 *size);
 int iort_iommu_configure_id(struct device *dev, const u32 *id_in);
-int iort_iommu_msi_get_resv_regions(struct device *dev, struct list_head 
*head);
+void iort_iommu_msi_get_resv_regions(struct device *dev, struct list_head 
*head);
 phys_addr_t acpi_iort_dma_get_max_cpu_address(void);
 #else
 static inline void acpi_iort_init(void) { }
@@ -52,8 +52,8 @@ static inline int iort_dma_get_ranges(struct device *dev, u64 
*size)
 static inline int iort_iommu_configure_id(struct device *dev, const u32 *id_in)
 { return -ENODEV; }
 static inline
-int iort_iommu_msi_get_resv_regions(struct device *dev, struct list_head *head)
-{ return 0; }
+void iort_iommu_msi_get_resv_regions(struct device *dev, struct list_head 
*head)
+{ }
 
 static inline phys_addr_t acpi_iort_dma_get_max_cpu_address(void)
 { return PHYS_ADDR_MAX; }
-- 
2.17.1

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


[PATCH v12 1/9] iommu: Introduce a callback to struct iommu_resv_region

2022-05-03 Thread Shameer Kolothum via iommu
A callback is introduced to struct iommu_resv_region to free memory
allocations associated with the reserved region. This will be useful
when we introduce support for IORT RMR based reserved regions.

Reviewed-by: Christoph Hellwig 
Tested-by: Steven Price 
Signed-off-by: Shameer Kolothum 
---
 drivers/iommu/iommu.c | 16 +++-
 include/linux/iommu.h |  2 ++
 2 files changed, 13 insertions(+), 5 deletions(-)

diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index f2c45b85b9fc..ffcfa684e80c 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -2597,16 +2597,22 @@ void iommu_put_resv_regions(struct device *dev, struct 
list_head *list)
  * @list: reserved region list for device
  *
  * IOMMU drivers can use this to implement their .put_resv_regions() callback
- * for simple reservations. Memory allocated for each reserved region will be
- * freed. If an IOMMU driver allocates additional resources per region, it is
- * going to have to implement a custom callback.
+ * for simple reservations. If a per region callback is provided that will be
+ * used to free all memory allocations associated with the reserved region or
+ * else just free up the memory for the regions. If an IOMMU driver allocates
+ * additional resources per region, it is going to have to implement a custom
+ * callback.
  */
 void generic_iommu_put_resv_regions(struct device *dev, struct list_head *list)
 {
struct iommu_resv_region *entry, *next;
 
-   list_for_each_entry_safe(entry, next, list, list)
-   kfree(entry);
+   list_for_each_entry_safe(entry, next, list, list) {
+   if (entry->free)
+   entry->free(dev, entry);
+   else
+   kfree(entry);
+   }
 }
 EXPORT_SYMBOL(generic_iommu_put_resv_regions);
 
diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index 9208eca4b0d1..68bcfb3a06d7 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -134,6 +134,7 @@ enum iommu_resv_type {
  * @length: Length of the region in bytes
  * @prot: IOMMU Protection flags (READ/WRITE/...)
  * @type: Type of the reserved region
+ * @free: Callback to free associated memory allocations
  */
 struct iommu_resv_region {
struct list_headlist;
@@ -141,6 +142,7 @@ struct iommu_resv_region {
size_t  length;
int prot;
enum iommu_resv_typetype;
+   void (*free)(struct device *dev, struct iommu_resv_region *region);
 };
 
 /**
-- 
2.17.1

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

[PATCH v12 0/9] ACPI/IORT: Support for IORT RMR node

2022-05-03 Thread Shameer Kolothum via iommu
Hi

v11 --> v12
  -Minor fix in patch #4 to address the issue reported by the kernel test robot.
  -Added R-by tags by Christoph(patch #1) and Lorenzo(patch #4).
  -Added T-by from Steve to all relevant patches. Many thanks!.

Please note, this series has a dependency on the ACPICA header patch
here[1]. 

Please take a look and let me know.

Thanks,
Shameer
[1] https://lore.kernel.org/all/44610361.fMDQidcC6G@kreacher/

From old:
We have faced issues with 3408iMR RAID controller cards which
fail to boot when SMMU is enabled. This is because these
controllers make use of host memory for various caching related
purposes and when SMMU is enabled the iMR firmware fails to
access these memory regions as there is no mapping for them.
IORT RMR provides a way for UEFI to describe and report these
memory regions so that the kernel can make a unity mapping for
these in SMMU.

Change History:

v10 --> v11
 -Addressed Christoph's comments. We now have a  callback to 
  struct iommu_resv_region to free all related memory and also dropped
  the FW specific union and now has a container struct iommu_iort_rmr_data.
  See patches #1 & #4
 -Added R-by from Christoph.
 -Dropped R-by from Lorenzo for patches #4 & #5 due to the above changes.
 -Also dropped T-by from Steve and Laurentiu. Many thanks for your test
  efforts. I have done basic sanity testing on my platform but please
  do it again at your end.

v9 --> v10
 - Dropped patch #1 ("Add temporary RMR node flag definitions") since
   the ACPICA header updates patch is now in the mailing list
 - Based on the suggestion from Christoph, introduced a 
   resv_region_free_fw_data() callback in struct iommu_resv_region and
   used that to free RMR specific memory allocations.

v8 --> v9
 - Adressed comments from Robin on interfaces.
 - Addressed comments from Lorenzo.

v7 --> v8
  - Patch #1 has temp definitions for RMR related changes till
    the ACPICA header changes are part of kernel.
  - No early parsing of RMR node info and is only parsed at the
    time of use.
  - Changes to the RMR get/put API format compared to the
    previous version.
  - Support for RMR descriptor shared by multiple stream IDs.

v6 --> v7
 -fix pointed out by Steve to the SMMUv2 SMR bypass install in patch #8.

v5 --> v6
- Addressed comments from Robin & Lorenzo.
  : Moved iort_parse_rmr() to acpi_iort_init() from
    iort_init_platform_devices().
  : Removed use of struct iort_rmr_entry during the initial
    parse. Using struct iommu_resv_region instead.
  : Report RMR address alignment and overlap errors, but continue.
  : Reworked arm_smmu_init_bypass_stes() (patch # 6).
- Updated SMMUv2 bypass SMR code. Thanks to Jon N (patch #8).
- Set IOMMU protection flags(IOMMU_CACHE, IOMMU_MMIO) based
  on Type of RMR region. Suggested by Jon N.

v4 --> v5
 -Added a fw_data union to struct iommu_resv_region and removed
  struct iommu_rmr (Based on comments from Joerg/Robin).
 -Added iommu_put_rmrs() to release mem.
 -Thanks to Steve for verifying on SMMUv2, but not added the Tested-by
  yet because of the above changes.

v3 -->v4
-Included the SMMUv2 SMR bypass install changes suggested by
 Steve(patch #7)
-As per Robin's comments, RMR reserve implementation is now
 more generic  (patch #8) and dropped v3 patches 8 and 10.
-Rebase to 5.13-rc1

RFC v2 --> v3
 -Dropped RFC tag as the ACPICA header changes are now ready to be
  part of 5.13[0]. But this series still has a dependency on that patch.
 -Added IORT E.b related changes(node flags, _DSM function 5 checks for
  PCIe).
 -Changed RMR to stream id mapping from M:N to M:1 as per the spec and
  discussion here[1].
 -Last two patches add support for SMMUv2(Thanks to Jon Nettleton!)

Jon Nettleton (1):
  iommu/arm-smmu: Get associated RMR info and install bypass SMR

Shameer Kolothum (8):
  iommu: Introduce a callback to struct iommu_resv_region
  ACPI/IORT: Make iort_iommu_msi_get_resv_regions() return void
  ACPI/IORT: Provide a generic helper to retrieve reserve regions
  ACPI/IORT: Add support to retrieve IORT RMR reserved regions
  ACPI/IORT: Add a helper to retrieve RMR info directly
  iommu/arm-smmu-v3: Introduce strtab init helper
  iommu/arm-smmu-v3: Refactor arm_smmu_init_bypass_stes() to force
bypass
  iommu/arm-smmu-v3: Get associated RMR info and install bypass STE

 drivers/acpi/arm64/iort.c   | 360 ++--
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c |  78 -
 drivers/iommu/arm/arm-smmu/arm-smmu.c   |  52 +++
 drivers/iommu/dma-iommu.c   |   2 +-
 drivers/iommu/iommu.c   |  16 +-
 include/linux/acpi_iort.h   |  14 +-
 include/linux/iommu.h   |  10 +
 7 files changed, 486 insertions(+), 46 deletions(-)

-- 
2.17.1

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

[PATCH 2/2] iommu/arm-smmu-qcom: Add SC8280XP support

2022-05-03 Thread Bjorn Andersson
Add the Qualcomm SC8280XP platform to the list of compatible for which
the Qualcomm-impl of the ARM SMMU should apply.

Signed-off-by: Bjorn Andersson 
---
 drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c 
b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c
index ba6298c7140e..7820711c4560 100644
--- a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c
+++ b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c
@@ -408,6 +408,7 @@ static const struct of_device_id __maybe_unused 
qcom_smmu_impl_of_match[] = {
{ .compatible = "qcom,sc7180-smmu-500" },
{ .compatible = "qcom,sc7280-smmu-500" },
{ .compatible = "qcom,sc8180x-smmu-500" },
+   { .compatible = "qcom,sc8280xp-smmu-500" },
{ .compatible = "qcom,sdm630-smmu-v2" },
{ .compatible = "qcom,sdm845-smmu-500" },
{ .compatible = "qcom,sm6125-smmu-500" },
-- 
2.35.1

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


[PATCH 0/2] iommu/arm-smmu-qcom: Add SC8280XP support

2022-05-03 Thread Bjorn Andersson
This adds the compatible for the Qualcomm SC8280XP platform and associate the
Qualcomm impl in the ARM SMMU driver to it.

Bjorn Andersson (2):
  dt-bindings: arm-smmu: Add compatible for Qualcomm SC8280XP
  iommu/arm-smmu-qcom: Add SC8280XP support

 Documentation/devicetree/bindings/iommu/arm,smmu.yaml | 1 +
 drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c| 1 +
 2 files changed, 2 insertions(+)

-- 
2.35.1

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


[PATCH 1/2] dt-bindings: arm-smmu: Add compatible for Qualcomm SC8280XP

2022-05-03 Thread Bjorn Andersson
Add compatible for the Qualcomm SC8280XP platform to the ARM SMMU
DeviceTree binding.

Signed-off-by: Bjorn Andersson 
---
 Documentation/devicetree/bindings/iommu/arm,smmu.yaml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu.yaml 
b/Documentation/devicetree/bindings/iommu/arm,smmu.yaml
index da5381c8ee11..ba38ce054062 100644
--- a/Documentation/devicetree/bindings/iommu/arm,smmu.yaml
+++ b/Documentation/devicetree/bindings/iommu/arm,smmu.yaml
@@ -37,6 +37,7 @@ properties:
   - qcom,sc7180-smmu-500
   - qcom,sc7280-smmu-500
   - qcom,sc8180x-smmu-500
+  - qcom,sc8280xp-smmu-500
   - qcom,sdm845-smmu-500
   - qcom,sdx55-smmu-500
   - qcom,sm6350-smmu-500
-- 
2.35.1

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


Re: [PATCH v7 00/36] MT8195 and MT8186 IOMMU SUPPORT

2022-05-03 Thread Matthias Brugger




On 03/05/2022 09:13, Yong Wu wrote:

This patchset adds MT8195 and MT8186 iommu support.

MT8195 have 3 IOMMU HWs. 2 IOMMU HW is for multimedia, and 1 IOMMU HW is
for infra-master, like PCIe/USB.

About the 2 MM IOMMU HW, something like this:

 IOMMU(VDO)  IOMMU(VPP)
|   |
   SMI_COMMON(VDO)  SMI_COMMON(VPP)
   --- 
   |  |   ...  |  | ...
 larb0 larb2  ...larb1 larb3...

these two MM IOMMU HW share a pgtable.

About the INFRA IOMMU, it don't have larbs, the master connects the iommu
directly. It use a independent pgtable.

Also, mt8195 IOMMU bank supports. Normally the IOMMU register size only
is 0x1000. In this IOMMU HW, the register size is 5 * 0x1000. each 0x1000
is a bank. the banks' register look like this:
  
  |bank0  | bank1 | bank2 | bank3 | bank4|
  
  |global |
  |control| null
  |regs   |
  -
  |bank   |bank   |bank   |bank   |bank   |
  |regs   |regs   |regs   |regs   |regs   |
  |   |   |   |   |   |
  -
All the banks share some global control registers, and each bank have its
special bank registers, like pgtable base register, tlb operation registers,
the fault status registers.
  
In mt8195, we enable this bank feature for infra iommu, We put PCIe in bank0

and USB in bank4. they have independent pgtable.

MT8186 is based on MT8195, it just has two patches.

Change note:
v7: 1) Update the changes from Matthias. like add a new function for 
readability.
 2) Add mt8186 into this patchset, It may be helpful for maintainer to 
apply.


For the whole series:

Reviewed-by: Matthias Brugger 



v6: 
https://lore.kernel.org/linux-iommu/20220407075726.17771-1-yong...@mediatek.com/
 Rebase on v5.18-rc1.

v5: 
https://lore.kernel.org/linux-iommu/20220217113453.13658-1-yong...@mediatek.com
1) Base on next-20220216
2) Remove a patch for kmalloc for protect buffer. keep the kzalloc for it.
3) minor fix from AngeloGioacchino, like rename the error label name
(data_unlock to err_unlock).
Note, keep the TODO for component compare_of[26/34].

v4: 
https://lore.kernel.org/linux-iommu/20220125085634.17972-1-yong...@mediatek.com/
1) Base on v5.16-rc1
2) Base on tlb logic 2 patchset, some patches in v3 has already gone
through that patchset.
3) Due to the unreadable union for v1/v2(comment in 26/33 of v3), I
separate mtk_iommu_data for v1 and v2 totally, then remove mtk_iommu.h.
please see patch[26/35][27/35].
4) add two mutex for the internal data. patch[6/35][7/35].
5) add a new flag PM_CLK_AO.

v3: 
https://lore.kernel.org/linux-mediatek/20210923115840.17813-1-yong...@mediatek.com/
 1) base on v5.15-rc1
 2) Adjust devlink with smi-common, not use the property(sub-sommon).
 3) Adjust tlb_flush_all flow,
a) Fix tlb_flush_all only is supported in bank0.
b) add tlb-flush-all in the resume callback.
c) remove the pm status checking in tlb-flush-all.
The reason are showed in the commit message.
 4) Allow IOMMU_DOMAIN_UNMANAGED since PCIe VFIO use that.
 5) Fix a clk warning and a null abort when unbind the iommu driver.

v2: 
https://lore.kernel.org/linux-mediatek/20210813065324.29220-1-yong...@mediatek.com/
 1) Base on v5.14-rc1.
 2) Fix build fail for arm32.
 3) Fix dt-binding issue from Rob.
 4) Fix the bank issue when tlb flush. v1 always use bank->base.
 5) adjust devlink with smi-common since the node may be smi-sub-common.
 6) other changes: like reword some commit message(removing many
"This patch..."); seperate serveral patches.

v1: 
https://lore.kernel.org/linux-mediatek/20210630023504.18177-1-yong...@mediatek.com/
 Base on v5.13-rc1

Yong Wu (36):
   dt-bindings: mediatek: mt8195: Add binding for MM IOMMU
   dt-bindings: mediatek: mt8195: Add binding for infra IOMMU
   dt-bindings: mediatek: mt8186: Add binding for MM iommu
   iommu/mediatek: Fix 2 HW sharing pgtable issue
   iommu/mediatek: Add list_del in mtk_iommu_remove
   iommu/mediatek: Remove clk_disable in mtk_iommu_remove
   iommu/mediatek: Add mutex for m4u_group and m4u_dom in data
   iommu/mediatek: Add mutex for data in the mtk_iommu_domain
   iommu/mediatek: Adapt sharing and non-sharing pgtable case
   iommu/mediatek: Add 12G~16G support for multi domains
   iommu/mediatek: Add a flag DCM_DISABLE
   iommu/mediatek: Add a flag STD_AXI_MODE
   iommu/mediatek: Remove the granule in the tlb flush
   iommu/mediatek: Always enable output PA over 32bits in isr
   iommu/mediatek: Add SUB_COMMON_3BITS flag
   iommu/mediatek: Add IOMMU_TYPE flag
   iommu/mediatek: Contain MM IOMMU flow with the MM TYPE
   iommu/mediatek: Adjust device link when it is 

Re: [RESEND PATCH v8 00/11] Fix BUG_ON in vfio_iommu_group_notifier()

2022-05-03 Thread Jason Gunthorpe via iommu
On Tue, May 03, 2022 at 02:04:37PM +0100, Robin Murphy wrote:

> > I'm guessing SMMU3 needs to call it's arm_smmu_detach_dev(master) from
> > the detach_dev op and null it's cached copy of the domain, but I don't
> > know this driver.. Robin?
> 
> The original intent was that .detach_dev is deprecated in favour of default
> domains, and when the latter are in use, a device is always attached
> *somewhere* once probed (i.e. group->domain is never NULL). At face value,
> the neatest fix IMO would probably be for SMMUv3's .domain_free to handle
> smmu_domain->devices being non-empty and detach them at that point. However
> that wouldn't be viable for virtio-iommu or anyone else keeping an internal
> one-way association of devices to their current domains.

Oh wow that is not obvious

Actually, I think it is much worse than this because
iommu_group_claim_dma_owner() does a __iommu_detach_group() with the
expecation that this would actually result in DMA being blocked,
immediately. The idea that __iomuu_detatch_group() is a NOP is kind of
scary.

Leaving the group attached to the kernel DMA domain will allow
userspace to DMA to all kernel memory :\

So one approach could be to block use of iommu_group_claim_dma_owner()
if no detatch_dev op is present and then go through and put them back
or do something else. This could be short-term OK if we add an op to
SMMUv3, but long term everything would have to be fixed

Or we can allocate a dummy empty/blocked domain during
iommu_group_claim_dma_owner() and attach it whenever.

The really ugly trick is that detatch cannot fail, so attach to this
blocking domain must also not fail - IMHO this is a very complicated
API to expect for the driver to implement correctly... I see there is
already a WARN_ON that attaching to the default domain cannot
fail. Maybe this warrants an actual no-fail attach op so the driver
can be more aware of this..

And some of these internal APIs could stand some adjusting if we
really never want a true "detatch" it is always some kind of
replace/swap type operation, either to the default domain or to the
blocking domain.

> We *could* stay true to the original paradigm by introducing some real usage
> of IOMMU_DOMAIN_BLOCKED, such that we could keep one or more of those around
> to actively attach to instead of having groups in this unattached limbo
> state, but that's a bigger job involving adding support to drivers as well;
> too much for a quick fix now...

I suspect for the short term we can get by with an empty mapping
domain - using DOMAIN_BLOCKED is a bit of a refinement.

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


Re: [RESEND PATCH v8 00/11] Fix BUG_ON in vfio_iommu_group_notifier()

2022-05-03 Thread Robin Murphy

On 2022-05-02 17:42, Jason Gunthorpe wrote:

On Mon, May 02, 2022 at 12:12:04PM -0400, Qian Cai wrote:

On Mon, Apr 18, 2022 at 08:49:49AM +0800, Lu Baolu wrote:

Hi Joerg,

This is a resend version of v8 posted here:
https://lore.kernel.org/linux-iommu/20220308054421.847385-1-baolu...@linux.intel.com/
as we discussed in this thread:
https://lore.kernel.org/linux-iommu/yk%2fq1bgn8pc5h...@8bytes.org/

All patches can be applied perfectly except this one:
  - [PATCH v8 02/11] driver core: Add dma_cleanup callback in bus_type
It conflicts with below refactoring commit:
  - 4b775aaf1ea99 "driver core: Refactor sysfs and drv/bus remove hooks"
The conflict has been fixed in this post.

No functional changes in this series. I suppress cc-ing this series to
all v8 reviewers in order to avoid spam.

Please consider it for your iommu tree.


Reverting this series fixed an user-after-free while doing SR-IOV.

  BUG: KASAN: use-after-free in __lock_acquire
  Read of size 8 at addr 080279825d78 by task qemu-system-aar/22429
  CPU: 24 PID: 22429 Comm: qemu-system-aar Not tainted 5.18.0-rc5-next-20220502 
#69
  Call trace:
   dump_backtrace
   show_stack
   dump_stack_lvl
   print_address_description.constprop.0
   print_report
   kasan_report
   __asan_report_load8_noabort
   __lock_acquire
   lock_acquire.part.0
   lock_acquire
   _raw_spin_lock_irqsave
   arm_smmu_detach_dev
   arm_smmu_detach_dev at drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c:2377
   arm_smmu_attach_dev


Hum.

So what has happened is that VFIO does this sequence:

  iommu_detach_group()
  iommu_domain_free()
  iommu_group_release_dma_owner()

Which, I think should be valid, API wise.

 From what I can see reading the code SMMUv3 blows up above because it
doesn't have a detach_dev op:

.default_domain_ops = &(const struct iommu_domain_ops) {
.attach_dev = arm_smmu_attach_dev,
.map_pages  = arm_smmu_map_pages,
.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,
.enable_nesting = arm_smmu_enable_nesting,
.free   = arm_smmu_domain_free,
}

But it is internally tracking the domain inside the master - so when
the next domain is attached it does this:

static void arm_smmu_detach_dev(struct arm_smmu_master *master)
{
struct arm_smmu_domain *smmu_domain = master->domain;

spin_lock_irqsave(_domain->devices_lock, flags);

And explodes as the domain has been freed but master->domain was not
NULL'd.

It worked before because iommu_detach_group() used to attach the
default group and that was before the domain was freed in the above
sequence.


Oof, I totally overlooked the significance of that little subtlety in 
review :(



I'm guessing SMMU3 needs to call it's arm_smmu_detach_dev(master) from
the detach_dev op and null it's cached copy of the domain, but I don't
know this driver.. Robin?


The original intent was that .detach_dev is deprecated in favour of 
default domains, and when the latter are in use, a device is always 
attached *somewhere* once probed (i.e. group->domain is never NULL). At 
face value, the neatest fix IMO would probably be for SMMUv3's 
.domain_free to handle smmu_domain->devices being non-empty and detach 
them at that point. However that wouldn't be viable for virtio-iommu or 
anyone else keeping an internal one-way association of devices to their 
current domains.


If we're giving up entirely on that notion of .detach_dev going away 
then all default-domain-supporting drivers probably want checking to 
make sure that path hasn't bitrotted; both Arm SMMU drivers had it 
proactively removed 6 years ago; virtio-iommu never had it at all; newer 
drivers like apple-dart have some code there, but it won't have ever run 
until now.


We *could* stay true to the original paradigm by introducing some real 
usage of IOMMU_DOMAIN_BLOCKED, such that we could keep one or more of 
those around to actively attach to instead of having groups in this 
unattached limbo state, but that's a bigger job involving adding support 
to drivers as well; too much for a quick fix now...


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


Re: [PATCH 6/7] dt-bindings: serial: renesas, scif: R-Car V3U is R-Car Gen4

2022-05-03 Thread Krzysztof Kozlowski
On 02/05/2022 15:34, Geert Uytterhoeven wrote:
> Despite the name, R-Car V3U is the first member of the R-Car Gen4
> family.  Hence move its compatible value to the R-Car Gen4 section.
> 


Acked-by: Krzysztof Kozlowski 


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


Re: [PATCH 5/7] dt-bindings: serial: renesas,hscif: R-Car V3U is R-Car Gen4

2022-05-03 Thread Krzysztof Kozlowski
On 02/05/2022 15:34, Geert Uytterhoeven wrote:
> Despite the name, R-Car V3U is the first member of the R-Car Gen4
> family.  Hence move its compatible value to the R-Car Gen4 section.
> 
> Signed-off-by: Geert Uytterhoeven 

Acked-by: Krzysztof Kozlowski 


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


Re: [PATCH 4/7] dt-bindings: renesas,rcar-dmac: R-Car V3U is R-Car Gen4

2022-05-03 Thread Krzysztof Kozlowski
On 02/05/2022 15:34, Geert Uytterhoeven wrote:
> Despite the name, R-Car V3U is the first member of the R-Car Gen4
> family.  Hence move its compatible value to the R-Car Gen4 section.
> 
> Signed-off-by: Geert Uytterhoeven 
> ---
>  .../devicetree/bindings/dma/renesas,rcar-dmac.yaml | 10 --
>  1 file changed, 4 insertions(+), 6 deletions(-)

Acked-by: Krzysztof Kozlowski 


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


Re: [PATCH 7/7] dt-bindings: watchdog: renesas,wdt: R-Car V3U is R-Car Gen4

2022-05-03 Thread Krzysztof Kozlowski
On 02/05/2022 15:34, Geert Uytterhoeven wrote:
> Despite the name, R-Car V3U is the first member of the R-Car Gen4
> family.  Hence move its compatible value to the R-Car Gen4 section.
> 
> Signed-off-by: Geert Uytterhoeven 


Acked-by: Krzysztof Kozlowski 


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


Re: [PATCH 3/7] dt-bindings: iommu: renesas, ipmmu-vmsa: R-Car V3U is R-Car Gen4

2022-05-03 Thread Krzysztof Kozlowski
On 02/05/2022 15:34, Geert Uytterhoeven wrote:
> Despite the name, R-Car V3U is the first member of the R-Car Gen4
> family.  Hence move its compatible value to the R-Car Gen4 section.
> 
> Signed-off-by: Geert Uytterhoeven 

Acked-by: Krzysztof Kozlowski 


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


Re: [PATCH 2/7] dt-bindings: i2c: renesas,rcar-i2c: R-Car V3U is R-Car Gen4

2022-05-03 Thread Krzysztof Kozlowski
On 02/05/2022 15:34, Geert Uytterhoeven wrote:
> Despite the name, R-Car V3U is the first member of the R-Car Gen4
> family.  I2C on R-Car V3U also supports some extra features (e.g. Slave
> Clock Stretch Select), which are supported by other R-Car Gen4 SoCs, but
> not by any other R-Car Gen3 SoC.
> 
> Hence move its compatible value to the R-Car Gen4 section.
> 
> Signed-off-by: Geert Uytterhoeven 


Acked-by: Krzysztof Kozlowski 


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


Re: [PATCH 1/7] dt-bindings: gpio: renesas,rcar-gpio: R-Car V3U is R-Car Gen4

2022-05-03 Thread Krzysztof Kozlowski
On 02/05/2022 15:34, Geert Uytterhoeven wrote:
> Despite the name, R-Car V3U is the first member of the R-Car Gen4
> family.  Hence move its compatible value to the R-Car Gen4 section.
> 
> Signed-off-by: Geert Uytterhoeven 


Acked-by: Krzysztof Kozlowski 


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


Re: [PATCH 3/4] dt-bindings: arm-smmu: Add binding for SDX65 SMMU

2022-05-03 Thread Krzysztof Kozlowski
On 02/05/2022 10:37, Rohit Agarwal wrote:
> Add devicetree binding for Qualcomm SDX65 SMMU.
> 
> Signed-off-by: Rohit Agarwal 


Acked-by: Krzysztof Kozlowski 


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


Re: [PATCH RFC 00/19] IOMMUFD Dirty Tracking

2022-05-03 Thread Joao Martins
On 5/2/22 19:52, Jason Gunthorpe wrote:
> On Mon, May 02, 2022 at 12:11:07PM -0600, Alex Williamson wrote:
>> On Fri, 29 Apr 2022 05:45:20 +
>> "Tian, Kevin"  wrote:
 From: Joao Martins 
  3) Unmapping an IOVA range while returning its dirty bit prior to
 unmap. This case is specific for non-nested vIOMMU case where an
 erronous guest (or device) DMAing to an address being unmapped at the
 same time.  
>>>
>>> an erroneous attempt like above cannot anticipate which DMAs can
>>> succeed in that window thus the end behavior is undefined. For an
>>> undefined behavior nothing will be broken by losing some bits dirtied
>>> in the window between reading back dirty bits of the range and
>>> actually calling unmap. From guest p.o.v. all those are black-box
>>> hardware logic to serve a virtual iotlb invalidation request which just
>>> cannot be completed in one cycle.
>>>
>>> Hence in reality probably this is not required except to meet vfio
>>> compat requirement. Just in concept returning dirty bits at unmap
>>> is more accurate.
>>>
>>> I'm slightly inclined to abandon it in iommufd uAPI.
>>
>> Sorry, I'm not following why an unmap with returned dirty bitmap
>> operation is specific to a vIOMMU case, or in fact indicative of some
>> sort of erroneous, racy behavior of guest or device.
> 
> It is being compared against the alternative which is to explicitly
> query dirty then do a normal unmap as two system calls and permit a
> race.
> 
> The only case with any difference is if the guest is racing DMA with
> the unmap - in which case it is already indeterminate for the guest if
> the DMA will be completed or not. 
> 
> eg on the vIOMMU case if the guest races DMA with unmap then we are
> already fine with throwing away that DMA because that is how the race
> resolves during non-migration situations, so resovling it as throwing
> away the DMA during migration is OK too.
> 

Exactly.

Even current unmap (ignoring dirties) isn't race-free and DMA could still be
happening between clearing PTE until the IOTLB flush.

The code in this series *attempted* at tackling races against hw IOMMU updates
to the A/D bits at the same time we are clearing the IOPTEs. But it didn't fully
addressed the race with DMA.

The current code (IIUC) just assumes it is dirty if it as pinned and DMA mapped,
so maybe it avoided some of these fundamental questions...

So really the comparison is whether we care of fixing the race *during unmap* --
which really device shouldn't be DMA-ing to in the first place -- that we need
to go out of our way to block DMA writes from happening then fetch dirties and
then unmap. Or can we fetch dirties and then unmap as two separate operations.

>> We need the flexibility to support memory hot-unplug operations
>> during migration,
> 
> I would have thought that hotplug during migration would simply
> discard all the data - how does it use the dirty bitmap?
> 

hmmm I don't follow either -- why one would we care about hot-unplugged
memory being dirty? Unless Alex is thinking that the guest would take
initiative in hotunplugging+hotplugging and expecting the same data to
be there, like pmem style...?

>> This was implemented as a single operation specifically to avoid
>> races where ongoing access may be available after retrieving a
>> snapshot of the bitmap.  Thanks,
> 
> The issue is the cost.
> 
> On a real iommu elminating the race is expensive as we have to write
> protect the pages before query dirty, which seems to be an extra IOTLB
> flush.
> 

... and that is only the DMA performance part affecting the endpoint
device. In software, there's also the extra overhead of walking the IOMMU
pagetables twice. So it's like unmap being 2x more expensive.


> It is not clear if paying this cost to become atomic is actually
> something any use case needs.
> 
> So, I suggest we think about a 3rd op 'write protect and clear
> dirties' that will be followed by a normal unmap - the extra op will
> have the extra oveheard and userspace can decide if it wants to pay or
> not vs the non-atomic read dirties operation. And lets have a use case
> where this must be atomic before we implement it..
> 

Definitely, I am happy to implement it if there's a use-case. But
I am not sure there's one right now aside from theory only? Have we
see issues that would otherwise require this?

> The downside is we loose a little bit of efficiency by unbundling
> these steps, the upside is that it doesn't require quite as many
> special iommu_domain/etc paths.
> 
> (Also Joao, you should probably have a read and do not clear dirty
> operation with the idea that the next operation will be unmap - then
> maybe we can avoid IOTLB flushing..)

Yes, that's a great idea. I am thinking of adding a regular @flags field to
the GET_DIRTY_IOVA and iommu domain op argument counterpart.

Albeit, from iommu kAPI side at the end of the day this primitive is an IO
pagetable walker helper which lets it check/manipulate some of 

Re: [PATCH 2/2] iommu/mediatek: Enable allocating page table in normal memory

2022-05-03 Thread Yong Wu via iommu
Hi YF,

Thanks very much for this patch. Nearly all the lastest SoC like
mt8192/mt8195 support this.

On Fri, 2022-04-29 at 22:34 +0800, yf.w...@mediatek.com wrote:
> From: Yunfei Wang 
> 
> Add the quirk IO_PGTABLE_QUIRK_ARM_MTK_TTBR_EXT support, so that
> level 2 page table can allocate in normal memory.

Could you help comment more detailedly here and in the title?, this
patch just allows the level 2 pgtable PA up to 35bits, not only in
ZONE_DMA32(GFP_DMA32).

> 
> Signed-off-by: Ning Li 
> Signed-off-by: Yunfei Wang 
> Cc:  # 5.10.*

If you add this for stable, Which commit do you need for "Fixes:" tag?

It looks you add a new feature, rather than fixing a bug of the current
kernel. I didn't get a issue report for this. If this is a bug, we need
more information like under which condition/SoC the error will occur.

The code is ok for me.

Thanks.

> ---
>  drivers/iommu/mtk_iommu.c | 7 ++-
>  1 file changed, 6 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c
> index 6fd75a60abd6..27481f562df7 100644
> --- a/drivers/iommu/mtk_iommu.c
> +++ b/drivers/iommu/mtk_iommu.c
> @@ -118,6 +118,7 @@
>  #define WR_THROT_EN  BIT(6)
>  #define HAS_LEGACY_IVRP_PADDRBIT(7)
>  #define IOVA_34_EN   BIT(8)
> +#define PGTABLE_L2_PA_35_EN  BIT(9)
>  
>  #define MTK_IOMMU_HAS_FLAG(pdata, _x) \
>   pdata)->flags) & (_x)) == (_x))
> @@ -401,6 +402,9 @@ static int mtk_iommu_domain_finalise(struct
> mtk_iommu_domain *dom,
>   .iommu_dev = data->dev,
>   };
>  
> + if (MTK_IOMMU_HAS_FLAG(data->plat_data, PGTABLE_L2_PA_35_EN))
> + dom->cfg.quirks |= IO_PGTABLE_QUIRK_ARM_MTK_TTBR_EXT;
> +
>   if (MTK_IOMMU_HAS_FLAG(data->plat_data, HAS_4GB_MODE))
>   dom->cfg.oas = data->enable_4GB ? 33 : 32;
>   else
> @@ -1038,7 +1042,8 @@ static const struct mtk_iommu_plat_data
> mt2712_data = {
>  
>  static const struct mtk_iommu_plat_data mt6779_data = {
>   .m4u_plat  = M4U_MT6779,
> - .flags = HAS_SUB_COMM | OUT_ORDER_WR_EN | WR_THROT_EN,
> + .flags = HAS_SUB_COMM | OUT_ORDER_WR_EN | WR_THROT_EN |
> +  PGTABLE_L2_PA_35_EN,
>   .inv_sel_reg   = REG_MMU_INV_SEL_GEN2,
>   .iova_region   = single_domain,
>   .iova_region_nr = ARRAY_SIZE(single_domain),

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


Re: [PATCH v4 05/11] iommu/sva: Assign a PASID to mm on PASID allocation and free it on mm exit

2022-05-03 Thread Jean-Philippe Brucker
On Sat, Apr 30, 2022 at 03:33:17PM +0800, Baolu Lu wrote:
> Jean, another quick question about the iommu_sva_bind_device()
> 
> /**
>  * iommu_sva_bind_device() - Bind a process address space to a device
>  * @dev: the device
>  * @mm: the mm to bind, caller must hold a reference to it
>  * @drvdata: opaque data pointer to pass to bind callback
> 
> This interface requires the caller to take a reference to mm. Which
> reference should it take, mm->mm_count or mm->mm_users? It's better to
> make it explicit in this comment.

Agreed, it's mm_users as required by mmu_notifier_register()

Thanks,
Jean

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


[PATCH v7 36/36] iommu/mediatek: Add mt8186 iommu support

2022-05-03 Thread Yong Wu via iommu
Add mt8186 iommu supports.

Signed-off-by: Anan Sun 
Signed-off-by: Yong Wu 
Reviewed-by: Matthias Brugger 
Reviewed-by: AngeloGioacchino Del Regno 

---
 drivers/iommu/mtk_iommu.c | 16 
 1 file changed, 16 insertions(+)

diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c
index 0fa1d5240ac6..71b2ace74cd6 100644
--- a/drivers/iommu/mtk_iommu.c
+++ b/drivers/iommu/mtk_iommu.c
@@ -160,6 +160,7 @@ enum mtk_iommu_plat {
M4U_MT8167,
M4U_MT8173,
M4U_MT8183,
+   M4U_MT8186,
M4U_MT8192,
M4U_MT8195,
 };
@@ -1437,6 +1438,20 @@ static const struct mtk_iommu_plat_data mt8183_data = {
.larbid_remap = {{0}, {4}, {5}, {6}, {7}, {2}, {3}, {1}},
 };
 
+static const struct mtk_iommu_plat_data mt8186_data_mm = {
+   .m4u_plat   = M4U_MT8186,
+   .flags  = HAS_BCLK | HAS_SUB_COMM_2BITS | OUT_ORDER_WR_EN |
+ WR_THROT_EN | IOVA_34_EN | MTK_IOMMU_TYPE_MM,
+   .larbid_remap   = {{0}, {1, MTK_INVALID_LARBID, 8}, {4}, {7}, {2}, {9, 
11, 19, 20},
+  {MTK_INVALID_LARBID, 14, 16},
+  {MTK_INVALID_LARBID, 13, MTK_INVALID_LARBID, 17}},
+   .inv_sel_reg= REG_MMU_INV_SEL_GEN2,
+   .banks_num  = 1,
+   .banks_enable   = {true},
+   .iova_region= mt8192_multi_dom,
+   .iova_region_nr = ARRAY_SIZE(mt8192_multi_dom),
+};
+
 static const struct mtk_iommu_plat_data mt8192_data = {
.m4u_plat   = M4U_MT8192,
.flags  = HAS_BCLK | HAS_SUB_COMM_2BITS | OUT_ORDER_WR_EN |
@@ -1503,6 +1518,7 @@ static const struct of_device_id mtk_iommu_of_ids[] = {
{ .compatible = "mediatek,mt8167-m4u", .data = _data},
{ .compatible = "mediatek,mt8173-m4u", .data = _data},
{ .compatible = "mediatek,mt8183-m4u", .data = _data},
+   { .compatible = "mediatek,mt8186-iommu-mm",.data = 
_data_mm}, /* mm: m4u */
{ .compatible = "mediatek,mt8192-m4u", .data = _data},
{ .compatible = "mediatek,mt8195-iommu-infra", .data = 
_data_infra},
{ .compatible = "mediatek,mt8195-iommu-vdo",   .data = 
_data_vdo},
-- 
2.18.0

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


[PATCH v7 35/36] iommu/mediatek: mt8195: Enable multi banks for infra iommu

2022-05-03 Thread Yong Wu via iommu
Enable the multi-bank functions for infra-iommu. We put PCIE in bank0
and USB in the last bank(bank4). and we don't use the other banks
currently, disable them.

Signed-off-by: Yong Wu 
Reviewed-by: AngeloGioacchino Del Regno 

---
 drivers/iommu/mtk_iommu.c | 7 +--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c
index d3e8773b4c47..0fa1d5240ac6 100644
--- a/drivers/iommu/mtk_iommu.c
+++ b/drivers/iommu/mtk_iommu.c
@@ -1456,8 +1456,11 @@ static const struct mtk_iommu_plat_data 
mt8195_data_infra = {
MTK_IOMMU_TYPE_INFRA | IFA_IOMMU_PCIE_SUPPORT,
.pericfg_comp_str = "mediatek,mt8195-pericfg_ao",
.inv_sel_reg  = REG_MMU_INV_SEL_GEN2,
-   .banks_num= 1,
-   .banks_enable = {true},
+   .banks_num= 5,
+   .banks_enable = {true, false, false, false, true},
+   .banks_portmsk= {[0] = GENMASK(19, 16), /* PCIe */
+[4] = GENMASK(31, 20), /* USB */
+   },
.iova_region  = single_domain,
.iova_region_nr   = ARRAY_SIZE(single_domain),
 };
-- 
2.18.0

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


[PATCH v7 34/36] iommu/mediatek: Backup/restore regsiters for multi banks

2022-05-03 Thread Yong Wu via iommu
Each bank has some independent registers. thus backup/restore them for
each a bank when suspend and resume.

Signed-off-by: Yong Wu 
Reviewed-by: AngeloGioacchino Del Regno 

---
 drivers/iommu/mtk_iommu.c | 46 ++-
 1 file changed, 31 insertions(+), 15 deletions(-)

diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c
index 400dea33aea1..d3e8773b4c47 100644
--- a/drivers/iommu/mtk_iommu.c
+++ b/drivers/iommu/mtk_iommu.c
@@ -173,11 +173,12 @@ struct mtk_iommu_suspend_reg {
u32 misc_ctrl;
u32 dcm_dis;
u32 ctrl_reg;
-   u32 int_control0;
-   u32 int_main_control;
-   u32 ivrp_paddr;
u32 vld_pa_rng;
u32 wr_len_ctrl;
+
+   u32 int_control[MTK_IOMMU_BANK_MAX];
+   u32 int_main_control[MTK_IOMMU_BANK_MAX];
+   u32 ivrp_paddr[MTK_IOMMU_BANK_MAX];
 };
 
 struct mtk_iommu_plat_data {
@@ -1302,16 +1303,23 @@ static int __maybe_unused 
mtk_iommu_runtime_suspend(struct device *dev)
 {
struct mtk_iommu_data *data = dev_get_drvdata(dev);
struct mtk_iommu_suspend_reg *reg = >reg;
-   void __iomem *base = data->bank[0].base;
+   void __iomem *base;
+   int i = 0;
 
+   base = data->bank[i].base;
reg->wr_len_ctrl = readl_relaxed(base + REG_MMU_WR_LEN_CTRL);
reg->misc_ctrl = readl_relaxed(base + REG_MMU_MISC_CTRL);
reg->dcm_dis = readl_relaxed(base + REG_MMU_DCM_DIS);
reg->ctrl_reg = readl_relaxed(base + REG_MMU_CTRL_REG);
-   reg->int_control0 = readl_relaxed(base + REG_MMU_INT_CONTROL0);
-   reg->int_main_control = readl_relaxed(base + REG_MMU_INT_MAIN_CONTROL);
-   reg->ivrp_paddr = readl_relaxed(base + REG_MMU_IVRP_PADDR);
reg->vld_pa_rng = readl_relaxed(base + REG_MMU_VLD_PA_RNG);
+   do {
+   if (!data->plat_data->banks_enable[i])
+   continue;
+   base = data->bank[i].base;
+   reg->int_control[i] = readl_relaxed(base + 
REG_MMU_INT_CONTROL0);
+   reg->int_main_control[i] = readl_relaxed(base + 
REG_MMU_INT_MAIN_CONTROL);
+   reg->ivrp_paddr[i] = readl_relaxed(base + REG_MMU_IVRP_PADDR);
+   } while (++i < data->plat_data->banks_num);
clk_disable_unprepare(data->bclk);
return 0;
 }
@@ -1320,9 +1328,9 @@ static int __maybe_unused mtk_iommu_runtime_resume(struct 
device *dev)
 {
struct mtk_iommu_data *data = dev_get_drvdata(dev);
struct mtk_iommu_suspend_reg *reg = >reg;
-   struct mtk_iommu_domain *m4u_dom = data->bank[0].m4u_dom;
-   void __iomem *base = data->bank[0].base;
-   int ret;
+   struct mtk_iommu_domain *m4u_dom;
+   void __iomem *base;
+   int ret, i = 0;
 
ret = clk_prepare_enable(data->bclk);
if (ret) {
@@ -1334,18 +1342,26 @@ static int __maybe_unused 
mtk_iommu_runtime_resume(struct device *dev)
 * Uppon first resume, only enable the clk and return, since the values 
of the
 * registers are not yet set.
 */
-   if (!m4u_dom)
+   if (!reg->wr_len_ctrl)
return 0;
 
+   base = data->bank[i].base;
writel_relaxed(reg->wr_len_ctrl, base + REG_MMU_WR_LEN_CTRL);
writel_relaxed(reg->misc_ctrl, base + REG_MMU_MISC_CTRL);
writel_relaxed(reg->dcm_dis, base + REG_MMU_DCM_DIS);
writel_relaxed(reg->ctrl_reg, base + REG_MMU_CTRL_REG);
-   writel_relaxed(reg->int_control0, base + REG_MMU_INT_CONTROL0);
-   writel_relaxed(reg->int_main_control, base + REG_MMU_INT_MAIN_CONTROL);
-   writel_relaxed(reg->ivrp_paddr, base + REG_MMU_IVRP_PADDR);
writel_relaxed(reg->vld_pa_rng, base + REG_MMU_VLD_PA_RNG);
-   writel(m4u_dom->cfg.arm_v7s_cfg.ttbr & MMU_PT_ADDR_MASK, base + 
REG_MMU_PT_BASE_ADDR);
+   do {
+   m4u_dom = data->bank[i].m4u_dom;
+   if (!data->plat_data->banks_enable[i] || !m4u_dom)
+   continue;
+   base = data->bank[i].base;
+   writel_relaxed(reg->int_control[i], base + 
REG_MMU_INT_CONTROL0);
+   writel_relaxed(reg->int_main_control[i], base + 
REG_MMU_INT_MAIN_CONTROL);
+   writel_relaxed(reg->ivrp_paddr[i], base + REG_MMU_IVRP_PADDR);
+   writel(m4u_dom->cfg.arm_v7s_cfg.ttbr & MMU_PT_ADDR_MASK,
+  base + REG_MMU_PT_BASE_ADDR);
+   } while (++i < data->plat_data->banks_num);
 
/*
 * Users may allocate dma buffer before they call pm_runtime_get,
-- 
2.18.0

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


[PATCH v7 33/36] iommu/mediatek: Initialise/Remove for multi bank dev

2022-05-03 Thread Yong Wu via iommu
The registers for each bank of the IOMMU base are in order, delta is
0x1000. Initialise the base for each bank.

For all the previous SoC, we only have bank0. thus use "do {} while()"
to allow bank0 always go.

When removing the device, Not always all the banks are initialised, it
depend on if there is masters for that bank.

Signed-off-by: Yong Wu 
Reviewed-by: AngeloGioacchino Del Regno 

---
 drivers/iommu/mtk_iommu.c | 44 ++-
 1 file changed, 30 insertions(+), 14 deletions(-)

diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c
index 5f3e88c44514..400dea33aea1 100644
--- a/drivers/iommu/mtk_iommu.c
+++ b/drivers/iommu/mtk_iommu.c
@@ -113,6 +113,7 @@
 #define F_MMU_INT_ID_PORT_ID(a)(((a) >> 2) & 0x1f)
 
 #define MTK_PROTECT_PA_ALIGN   256
+#define MTK_IOMMU_BANK_SZ  0x1000
 
 #define PERICFG_IOMMU_10x714
 
@@ -1112,7 +1113,7 @@ static int mtk_iommu_probe(struct platform_device *pdev)
struct component_match  *match = NULL;
struct regmap   *infracfg;
void*protect;
-   int ret, banks_num;
+   int ret, banks_num, i = 0;
u32 val;
char*p;
struct mtk_iommu_bank_data *bank;
@@ -1153,27 +1154,36 @@ static int mtk_iommu_probe(struct platform_device *pdev)
data->enable_4GB = !!(val & F_DDR_4GB_SUPPORT_EN);
}
 
+   banks_num = data->plat_data->banks_num;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+   if (resource_size(res) < banks_num * MTK_IOMMU_BANK_SZ) {
+   dev_err(dev, "banknr %d. res %pR is not enough.\n", banks_num, 
res);
+   return -EINVAL;
+   }
base = devm_ioremap_resource(dev, res);
if (IS_ERR(base))
return PTR_ERR(base);
ioaddr = res->start;
 
-   banks_num = data->plat_data->banks_num;
data->bank = devm_kmalloc(dev, banks_num * sizeof(*data->bank), 
GFP_KERNEL);
if (!data->bank)
return -ENOMEM;
 
-   bank = >bank[0];
-   bank->id = 0;
-   bank->base = base;
-   bank->m4u_dom = NULL;
-   bank->irq = platform_get_irq(pdev, 0);
-   if (bank->irq < 0)
-   return bank->irq;
-   bank->parent_dev = dev;
-   bank->parent_data = data;
-   spin_lock_init(>tlb_lock);
+   do {
+   if (!data->plat_data->banks_enable[i])
+   continue;
+   bank = >bank[i];
+   bank->id = i;
+   bank->base = base + i * MTK_IOMMU_BANK_SZ;
+   bank->m4u_dom = NULL;
+
+   bank->irq = platform_get_irq(pdev, i);
+   if (bank->irq < 0)
+   return bank->irq;
+   bank->parent_dev = dev;
+   bank->parent_data = data;
+   spin_lock_init(>tlb_lock);
+   } while (++i < banks_num);
 
if (MTK_IOMMU_HAS_FLAG(data->plat_data, HAS_BCLK)) {
data->bclk = devm_clk_get(dev, "bclk");
@@ -1261,7 +1271,8 @@ static int mtk_iommu_probe(struct platform_device *pdev)
 static int mtk_iommu_remove(struct platform_device *pdev)
 {
struct mtk_iommu_data *data = platform_get_drvdata(pdev);
-   struct mtk_iommu_bank_data *bank = >bank[0];
+   struct mtk_iommu_bank_data *bank;
+   int i;
 
iommu_device_sysfs_remove(>iommu);
iommu_device_unregister(>iommu);
@@ -1278,7 +1289,12 @@ static int mtk_iommu_remove(struct platform_device *pdev)
 #endif
}
pm_runtime_disable(>dev);
-   devm_free_irq(>dev, bank->irq, bank);
+   for (i = 0; i < data->plat_data->banks_num; i++) {
+   bank = >bank[i];
+   if (!bank->m4u_dom)
+   continue;
+   devm_free_irq(>dev, bank->irq, bank);
+   }
return 0;
 }
 
-- 
2.18.0

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


[PATCH v7 32/36] iommu/mediatek: Get the proper bankid for multi banks

2022-05-03 Thread Yong Wu via iommu
We preassign some ports in a special bank via the new defined
banks_portmsk. Put it in the plat_data means it is not expected to be
adjusted dynamically.

If the iommu id in the iommu consumer's dtsi node is inside this
banks_portmsk, then we switch it to this special iommu bank, and
initialise the IOMMU bank HW.

Each bank has the independent pgtable(4GB iova range). Each bank
is a independent iommu domain/group. Currently we don't separate different
iova ranges inside a bank.

Signed-off-by: Yong Wu 
Reviewed-by: AngeloGioacchino Del Regno 

---
 drivers/iommu/mtk_iommu.c | 55 ++-
 1 file changed, 48 insertions(+), 7 deletions(-)

diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c
index 023bb7d3ffb2..5f3e88c44514 100644
--- a/drivers/iommu/mtk_iommu.c
+++ b/drivers/iommu/mtk_iommu.c
@@ -191,6 +191,7 @@ struct mtk_iommu_plat_data {
 
u8  banks_num;
boolbanks_enable[MTK_IOMMU_BANK_MAX];
+   unsigned intbanks_portmsk[MTK_IOMMU_BANK_MAX];
unsigned char   larbid_remap[MTK_LARB_COM_MAX][MTK_LARB_SUBCOM_MAX];
 };
 
@@ -467,6 +468,30 @@ static irqreturn_t mtk_iommu_isr(int irq, void *dev_id)
return IRQ_HANDLED;
 }
 
+static unsigned int mtk_iommu_get_bank_id(struct device *dev,
+ const struct mtk_iommu_plat_data 
*plat_data)
+{
+   struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
+   unsigned int i, portmsk = 0, bankid = 0;
+
+   if (plat_data->banks_num == 1)
+   return bankid;
+
+   for (i = 0; i < fwspec->num_ids; i++)
+   portmsk |= BIT(MTK_M4U_TO_PORT(fwspec->ids[i]));
+
+   for (i = 0; i < plat_data->banks_num && i < MTK_IOMMU_BANK_MAX; i++) {
+   if (!plat_data->banks_enable[i])
+   continue;
+
+   if (portmsk & plat_data->banks_portmsk[i]) {
+   bankid = i;
+   break;
+   }
+   }
+   return bankid; /* default is 0 */
+}
+
 static int mtk_iommu_get_iova_region_id(struct device *dev,
const struct mtk_iommu_plat_data 
*plat_data)
 {
@@ -619,13 +644,14 @@ static int mtk_iommu_attach_device(struct iommu_domain 
*domain,
struct list_head *hw_list = data->hw_list;
struct device *m4udev = data->dev;
struct mtk_iommu_bank_data *bank;
-   unsigned int bankid = 0;
+   unsigned int bankid;
int ret, region_id;
 
region_id = mtk_iommu_get_iova_region_id(dev, data->plat_data);
if (region_id < 0)
return region_id;
 
+   bankid = mtk_iommu_get_bank_id(dev, data->plat_data);
mutex_lock(>mutex);
if (!dom->bank) {
/* Data is in the frstdata in sharing pgtable case. */
@@ -797,27 +823,42 @@ static void mtk_iommu_release_device(struct device *dev)
iommu_fwspec_free(dev);
 }
 
+static int mtk_iommu_get_group_id(struct device *dev, const struct 
mtk_iommu_plat_data *plat_data)
+{
+   unsigned int bankid;
+
+   /*
+* If the bank function is enabled, each bank is a iommu group/domain.
+* Otherwise, each iova region is a iommu group/domain.
+*/
+   bankid = mtk_iommu_get_bank_id(dev, plat_data);
+   if (bankid)
+   return bankid;
+
+   return mtk_iommu_get_iova_region_id(dev, plat_data);
+}
+
 static struct iommu_group *mtk_iommu_device_group(struct device *dev)
 {
struct mtk_iommu_data *c_data = dev_iommu_priv_get(dev), *data;
struct list_head *hw_list = c_data->hw_list;
struct iommu_group *group;
-   int regionid;
+   int groupid;
 
data = mtk_iommu_get_frst_data(hw_list);
if (!data)
return ERR_PTR(-ENODEV);
 
-   regionid = mtk_iommu_get_iova_region_id(dev, data->plat_data);
-   if (regionid < 0)
-   return ERR_PTR(regionid);
+   groupid = mtk_iommu_get_group_id(dev, data->plat_data);
+   if (groupid < 0)
+   return ERR_PTR(groupid);
 
mutex_lock(>mutex);
-   group = data->m4u_group[regionid];
+   group = data->m4u_group[groupid];
if (!group) {
group = iommu_group_alloc();
if (!IS_ERR(group))
-   data->m4u_group[regionid] = group;
+   data->m4u_group[groupid] = group;
} else {
iommu_group_ref_get(group);
}
-- 
2.18.0

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


[PATCH v7 31/36] iommu/mediatek: Change the domid to iova_region_id

2022-05-03 Thread Yong Wu via iommu
Prepare for adding bankid, also no functional change.

In the previous SoC, each a iova_region is a domain; In the multi-banks
case, each a bank is a domain, then the original function name
"mtk_iommu_get_domain_id" is not proper. Use "iova_region_id" instead of
"domain_id".

Signed-off-by: Yong Wu 
Reviewed-by: AngeloGioacchino Del Regno 

---
 drivers/iommu/mtk_iommu.c | 46 +++
 1 file changed, 23 insertions(+), 23 deletions(-)

diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c
index 5f298cf6aac3..023bb7d3ffb2 100644
--- a/drivers/iommu/mtk_iommu.c
+++ b/drivers/iommu/mtk_iommu.c
@@ -467,8 +467,8 @@ static irqreturn_t mtk_iommu_isr(int irq, void *dev_id)
return IRQ_HANDLED;
 }
 
-static int mtk_iommu_get_domain_id(struct device *dev,
-  const struct mtk_iommu_plat_data *plat_data)
+static int mtk_iommu_get_iova_region_id(struct device *dev,
+   const struct mtk_iommu_plat_data 
*plat_data)
 {
const struct mtk_iommu_iova_region *rgn = plat_data->iova_region;
const struct bus_dma_region *dma_rgn = dev->dma_range_map;
@@ -498,7 +498,7 @@ static int mtk_iommu_get_domain_id(struct device *dev,
 }
 
 static int mtk_iommu_config(struct mtk_iommu_data *data, struct device *dev,
-   bool enable, unsigned int domid)
+   bool enable, unsigned int regionid)
 {
struct mtk_smi_larb_iommu*larb_mmu;
unsigned int larbid, portid;
@@ -514,12 +514,12 @@ static int mtk_iommu_config(struct mtk_iommu_data *data, 
struct device *dev,
if (MTK_IOMMU_IS_TYPE(data->plat_data, MTK_IOMMU_TYPE_MM)) {
larb_mmu = >larb_imu[larbid];
 
-   region = data->plat_data->iova_region + domid;
+   region = data->plat_data->iova_region + regionid;
larb_mmu->bank[portid] = 
upper_32_bits(region->iova_base);
 
-   dev_dbg(dev, "%s iommu for larb(%s) port %d dom %d bank 
%d.\n",
+   dev_dbg(dev, "%s iommu for larb(%s) port %d region %d 
rgn-bank %d.\n",
enable ? "enable" : "disable", 
dev_name(larb_mmu->dev),
-   portid, domid, larb_mmu->bank[portid]);
+   portid, regionid, larb_mmu->bank[portid]);
 
if (enable)
larb_mmu->mmu |= MTK_SMI_MMU_EN(portid);
@@ -545,7 +545,7 @@ static int mtk_iommu_config(struct mtk_iommu_data *data, 
struct device *dev,
 
 static int mtk_iommu_domain_finalise(struct mtk_iommu_domain *dom,
 struct mtk_iommu_data *data,
-unsigned int domid)
+unsigned int region_id)
 {
const struct mtk_iommu_iova_region *region;
struct mtk_iommu_domain *m4u_dom;
@@ -584,7 +584,7 @@ static int mtk_iommu_domain_finalise(struct 
mtk_iommu_domain *dom,
 
 update_iova_region:
/* Update the iova region for this domain */
-   region = data->plat_data->iova_region + domid;
+   region = data->plat_data->iova_region + region_id;
dom->domain.geometry.aperture_start = region->iova_base;
dom->domain.geometry.aperture_end = region->iova_base + region->size - 
1;
dom->domain.geometry.force_aperture = true;
@@ -620,18 +620,18 @@ static int mtk_iommu_attach_device(struct iommu_domain 
*domain,
struct device *m4udev = data->dev;
struct mtk_iommu_bank_data *bank;
unsigned int bankid = 0;
-   int ret, domid;
+   int ret, region_id;
 
-   domid = mtk_iommu_get_domain_id(dev, data->plat_data);
-   if (domid < 0)
-   return domid;
+   region_id = mtk_iommu_get_iova_region_id(dev, data->plat_data);
+   if (region_id < 0)
+   return region_id;
 
mutex_lock(>mutex);
if (!dom->bank) {
/* Data is in the frstdata in sharing pgtable case. */
frstdata = mtk_iommu_get_frst_data(hw_list);
 
-   ret = mtk_iommu_domain_finalise(dom, frstdata, domid);
+   ret = mtk_iommu_domain_finalise(dom, frstdata, region_id);
if (ret) {
mutex_unlock(>mutex);
return -ENODEV;
@@ -662,7 +662,7 @@ static int mtk_iommu_attach_device(struct iommu_domain 
*domain,
}
mutex_unlock(>mutex);
 
-   return mtk_iommu_config(data, dev, true, domid);
+   return mtk_iommu_config(data, dev, true, region_id);
 
 err_unlock:
mutex_unlock(>mutex);
@@ -802,22 +802,22 @@ static struct iommu_group *mtk_iommu_device_group(struct 
device *dev)
struct mtk_iommu_data *c_data = dev_iommu_priv_get(dev), *data;
struct list_head *hw_list = c_data->hw_list;
struct iommu_group *group;
-   

[PATCH v7 30/36] iommu/mediatek: Initialise bank HW for each a bank

2022-05-03 Thread Yong Wu via iommu
The mt8195 IOMMU HW max support 5 banks, and regarding the banks'
registers, it looks like:

 
 |bank0  | bank1 | bank2 | bank3 | bank4|
 
 |global |
 |control| null
 |regs   |
 -
 |bank   |bank   |bank   |bank   |bank   |
 |regs   |regs   |regs   |regs   |regs   |
 |   |   |   |   |   |
 -

Each bank has some special bank registers and it share bank0's global
control registers. this patch initialise the bank hw with the bankid.

In the hw_init, we always initialise bank0's control register since
we don't know if the bank0 is initialised.

Additionally, About each bank's register base, always delta 0x1000.
like bank[x + 1] = bank[x] + 0x1000.

Signed-off-by: Yong Wu 
Reviewed-by: AngeloGioacchino Del Regno 

---
 drivers/iommu/mtk_iommu.c | 32 
 1 file changed, 20 insertions(+), 12 deletions(-)

diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c
index 968e1486e6fd..5f298cf6aac3 100644
--- a/drivers/iommu/mtk_iommu.c
+++ b/drivers/iommu/mtk_iommu.c
@@ -259,7 +259,7 @@ static void mtk_iommu_unbind(struct device *dev)
 
 static const struct iommu_ops mtk_iommu_ops;
 
-static int mtk_iommu_hw_init(const struct mtk_iommu_data *data);
+static int mtk_iommu_hw_init(const struct mtk_iommu_data *data, unsigned int 
bankid);
 
 #define MTK_IOMMU_TLB_ADDR(iova) ({\
dma_addr_t _addr = iova;\
@@ -642,12 +642,14 @@ static int mtk_iommu_attach_device(struct iommu_domain 
*domain,
 
mutex_lock(>mutex);
bank = >bank[bankid];
-   if (!bank->m4u_dom) { /* Initialize the M4U HW */
+   if (!bank->m4u_dom) { /* Initialize the M4U HW for each a BANK */
ret = pm_runtime_resume_and_get(m4udev);
-   if (ret < 0)
+   if (ret < 0) {
+   dev_err(m4udev, "pm get fail(%d) in attach.\n", ret);
goto err_unlock;
+   }
 
-   ret = mtk_iommu_hw_init(data);
+   ret = mtk_iommu_hw_init(data, bankid);
if (ret) {
pm_runtime_put(m4udev);
goto err_unlock;
@@ -897,11 +899,16 @@ static const struct iommu_ops mtk_iommu_ops = {
}
 };
 
-static int mtk_iommu_hw_init(const struct mtk_iommu_data *data)
+static int mtk_iommu_hw_init(const struct mtk_iommu_data *data, unsigned int 
bankid)
 {
+   const struct mtk_iommu_bank_data *bankx = >bank[bankid];
const struct mtk_iommu_bank_data *bank0 = >bank[0];
u32 regval;
 
+   /*
+* Global control settings are in bank0. May re-init these global 
registers
+* since no sure if there is bank0 consumers.
+*/
if (data->plat_data->m4u_plat == M4U_MT8173) {
regval = F_MMU_PREFETCH_RT_REPLACE_MOD |
 F_MMU_TF_PROT_TO_PROGRAM_ADDR_MT8173;
@@ -944,13 +951,14 @@ static int mtk_iommu_hw_init(const struct mtk_iommu_data 
*data)
}
writel_relaxed(regval, bank0->base + REG_MMU_MISC_CTRL);
 
+   /* Independent settings for each bank */
regval = F_L2_MULIT_HIT_EN |
F_TABLE_WALK_FAULT_INT_EN |
F_PREETCH_FIFO_OVERFLOW_INT_EN |
F_MISS_FIFO_OVERFLOW_INT_EN |
F_PREFETCH_FIFO_ERR_INT_EN |
F_MISS_FIFO_ERR_INT_EN;
-   writel_relaxed(regval, bank0->base + REG_MMU_INT_CONTROL0);
+   writel_relaxed(regval, bankx->base + REG_MMU_INT_CONTROL0);
 
regval = F_INT_TRANSLATION_FAULT |
F_INT_MAIN_MULTI_HIT_FAULT |
@@ -959,19 +967,19 @@ static int mtk_iommu_hw_init(const struct mtk_iommu_data 
*data)
F_INT_TLB_MISS_FAULT |
F_INT_MISS_TRANSACTION_FIFO_FAULT |
F_INT_PRETETCH_TRANSATION_FIFO_FAULT;
-   writel_relaxed(regval, bank0->base + REG_MMU_INT_MAIN_CONTROL);
+   writel_relaxed(regval, bankx->base + REG_MMU_INT_MAIN_CONTROL);
 
if (MTK_IOMMU_HAS_FLAG(data->plat_data, HAS_LEGACY_IVRP_PADDR))
regval = (data->protect_base >> 1) | (data->enable_4GB << 31);
else
regval = lower_32_bits(data->protect_base) |
 upper_32_bits(data->protect_base);
-   writel_relaxed(regval, bank0->base + REG_MMU_IVRP_PADDR);
+   writel_relaxed(regval, bankx->base + REG_MMU_IVRP_PADDR);
 
-   if (devm_request_irq(bank0->parent_dev, bank0->irq, mtk_iommu_isr, 0,
-dev_name(bank0->parent_dev), (void *)bank0)) {
-   writel_relaxed(0, bank0->base + REG_MMU_PT_BASE_ADDR);
-   dev_err(bank0->parent_dev, "Failed @ IRQ-%d Request\n", 
bank0->irq);
+   if (devm_request_irq(bankx->parent_dev, bankx->irq, mtk_iommu_isr, 0,
+ 

[PATCH v7 29/36] iommu/mediatek: Add mtk_iommu_bank_data structure

2022-05-03 Thread Yong Wu via iommu
Prepare for supporting multi-banks for the IOMMU HW, No functional change.

Add a new structure(mtk_iommu_bank_data) for each a bank. Each a bank have
the independent HW base/IRQ/tlb-range ops, and each a bank has its special
iommu-domain(independent pgtable), thus, also move the domain information
into it.

In previous SoC, we have only one bank which could be treated as bank0(
bankid always is 0 for the previous SoC).

After adding this structure, the tlb operations and irq could use
bank_data as parameter.

Signed-off-by: Yong Wu 
Reviewed-by: AngeloGioacchino Del Regno 

---
 drivers/iommu/mtk_iommu.c | 179 +-
 1 file changed, 117 insertions(+), 62 deletions(-)

diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c
index 349640bcbd01..968e1486e6fd 100644
--- a/drivers/iommu/mtk_iommu.c
+++ b/drivers/iommu/mtk_iommu.c
@@ -151,6 +151,7 @@
 #define MTK_LARB_SUBCOM_MAX8
 
 #define MTK_IOMMU_GROUP_MAX8
+#define MTK_IOMMU_BANK_MAX 5
 
 enum mtk_iommu_plat {
M4U_MT2712,
@@ -187,25 +188,36 @@ struct mtk_iommu_plat_data {
struct list_head*hw_list;
unsigned intiova_region_nr;
const struct mtk_iommu_iova_region  *iova_region;
+
+   u8  banks_num;
+   boolbanks_enable[MTK_IOMMU_BANK_MAX];
unsigned char   larbid_remap[MTK_LARB_COM_MAX][MTK_LARB_SUBCOM_MAX];
 };
 
-struct mtk_iommu_data {
+struct mtk_iommu_bank_data {
void __iomem*base;
int irq;
+   u8  id;
+   struct device   *parent_dev;
+   struct mtk_iommu_data   *parent_data;
+   spinlock_t  tlb_lock; /* lock for tlb range flush */
+   struct mtk_iommu_domain *m4u_dom; /* Each bank has a domain */
+};
+
+struct mtk_iommu_data {
struct device   *dev;
struct clk  *bclk;
phys_addr_t protect_base; /* protect memory base */
struct mtk_iommu_suspend_regreg;
-   struct mtk_iommu_domain *m4u_dom;
struct iommu_group  *m4u_group[MTK_IOMMU_GROUP_MAX];
boolenable_4GB;
-   spinlock_t  tlb_lock; /* lock for tlb range flush */
 
struct iommu_device iommu;
const struct mtk_iommu_plat_data *plat_data;
struct device   *smicomm_dev;
 
+   struct mtk_iommu_bank_data  *bank;
+
struct dma_iommu_mapping*mapping; /* For mtk_iommu_v1.c */
struct regmap   *pericfg;
 
@@ -225,7 +237,7 @@ struct mtk_iommu_domain {
struct io_pgtable_cfg   cfg;
struct io_pgtable_ops   *iop;
 
-   struct mtk_iommu_data   *data;
+   struct mtk_iommu_bank_data  *bank;
struct iommu_domain domain;
 
struct mutexmutex; /* Protect "data" in this 
structure */
@@ -311,20 +323,24 @@ static struct mtk_iommu_domain *to_mtk_domain(struct 
iommu_domain *dom)
 
 static void mtk_iommu_tlb_flush_all(struct mtk_iommu_data *data)
 {
-   void __iomem *base = data->base;
+   /* Tlb flush all always is in bank0. */
+   struct mtk_iommu_bank_data *bank = >bank[0];
+   void __iomem *base = bank->base;
unsigned long flags;
 
-   spin_lock_irqsave(>tlb_lock, flags);
+   spin_lock_irqsave(>tlb_lock, flags);
writel_relaxed(F_INVLD_EN1 | F_INVLD_EN0, base + 
data->plat_data->inv_sel_reg);
writel_relaxed(F_ALL_INVLD, base + REG_MMU_INVALIDATE);
wmb(); /* Make sure the tlb flush all done */
-   spin_unlock_irqrestore(>tlb_lock, flags);
+   spin_unlock_irqrestore(>tlb_lock, flags);
 }
 
 static void mtk_iommu_tlb_flush_range_sync(unsigned long iova, size_t size,
-  struct mtk_iommu_data *data)
+  struct mtk_iommu_bank_data *bank)
 {
-   struct list_head *head = data->hw_list;
+   struct list_head *head = bank->parent_data->hw_list;
+   struct mtk_iommu_bank_data *curbank;
+   struct mtk_iommu_data *data;
bool check_pm_status;
unsigned long flags;
void __iomem *base;
@@ -354,9 +370,10 @@ static void mtk_iommu_tlb_flush_range_sync(unsigned long 
iova, size_t size,
continue;
}
 
-   base = data->base;
+   curbank = >bank[bank->id];
+   base = curbank->base;
 
-   spin_lock_irqsave(>tlb_lock, flags);
+   spin_lock_irqsave(>tlb_lock, flags);
writel_relaxed(F_INVLD_EN1 | F_INVLD_EN0,
   base + data->plat_data->inv_sel_reg);
 
@@ -371,7 +388,7 @@ static void mtk_iommu_tlb_flush_range_sync(unsigned long 
iova, 

[PATCH v7 28/36] iommu/mediatek-v1: Just rename mtk_iommu to mtk_iommu_v1

2022-05-03 Thread Yong Wu via iommu
No functional change. Just rename this for readable. Differentiate this
from mtk_iommu.c

Signed-off-by: Yong Wu 
Reviewed-by: AngeloGioacchino Del Regno 

---
 drivers/iommu/mtk_iommu_v1.c | 211 +--
 1 file changed, 103 insertions(+), 108 deletions(-)

diff --git a/drivers/iommu/mtk_iommu_v1.c b/drivers/iommu/mtk_iommu_v1.c
index 3d1f0897d1cc..62669e60991f 100644
--- a/drivers/iommu/mtk_iommu_v1.c
+++ b/drivers/iommu/mtk_iommu_v1.c
@@ -85,53 +85,53 @@
  */
 #define M2701_IOMMU_PGT_SIZE   SZ_4M
 
-struct mtk_iommu_suspend_reg {
+struct mtk_iommu_v1_suspend_reg {
u32 standard_axi_mode;
u32 dcm_dis;
u32 ctrl_reg;
u32 int_control0;
 };
 
-struct mtk_iommu_data {
+struct mtk_iommu_v1_data {
void __iomem*base;
int irq;
struct device   *dev;
struct clk  *bclk;
phys_addr_t protect_base; /* protect memory base */
-   struct mtk_iommu_domain *m4u_dom;
+   struct mtk_iommu_v1_domain  *m4u_dom;
 
struct iommu_device iommu;
struct dma_iommu_mapping*mapping;
struct mtk_smi_larb_iommu   larb_imu[MTK_LARB_NR_MAX];
 
-   struct mtk_iommu_suspend_regreg;
+   struct mtk_iommu_v1_suspend_reg reg;
 };
 
-struct mtk_iommu_domain {
+struct mtk_iommu_v1_domain {
spinlock_t  pgtlock; /* lock for page table */
struct iommu_domain domain;
u32 *pgt_va;
dma_addr_t  pgt_pa;
-   struct mtk_iommu_data   *data;
+   struct mtk_iommu_v1_data*data;
 };
 
-static int mtk_iommu_bind(struct device *dev)
+static int mtk_iommu_v1_bind(struct device *dev)
 {
-   struct mtk_iommu_data *data = dev_get_drvdata(dev);
+   struct mtk_iommu_v1_data *data = dev_get_drvdata(dev);
 
return component_bind_all(dev, >larb_imu);
 }
 
-static void mtk_iommu_unbind(struct device *dev)
+static void mtk_iommu_v1_unbind(struct device *dev)
 {
-   struct mtk_iommu_data *data = dev_get_drvdata(dev);
+   struct mtk_iommu_v1_data *data = dev_get_drvdata(dev);
 
component_unbind_all(dev, >larb_imu);
 }
 
-static struct mtk_iommu_domain *to_mtk_domain(struct iommu_domain *dom)
+static struct mtk_iommu_v1_domain *to_mtk_domain(struct iommu_domain *dom)
 {
-   return container_of(dom, struct mtk_iommu_domain, domain);
+   return container_of(dom, struct mtk_iommu_v1_domain, domain);
 }
 
 static const int mt2701_m4u_in_larb[] = {
@@ -157,7 +157,7 @@ static inline int mt2701_m4u_to_port(int id)
return id - mt2701_m4u_in_larb[larb];
 }
 
-static void mtk_iommu_tlb_flush_all(struct mtk_iommu_data *data)
+static void mtk_iommu_v1_tlb_flush_all(struct mtk_iommu_v1_data *data)
 {
writel_relaxed(F_INVLD_EN1 | F_INVLD_EN0,
data->base + REG_MMU_INV_SEL);
@@ -165,8 +165,8 @@ static void mtk_iommu_tlb_flush_all(struct mtk_iommu_data 
*data)
wmb(); /* Make sure the tlb flush all done */
 }
 
-static void mtk_iommu_tlb_flush_range(struct mtk_iommu_data *data,
-   unsigned long iova, size_t size)
+static void mtk_iommu_v1_tlb_flush_range(struct mtk_iommu_v1_data *data,
+unsigned long iova, size_t size)
 {
int ret;
u32 tmp;
@@ -184,16 +184,16 @@ static void mtk_iommu_tlb_flush_range(struct 
mtk_iommu_data *data,
if (ret) {
dev_warn(data->dev,
 "Partial TLB flush timed out, falling back to full 
flush\n");
-   mtk_iommu_tlb_flush_all(data);
+   mtk_iommu_v1_tlb_flush_all(data);
}
/* Clear the CPE status */
writel_relaxed(0, data->base + REG_MMU_CPE_DONE);
 }
 
-static irqreturn_t mtk_iommu_isr(int irq, void *dev_id)
+static irqreturn_t mtk_iommu_v1_isr(int irq, void *dev_id)
 {
-   struct mtk_iommu_data *data = dev_id;
-   struct mtk_iommu_domain *dom = data->m4u_dom;
+   struct mtk_iommu_v1_data *data = dev_id;
+   struct mtk_iommu_v1_domain *dom = data->m4u_dom;
u32 int_state, regval, fault_iova, fault_pa;
unsigned int fault_larb, fault_port;
 
@@ -223,13 +223,13 @@ static irqreturn_t mtk_iommu_isr(int irq, void *dev_id)
regval |= F_INT_CLR_BIT;
writel_relaxed(regval, data->base + REG_MMU_INT_CONTROL);
 
-   mtk_iommu_tlb_flush_all(data);
+   mtk_iommu_v1_tlb_flush_all(data);
 
return IRQ_HANDLED;
 }
 
-static void mtk_iommu_config(struct mtk_iommu_data *data,
-struct device *dev, bool enable)
+static void mtk_iommu_v1_config(struct mtk_iommu_v1_data *data,
+   struct device *dev, bool enable)
 

[PATCH v7 27/36] iommu/mediatek: Remove mtk_iommu.h

2022-05-03 Thread Yong Wu via iommu
Currently there is a suspend structure in the header file. It's no need
to keep a header file only for this. Move these into the c file and rm
this header file.

Signed-off-by: Yong Wu 
Reviewed-by: AngeloGioacchino Del Regno 

---
 drivers/iommu/mtk_iommu.c| 14 +-
 drivers/iommu/mtk_iommu.h| 32 
 drivers/iommu/mtk_iommu_v1.c | 11 ---
 3 files changed, 21 insertions(+), 36 deletions(-)
 delete mode 100644 drivers/iommu/mtk_iommu.h

diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c
index 7383a5df6021..349640bcbd01 100644
--- a/drivers/iommu/mtk_iommu.c
+++ b/drivers/iommu/mtk_iommu.c
@@ -14,6 +14,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -30,7 +31,7 @@
 #include 
 #include 
 
-#include "mtk_iommu.h"
+#include 
 
 #define REG_MMU_PT_BASE_ADDR   0x000
 #define MMU_PT_ADDR_MASK   GENMASK(31, 7)
@@ -166,6 +167,17 @@ struct mtk_iommu_iova_region {
unsigned long long  size;
 };
 
+struct mtk_iommu_suspend_reg {
+   u32 misc_ctrl;
+   u32 dcm_dis;
+   u32 ctrl_reg;
+   u32 int_control0;
+   u32 int_main_control;
+   u32 ivrp_paddr;
+   u32 vld_pa_rng;
+   u32 wr_len_ctrl;
+};
+
 struct mtk_iommu_plat_data {
enum mtk_iommu_plat m4u_plat;
u32 flags;
diff --git a/drivers/iommu/mtk_iommu.h b/drivers/iommu/mtk_iommu.h
deleted file mode 100644
index 305243e18aa9..
--- a/drivers/iommu/mtk_iommu.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Copyright (c) 2015-2016 MediaTek Inc.
- * Author: Honghui Zhang 
- */
-
-#ifndef _MTK_IOMMU_H_
-#define _MTK_IOMMU_H_
-
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-
-struct mtk_iommu_suspend_reg {
-   union {
-   u32 standard_axi_mode;/* v1 */
-   u32 misc_ctrl;/* v2 */
-   };
-   u32 dcm_dis;
-   u32 ctrl_reg;
-   u32 int_control0;
-   u32 int_main_control;
-   u32 ivrp_paddr;
-   u32 vld_pa_rng;
-   u32 wr_len_ctrl;
-};
-
-#endif
diff --git a/drivers/iommu/mtk_iommu_v1.c b/drivers/iommu/mtk_iommu_v1.c
index 6d1c09c91e1f..3d1f0897d1cc 100644
--- a/drivers/iommu/mtk_iommu_v1.c
+++ b/drivers/iommu/mtk_iommu_v1.c
@@ -7,7 +7,6 @@
  *
  * Based on driver/iommu/mtk_iommu.c
  */
-#include 
 #include 
 #include 
 #include 
@@ -28,10 +27,9 @@
 #include 
 #include 
 #include 
-#include 
+#include 
 #include 
 #include 
-#include "mtk_iommu.h"
 
 #define REG_MMU_PT_BASE_ADDR   0x000
 
@@ -87,6 +85,13 @@
  */
 #define M2701_IOMMU_PGT_SIZE   SZ_4M
 
+struct mtk_iommu_suspend_reg {
+   u32 standard_axi_mode;
+   u32 dcm_dis;
+   u32 ctrl_reg;
+   u32 int_control0;
+};
+
 struct mtk_iommu_data {
void __iomem*base;
int irq;
-- 
2.18.0

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


[PATCH v7 26/36] iommu/mediatek: Separate mtk_iommu_data for v1 and v2

2022-05-03 Thread Yong Wu via iommu
Prepare for adding the structure "mtk_iommu_bank_data". No functional
change. The mtk_iommu_domain in v1 and v2 are different, we could not add
current data as bank[0] in v1 simplistically.

Currently we have no plan to add new SoC for v1, in order to avoid affect
v1 when we add many new features for v2, I totally separate v1 and v2 in
this patch, there are many structures only for v2.

Signed-off-by: Yong Wu 
Reviewed-by: AngeloGioacchino Del Regno 

---
 drivers/iommu/mtk_iommu.c| 82 +---
 drivers/iommu/mtk_iommu.h| 81 ---
 drivers/iommu/mtk_iommu_v1.c | 29 +
 3 files changed, 106 insertions(+), 86 deletions(-)

diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c
index ac1681858af8..7383a5df6021 100644
--- a/drivers/iommu/mtk_iommu.c
+++ b/drivers/iommu/mtk_iommu.c
@@ -146,6 +146,69 @@
 
 #define MTK_INVALID_LARBID MTK_LARB_NR_MAX
 
+#define MTK_LARB_COM_MAX   8
+#define MTK_LARB_SUBCOM_MAX8
+
+#define MTK_IOMMU_GROUP_MAX8
+
+enum mtk_iommu_plat {
+   M4U_MT2712,
+   M4U_MT6779,
+   M4U_MT8167,
+   M4U_MT8173,
+   M4U_MT8183,
+   M4U_MT8192,
+   M4U_MT8195,
+};
+
+struct mtk_iommu_iova_region {
+   dma_addr_t  iova_base;
+   unsigned long long  size;
+};
+
+struct mtk_iommu_plat_data {
+   enum mtk_iommu_plat m4u_plat;
+   u32 flags;
+   u32 inv_sel_reg;
+
+   char*pericfg_comp_str;
+   struct list_head*hw_list;
+   unsigned intiova_region_nr;
+   const struct mtk_iommu_iova_region  *iova_region;
+   unsigned char   larbid_remap[MTK_LARB_COM_MAX][MTK_LARB_SUBCOM_MAX];
+};
+
+struct mtk_iommu_data {
+   void __iomem*base;
+   int irq;
+   struct device   *dev;
+   struct clk  *bclk;
+   phys_addr_t protect_base; /* protect memory base */
+   struct mtk_iommu_suspend_regreg;
+   struct mtk_iommu_domain *m4u_dom;
+   struct iommu_group  *m4u_group[MTK_IOMMU_GROUP_MAX];
+   boolenable_4GB;
+   spinlock_t  tlb_lock; /* lock for tlb range flush */
+
+   struct iommu_device iommu;
+   const struct mtk_iommu_plat_data *plat_data;
+   struct device   *smicomm_dev;
+
+   struct dma_iommu_mapping*mapping; /* For mtk_iommu_v1.c */
+   struct regmap   *pericfg;
+
+   struct mutexmutex; /* Protect m4u_group/m4u_dom 
above */
+
+   /*
+* In the sharing pgtable case, list data->list to the global list like 
m4ulist.
+* In the non-sharing pgtable case, list data->list to the itself 
hw_list_head.
+*/
+   struct list_head*hw_list;
+   struct list_headhw_list_head;
+   struct list_headlist;
+   struct mtk_smi_larb_iommu   larb_imu[MTK_LARB_NR_MAX];
+};
+
 struct mtk_iommu_domain {
struct io_pgtable_cfg   cfg;
struct io_pgtable_ops   *iop;
@@ -156,6 +219,20 @@ struct mtk_iommu_domain {
struct mutexmutex; /* Protect "data" in this 
structure */
 };
 
+static int mtk_iommu_bind(struct device *dev)
+{
+   struct mtk_iommu_data *data = dev_get_drvdata(dev);
+
+   return component_bind_all(dev, >larb_imu);
+}
+
+static void mtk_iommu_unbind(struct device *dev)
+{
+   struct mtk_iommu_data *data = dev_get_drvdata(dev);
+
+   component_unbind_all(dev, >larb_imu);
+}
+
 static const struct iommu_ops mtk_iommu_ops;
 
 static int mtk_iommu_hw_init(const struct mtk_iommu_data *data);
@@ -193,11 +270,6 @@ static LIST_HEAD(m4ulist); /* List all the M4U HWs */
 
 #define for_each_m4u(data, head)  list_for_each_entry(data, head, list)
 
-struct mtk_iommu_iova_region {
-   dma_addr_t  iova_base;
-   unsigned long long  size;
-};
-
 static const struct mtk_iommu_iova_region single_domain[] = {
{.iova_base = 0,.size = SZ_4G},
 };
diff --git a/drivers/iommu/mtk_iommu.h b/drivers/iommu/mtk_iommu.h
index f2ee11cd254a..305243e18aa9 100644
--- a/drivers/iommu/mtk_iommu.h
+++ b/drivers/iommu/mtk_iommu.h
@@ -7,23 +7,14 @@
 #ifndef _MTK_IOMMU_H_
 #define _MTK_IOMMU_H_
 
-#include 
-#include 
 #include 
 #include 
 #include 
 #include 
-#include 
 #include 
-#include 
 #include 
 #include 
 
-#define MTK_LARB_COM_MAX   8
-#define MTK_LARB_SUBCOM_MAX8
-
-#define MTK_IOMMU_GROUP_MAX8
-
 struct mtk_iommu_suspend_reg {
union {
u32 standard_axi_mode;/* v1 */
@@ -38,76 +29,4 @@ struct mtk_iommu_suspend_reg {
u32 wr_len_ctrl;
 };
 
-enum 

[PATCH v7 25/36] iommu/mediatek: Just move code position in hw_init

2022-05-03 Thread Yong Wu via iommu
No functional change too, prepare for mt8195 IOMMU support bank functions.
Some global control settings are in bank0 while the other banks have
their bank independent setting. Here only move the global control
settings and the independent registers together.

Signed-off-by: Yong Wu 
Reviewed-by: AngeloGioacchino Del Regno 

---
 drivers/iommu/mtk_iommu.c | 48 +++
 1 file changed, 24 insertions(+), 24 deletions(-)

diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c
index de448d056135..ac1681858af8 100644
--- a/drivers/iommu/mtk_iommu.c
+++ b/drivers/iommu/mtk_iommu.c
@@ -803,30 +803,6 @@ static int mtk_iommu_hw_init(const struct mtk_iommu_data 
*data)
}
writel_relaxed(regval, data->base + REG_MMU_CTRL_REG);
 
-   regval = F_L2_MULIT_HIT_EN |
-   F_TABLE_WALK_FAULT_INT_EN |
-   F_PREETCH_FIFO_OVERFLOW_INT_EN |
-   F_MISS_FIFO_OVERFLOW_INT_EN |
-   F_PREFETCH_FIFO_ERR_INT_EN |
-   F_MISS_FIFO_ERR_INT_EN;
-   writel_relaxed(regval, data->base + REG_MMU_INT_CONTROL0);
-
-   regval = F_INT_TRANSLATION_FAULT |
-   F_INT_MAIN_MULTI_HIT_FAULT |
-   F_INT_INVALID_PA_FAULT |
-   F_INT_ENTRY_REPLACEMENT_FAULT |
-   F_INT_TLB_MISS_FAULT |
-   F_INT_MISS_TRANSACTION_FIFO_FAULT |
-   F_INT_PRETETCH_TRANSATION_FIFO_FAULT;
-   writel_relaxed(regval, data->base + REG_MMU_INT_MAIN_CONTROL);
-
-   if (MTK_IOMMU_HAS_FLAG(data->plat_data, HAS_LEGACY_IVRP_PADDR))
-   regval = (data->protect_base >> 1) | (data->enable_4GB << 31);
-   else
-   regval = lower_32_bits(data->protect_base) |
-upper_32_bits(data->protect_base);
-   writel_relaxed(regval, data->base + REG_MMU_IVRP_PADDR);
-
if (data->enable_4GB &&
MTK_IOMMU_HAS_FLAG(data->plat_data, HAS_VLD_PA_RNG)) {
/*
@@ -860,6 +836,30 @@ static int mtk_iommu_hw_init(const struct mtk_iommu_data 
*data)
}
writel_relaxed(regval, data->base + REG_MMU_MISC_CTRL);
 
+   regval = F_L2_MULIT_HIT_EN |
+   F_TABLE_WALK_FAULT_INT_EN |
+   F_PREETCH_FIFO_OVERFLOW_INT_EN |
+   F_MISS_FIFO_OVERFLOW_INT_EN |
+   F_PREFETCH_FIFO_ERR_INT_EN |
+   F_MISS_FIFO_ERR_INT_EN;
+   writel_relaxed(regval, data->base + REG_MMU_INT_CONTROL0);
+
+   regval = F_INT_TRANSLATION_FAULT |
+   F_INT_MAIN_MULTI_HIT_FAULT |
+   F_INT_INVALID_PA_FAULT |
+   F_INT_ENTRY_REPLACEMENT_FAULT |
+   F_INT_TLB_MISS_FAULT |
+   F_INT_MISS_TRANSACTION_FIFO_FAULT |
+   F_INT_PRETETCH_TRANSATION_FIFO_FAULT;
+   writel_relaxed(regval, data->base + REG_MMU_INT_MAIN_CONTROL);
+
+   if (MTK_IOMMU_HAS_FLAG(data->plat_data, HAS_LEGACY_IVRP_PADDR))
+   regval = (data->protect_base >> 1) | (data->enable_4GB << 31);
+   else
+   regval = lower_32_bits(data->protect_base) |
+upper_32_bits(data->protect_base);
+   writel_relaxed(regval, data->base + REG_MMU_IVRP_PADDR);
+
if (devm_request_irq(data->dev, data->irq, mtk_iommu_isr, 0,
 dev_name(data->dev), (void *)data)) {
writel_relaxed(0, data->base + REG_MMU_PT_BASE_ADDR);
-- 
2.18.0

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


[PATCH v7 24/36] iommu/mediatek: Only adjust code about register base

2022-05-03 Thread Yong Wu via iommu
No functional change. Use "base" instead of the data->base. This is
avoid to touch too many lines in the next patches.

Signed-off-by: Yong Wu 
Reviewed-by: AngeloGioacchino Del Regno 

---
 drivers/iommu/mtk_iommu.c | 51 +--
 1 file changed, 27 insertions(+), 24 deletions(-)

diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c
index 47355010502e..de448d056135 100644
--- a/drivers/iommu/mtk_iommu.c
+++ b/drivers/iommu/mtk_iommu.c
@@ -227,12 +227,12 @@ static struct mtk_iommu_domain *to_mtk_domain(struct 
iommu_domain *dom)
 
 static void mtk_iommu_tlb_flush_all(struct mtk_iommu_data *data)
 {
+   void __iomem *base = data->base;
unsigned long flags;
 
spin_lock_irqsave(>tlb_lock, flags);
-   writel_relaxed(F_INVLD_EN1 | F_INVLD_EN0,
-  data->base + data->plat_data->inv_sel_reg);
-   writel_relaxed(F_ALL_INVLD, data->base + REG_MMU_INVALIDATE);
+   writel_relaxed(F_INVLD_EN1 | F_INVLD_EN0, base + 
data->plat_data->inv_sel_reg);
+   writel_relaxed(F_ALL_INVLD, base + REG_MMU_INVALIDATE);
wmb(); /* Make sure the tlb flush all done */
spin_unlock_irqrestore(>tlb_lock, flags);
 }
@@ -243,6 +243,7 @@ static void mtk_iommu_tlb_flush_range_sync(unsigned long 
iova, size_t size,
struct list_head *head = data->hw_list;
bool check_pm_status;
unsigned long flags;
+   void __iomem *base;
int ret;
u32 tmp;
 
@@ -269,23 +270,23 @@ static void mtk_iommu_tlb_flush_range_sync(unsigned long 
iova, size_t size,
continue;
}
 
+   base = data->base;
+
spin_lock_irqsave(>tlb_lock, flags);
writel_relaxed(F_INVLD_EN1 | F_INVLD_EN0,
-  data->base + data->plat_data->inv_sel_reg);
+  base + data->plat_data->inv_sel_reg);
 
-   writel_relaxed(MTK_IOMMU_TLB_ADDR(iova),
-  data->base + REG_MMU_INVLD_START_A);
+   writel_relaxed(MTK_IOMMU_TLB_ADDR(iova), base + 
REG_MMU_INVLD_START_A);
writel_relaxed(MTK_IOMMU_TLB_ADDR(iova + size - 1),
-  data->base + REG_MMU_INVLD_END_A);
-   writel_relaxed(F_MMU_INV_RANGE,
-  data->base + REG_MMU_INVALIDATE);
+  base + REG_MMU_INVLD_END_A);
+   writel_relaxed(F_MMU_INV_RANGE, base + REG_MMU_INVALIDATE);
 
/* tlb sync */
-   ret = readl_poll_timeout_atomic(data->base + REG_MMU_CPE_DONE,
+   ret = readl_poll_timeout_atomic(base + REG_MMU_CPE_DONE,
tmp, tmp != 0, 10, 1000);
 
/* Clear the CPE status */
-   writel_relaxed(0, data->base + REG_MMU_CPE_DONE);
+   writel_relaxed(0, base + REG_MMU_CPE_DONE);
spin_unlock_irqrestore(>tlb_lock, flags);
 
if (ret) {
@@ -305,23 +306,25 @@ static irqreturn_t mtk_iommu_isr(int irq, void *dev_id)
struct mtk_iommu_domain *dom = data->m4u_dom;
unsigned int fault_larb = MTK_INVALID_LARBID, fault_port = 0, sub_comm 
= 0;
u32 int_state, regval, va34_32, pa34_32;
+   const struct mtk_iommu_plat_data *plat_data = data->plat_data;
+   void __iomem *base = data->base;
u64 fault_iova, fault_pa;
bool layer, write;
 
/* Read error info from registers */
-   int_state = readl_relaxed(data->base + REG_MMU_FAULT_ST1);
+   int_state = readl_relaxed(base + REG_MMU_FAULT_ST1);
if (int_state & F_REG_MMU0_FAULT_MASK) {
-   regval = readl_relaxed(data->base + REG_MMU0_INT_ID);
-   fault_iova = readl_relaxed(data->base + REG_MMU0_FAULT_VA);
-   fault_pa = readl_relaxed(data->base + REG_MMU0_INVLD_PA);
+   regval = readl_relaxed(base + REG_MMU0_INT_ID);
+   fault_iova = readl_relaxed(base + REG_MMU0_FAULT_VA);
+   fault_pa = readl_relaxed(base + REG_MMU0_INVLD_PA);
} else {
-   regval = readl_relaxed(data->base + REG_MMU1_INT_ID);
-   fault_iova = readl_relaxed(data->base + REG_MMU1_FAULT_VA);
-   fault_pa = readl_relaxed(data->base + REG_MMU1_INVLD_PA);
+   regval = readl_relaxed(base + REG_MMU1_INT_ID);
+   fault_iova = readl_relaxed(base + REG_MMU1_FAULT_VA);
+   fault_pa = readl_relaxed(base + REG_MMU1_INVLD_PA);
}
layer = fault_iova & F_MMU_FAULT_VA_LAYER_BIT;
write = fault_iova & F_MMU_FAULT_VA_WRITE_BIT;
-   if (MTK_IOMMU_HAS_FLAG(data->plat_data, IOVA_34_EN)) {
+   if (MTK_IOMMU_HAS_FLAG(plat_data, IOVA_34_EN)) {
va34_32 = FIELD_GET(F_MMU_INVAL_VA_34_32_MASK, fault_iova);
fault_iova = fault_iova & F_MMU_INVAL_VA_31_12_MASK;
fault_iova |= 

[PATCH v7 23/36] iommu/mediatek: Add mt8195 support

2022-05-03 Thread Yong Wu via iommu
mt8195 has 3 IOMMU, containing 2 MM IOMMUs, one is for vdo, the other
is for vpp. and 1 INFRA IOMMU.

Signed-off-by: Yong Wu 
Reviewed-by: AngeloGioacchino Del Regno 

---
 drivers/iommu/mtk_iommu.c | 41 +++
 drivers/iommu/mtk_iommu.h |  1 +
 2 files changed, 42 insertions(+)

diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c
index d63fe28c1403..47355010502e 100644
--- a/drivers/iommu/mtk_iommu.c
+++ b/drivers/iommu/mtk_iommu.c
@@ -1233,6 +1233,44 @@ static const struct mtk_iommu_plat_data mt8192_data = {
   {0, 14, 16}, {0, 13, 18, 17}},
 };
 
+static const struct mtk_iommu_plat_data mt8195_data_infra = {
+   .m4u_plat = M4U_MT8195,
+   .flags= WR_THROT_EN | DCM_DISABLE | STD_AXI_MODE | 
PM_CLK_AO |
+   MTK_IOMMU_TYPE_INFRA | IFA_IOMMU_PCIE_SUPPORT,
+   .pericfg_comp_str = "mediatek,mt8195-pericfg_ao",
+   .inv_sel_reg  = REG_MMU_INV_SEL_GEN2,
+   .iova_region  = single_domain,
+   .iova_region_nr   = ARRAY_SIZE(single_domain),
+};
+
+static const struct mtk_iommu_plat_data mt8195_data_vdo = {
+   .m4u_plat   = M4U_MT8195,
+   .flags  = HAS_BCLK | HAS_SUB_COMM_2BITS | OUT_ORDER_WR_EN |
+ WR_THROT_EN | IOVA_34_EN | SHARE_PGTABLE | 
MTK_IOMMU_TYPE_MM,
+   .hw_list= ,
+   .inv_sel_reg= REG_MMU_INV_SEL_GEN2,
+   .iova_region= mt8192_multi_dom,
+   .iova_region_nr = ARRAY_SIZE(mt8192_multi_dom),
+   .larbid_remap   = {{2, 0}, {21}, {24}, {7}, {19}, {9, 10, 11},
+  {13, 17, 15/* 17b */, 25}, {5}},
+};
+
+static const struct mtk_iommu_plat_data mt8195_data_vpp = {
+   .m4u_plat   = M4U_MT8195,
+   .flags  = HAS_BCLK | HAS_SUB_COMM_3BITS | OUT_ORDER_WR_EN |
+ WR_THROT_EN | IOVA_34_EN | SHARE_PGTABLE | 
MTK_IOMMU_TYPE_MM,
+   .hw_list= ,
+   .inv_sel_reg= REG_MMU_INV_SEL_GEN2,
+   .iova_region= mt8192_multi_dom,
+   .iova_region_nr = ARRAY_SIZE(mt8192_multi_dom),
+   .larbid_remap   = {{1}, {3},
+  {22, MTK_INVALID_LARBID, MTK_INVALID_LARBID, 
MTK_INVALID_LARBID, 23},
+  {8}, {20}, {12},
+  /* 16: 16a; 29: 16b; 30: CCUtop0; 31: CCUtop1 */
+  {14, 16, 29, 26, 30, 31, 18},
+  {4, MTK_INVALID_LARBID, MTK_INVALID_LARBID, 
MTK_INVALID_LARBID, 6}},
+};
+
 static const struct of_device_id mtk_iommu_of_ids[] = {
{ .compatible = "mediatek,mt2712-m4u", .data = _data},
{ .compatible = "mediatek,mt6779-m4u", .data = _data},
@@ -1240,6 +1278,9 @@ static const struct of_device_id mtk_iommu_of_ids[] = {
{ .compatible = "mediatek,mt8173-m4u", .data = _data},
{ .compatible = "mediatek,mt8183-m4u", .data = _data},
{ .compatible = "mediatek,mt8192-m4u", .data = _data},
+   { .compatible = "mediatek,mt8195-iommu-infra", .data = 
_data_infra},
+   { .compatible = "mediatek,mt8195-iommu-vdo",   .data = 
_data_vdo},
+   { .compatible = "mediatek,mt8195-iommu-vpp",   .data = 
_data_vpp},
{}
 };
 
diff --git a/drivers/iommu/mtk_iommu.h b/drivers/iommu/mtk_iommu.h
index 56838fad8c73..f2ee11cd254a 100644
--- a/drivers/iommu/mtk_iommu.h
+++ b/drivers/iommu/mtk_iommu.h
@@ -46,6 +46,7 @@ enum mtk_iommu_plat {
M4U_MT8173,
M4U_MT8183,
M4U_MT8192,
+   M4U_MT8195,
 };
 
 struct mtk_iommu_iova_region;
-- 
2.18.0

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


[PATCH v7 21/36] iommu/mediatek: Add infra iommu support

2022-05-03 Thread Yong Wu via iommu
The infra iommu enable bits in mt8195 is in the pericfg register segment,
use regmap to update it.

If infra iommu master translation fault, It doesn't have the larbid/portid,
thus print out the whole register value.

Since regmap_update_bits may fail, add return value for mtk_iommu_config.

Signed-off-by: Yong Wu 
Reviewed-by: AngeloGioacchino Del Regno 

---
 drivers/iommu/mtk_iommu.c | 36 +---
 drivers/iommu/mtk_iommu.h |  2 ++
 2 files changed, 31 insertions(+), 7 deletions(-)

diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c
index cd89c109e8c4..ff48506b480c 100644
--- a/drivers/iommu/mtk_iommu.c
+++ b/drivers/iommu/mtk_iommu.c
@@ -112,6 +112,8 @@
 
 #define MTK_PROTECT_PA_ALIGN   256
 
+#define PERICFG_IOMMU_10x714
+
 #define HAS_4GB_MODE   BIT(0)
 /* HW will use the EMI clock if there isn't the "bclk". */
 #define HAS_BCLK   BIT(1)
@@ -343,8 +345,8 @@ static irqreturn_t mtk_iommu_isr(int irq, void *dev_id)
   write ? IOMMU_FAULT_WRITE : IOMMU_FAULT_READ)) {
dev_err_ratelimited(
data->dev,
-   "fault type=0x%x iova=0x%llx pa=0x%llx larb=%d port=%d 
layer=%d %s\n",
-   int_state, fault_iova, fault_pa, fault_larb, fault_port,
+   "fault type=0x%x iova=0x%llx pa=0x%llx 
master=0x%x(larb=%d port=%d) layer=%d %s\n",
+   int_state, fault_iova, fault_pa, regval, fault_larb, 
fault_port,
layer, write ? "write" : "read");
}
 
@@ -388,14 +390,15 @@ static int mtk_iommu_get_domain_id(struct device *dev,
return -EINVAL;
 }
 
-static void mtk_iommu_config(struct mtk_iommu_data *data, struct device *dev,
-bool enable, unsigned int domid)
+static int mtk_iommu_config(struct mtk_iommu_data *data, struct device *dev,
+   bool enable, unsigned int domid)
 {
struct mtk_smi_larb_iommu*larb_mmu;
unsigned int larbid, portid;
struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
const struct mtk_iommu_iova_region *region;
-   int i;
+   u32 peri_mmuen, peri_mmuen_msk;
+   int i, ret = 0;
 
for (i = 0; i < fwspec->num_ids; ++i) {
larbid = MTK_M4U_TO_LARB(fwspec->ids[i]);
@@ -415,8 +418,19 @@ static void mtk_iommu_config(struct mtk_iommu_data *data, 
struct device *dev,
larb_mmu->mmu |= MTK_SMI_MMU_EN(portid);
else
larb_mmu->mmu &= ~MTK_SMI_MMU_EN(portid);
+   } else if (MTK_IOMMU_IS_TYPE(data->plat_data, 
MTK_IOMMU_TYPE_INFRA)) {
+   peri_mmuen_msk = BIT(portid);
+   peri_mmuen = enable ? peri_mmuen_msk : 0;
+
+   ret = regmap_update_bits(data->pericfg, PERICFG_IOMMU_1,
+peri_mmuen_msk, peri_mmuen);
+   if (ret)
+   dev_err(dev, "%s iommu(%s) inframaster 0x%x 
fail(%d).\n",
+   enable ? "enable" : "disable",
+   dev_name(data->dev), peri_mmuen_msk, 
ret);
}
}
+   return ret;
 }
 
 static int mtk_iommu_domain_finalise(struct mtk_iommu_domain *dom,
@@ -531,8 +545,7 @@ static int mtk_iommu_attach_device(struct iommu_domain 
*domain,
}
mutex_unlock(>mutex);
 
-   mtk_iommu_config(data, dev, true, domid);
-   return 0;
+   return mtk_iommu_config(data, dev, true, domid);
 
 err_unlock:
mutex_unlock(>mutex);
@@ -997,6 +1010,15 @@ static int mtk_iommu_probe(struct platform_device *pdev)
dev_err(dev, "mm dts parse fail(%d).", ret);
goto out_runtime_disable;
}
+   } else if (MTK_IOMMU_IS_TYPE(data->plat_data, MTK_IOMMU_TYPE_INFRA) &&
+  data->plat_data->pericfg_comp_str) {
+   infracfg = 
syscon_regmap_lookup_by_compatible(data->plat_data->pericfg_comp_str);
+   if (IS_ERR(infracfg)) {
+   ret = PTR_ERR(infracfg);
+   goto out_runtime_disable;
+   }
+
+   data->pericfg = infracfg;
}
 
platform_set_drvdata(pdev, data);
diff --git a/drivers/iommu/mtk_iommu.h b/drivers/iommu/mtk_iommu.h
index f41e32252056..56838fad8c73 100644
--- a/drivers/iommu/mtk_iommu.h
+++ b/drivers/iommu/mtk_iommu.h
@@ -55,6 +55,7 @@ struct mtk_iommu_plat_data {
u32 flags;
u32 inv_sel_reg;
 
+   char*pericfg_comp_str;
struct list_head*hw_list;
unsigned intiova_region_nr;
const 

[PATCH v7 22/36] iommu/mediatek: Add PCIe support

2022-05-03 Thread Yong Wu via iommu
Currently the code for of_iommu_configure_dev_id is like this:

static int of_iommu_configure_dev_id(struct device_node *master_np,
 struct device *dev,
 const u32 *id)
{
   struct of_phandle_args iommu_spec = { .args_count = 1 };

   err = of_map_id(master_np, *id, "iommu-map",
   "iommu-map-mask", _spec.np,
   iommu_spec.args);
...
}

It supports only one id output. BUT our PCIe HW has two ID(one is for
writing, the other is for reading). I'm not sure if we should change
of_map_id to support output MAX_PHANDLE_ARGS.

Here add the solution in ourselve drivers. If it's pcie case, enable one
more bit.

Not all infra iommu support PCIe, thus add a PCIe support flag here.

Signed-off-by: Yong Wu 
Reviewed-by: AngeloGioacchino Del Regno 

---
 drivers/iommu/mtk_iommu.c | 21 -
 1 file changed, 20 insertions(+), 1 deletion(-)

diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c
index ff48506b480c..d63fe28c1403 100644
--- a/drivers/iommu/mtk_iommu.c
+++ b/drivers/iommu/mtk_iommu.c
@@ -20,6 +20,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -134,6 +135,7 @@
 #define MTK_IOMMU_TYPE_MASK(0x3 << 13)
 /* PM and clock always on. e.g. infra iommu */
 #define PM_CLK_AO  BIT(15)
+#define IFA_IOMMU_PCIE_SUPPORT BIT(16)
 
 #define MTK_IOMMU_HAS_FLAG_MASK(pdata, _x, mask)   \
pdata)->flags) & (mask)) == (_x))
@@ -420,8 +422,11 @@ static int mtk_iommu_config(struct mtk_iommu_data *data, 
struct device *dev,
larb_mmu->mmu &= ~MTK_SMI_MMU_EN(portid);
} else if (MTK_IOMMU_IS_TYPE(data->plat_data, 
MTK_IOMMU_TYPE_INFRA)) {
peri_mmuen_msk = BIT(portid);
-   peri_mmuen = enable ? peri_mmuen_msk : 0;
+   /* PCI dev has only one output id, enable the next 
writing bit for PCIe */
+   if (dev_is_pci(dev))
+   peri_mmuen_msk |= BIT(portid + 1);
 
+   peri_mmuen = enable ? peri_mmuen_msk : 0;
ret = regmap_update_bits(data->pericfg, PERICFG_IOMMU_1,
 peri_mmuen_msk, peri_mmuen);
if (ret)
@@ -1054,6 +1059,15 @@ static int mtk_iommu_probe(struct platform_device *pdev)
ret = component_master_add_with_match(dev, _iommu_com_ops, 
match);
if (ret)
goto out_bus_set_null;
+   } else if (MTK_IOMMU_IS_TYPE(data->plat_data, MTK_IOMMU_TYPE_INFRA) &&
+  MTK_IOMMU_HAS_FLAG(data->plat_data, IFA_IOMMU_PCIE_SUPPORT)) 
{
+#ifdef CONFIG_PCI
+   if (!iommu_present(_bus_type)) {
+   ret = bus_set_iommu(_bus_type, _iommu_ops);
+   if (ret) /* PCIe fail don't affect platform_bus. */
+   goto out_list_del;
+   }
+#endif
}
return ret;
 
@@ -1084,6 +1098,11 @@ static int mtk_iommu_remove(struct platform_device *pdev)
if (MTK_IOMMU_IS_TYPE(data->plat_data, MTK_IOMMU_TYPE_MM)) {
device_link_remove(data->smicomm_dev, >dev);
component_master_del(>dev, _iommu_com_ops);
+   } else if (MTK_IOMMU_IS_TYPE(data->plat_data, MTK_IOMMU_TYPE_INFRA) &&
+  MTK_IOMMU_HAS_FLAG(data->plat_data, IFA_IOMMU_PCIE_SUPPORT)) 
{
+#ifdef CONFIG_PCI
+   bus_set_iommu(_bus_type, NULL);
+#endif
}
pm_runtime_disable(>dev);
devm_free_irq(>dev, data->irq, data);
-- 
2.18.0

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


[PATCH v7 20/36] iommu/mediatek: Add a PM_CLK_AO flag for infra iommu

2022-05-03 Thread Yong Wu via iommu
The power/clock of infra iommu is always on, and it doesn't have the
device link with the master devices, then the infra iommu device's PM
status is not active, thus we add A PM_CLK_AO flag for infra iommu.

The tlb operation is a bit not clear here, there are 2 special cases.
Comment them in the code.

Signed-off-by: Yong Wu 
Reviewed-by: AngeloGioacchino Del Regno 

---
 drivers/iommu/mtk_iommu.c | 29 ++---
 1 file changed, 26 insertions(+), 3 deletions(-)

diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c
index 0121d71c315f..cd89c109e8c4 100644
--- a/drivers/iommu/mtk_iommu.c
+++ b/drivers/iommu/mtk_iommu.c
@@ -130,6 +130,8 @@
 #define MTK_IOMMU_TYPE_MM  (0x0 << 13)
 #define MTK_IOMMU_TYPE_INFRA   (0x1 << 13)
 #define MTK_IOMMU_TYPE_MASK(0x3 << 13)
+/* PM and clock always on. e.g. infra iommu */
+#define PM_CLK_AO  BIT(15)
 
 #define MTK_IOMMU_HAS_FLAG_MASK(pdata, _x, mask)   \
pdata)->flags) & (mask)) == (_x))
@@ -235,13 +237,33 @@ static void mtk_iommu_tlb_flush_range_sync(unsigned long 
iova, size_t size,
   struct mtk_iommu_data *data)
 {
struct list_head *head = data->hw_list;
+   bool check_pm_status;
unsigned long flags;
int ret;
u32 tmp;
 
for_each_m4u(data, head) {
-   if (pm_runtime_get_if_in_use(data->dev) <= 0)
-   continue;
+   /*
+* To avoid resume the iommu device frequently when the iommu 
device
+* is not active, it doesn't always call pm_runtime_get here, 
then tlb
+* flush depends on the tlb flush all in the runtime resume.
+*
+* There are 2 special cases:
+*
+* Case1: The iommu dev doesn't have power domain but has bclk. 
This case
+* should also avoid the tlb flush while the dev is not active 
to mute
+* the tlb timeout log. like mt8173.
+*
+* Case2: The power/clock of infra iommu is always on, and it 
doesn't
+* have the device link with the master devices. This case 
should avoid
+* the PM status check.
+*/
+   check_pm_status = !MTK_IOMMU_HAS_FLAG(data->plat_data, 
PM_CLK_AO);
+
+   if (check_pm_status) {
+   if (pm_runtime_get_if_in_use(data->dev) <= 0)
+   continue;
+   }
 
spin_lock_irqsave(>tlb_lock, flags);
writel_relaxed(F_INVLD_EN1 | F_INVLD_EN0,
@@ -268,7 +290,8 @@ static void mtk_iommu_tlb_flush_range_sync(unsigned long 
iova, size_t size,
mtk_iommu_tlb_flush_all(data);
}
 
-   pm_runtime_put(data->dev);
+   if (check_pm_status)
+   pm_runtime_put(data->dev);
}
 }
 
-- 
2.18.0

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


[PATCH v7 19/36] iommu/mediatek: Allow IOMMU_DOMAIN_UNMANAGED for PCIe VFIO

2022-05-03 Thread Yong Wu via iommu
Allow the type IOMMU_DOMAIN_UNMANAGED since vfio_iommu_type1.c always call
iommu_domain_alloc. The PCIe EP works ok when going through vfio.

Signed-off-by: Yong Wu 
Reviewed-by: AngeloGioacchino Del Regno 

---
 drivers/iommu/mtk_iommu.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c
index bcdc932cd473..0121d71c315f 100644
--- a/drivers/iommu/mtk_iommu.c
+++ b/drivers/iommu/mtk_iommu.c
@@ -446,7 +446,7 @@ static struct iommu_domain *mtk_iommu_domain_alloc(unsigned 
type)
 {
struct mtk_iommu_domain *dom;
 
-   if (type != IOMMU_DOMAIN_DMA)
+   if (type != IOMMU_DOMAIN_DMA && type != IOMMU_DOMAIN_UNMANAGED)
return NULL;
 
dom = kzalloc(sizeof(*dom), GFP_KERNEL);
-- 
2.18.0

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


[PATCH v7 18/36] iommu/mediatek: Adjust device link when it is sub-common

2022-05-03 Thread Yong Wu via iommu
For MM IOMMU, We always add device link between smi-common and IOMMU HW.
In mt8195, we add smi-sub-common. Thus, if the node is sub-common, we still
need find again to get smi-common, then do device link.

Signed-off-by: Yong Wu 
Reviewed-by: AngeloGioacchino Del Regno 

---
 drivers/iommu/mtk_iommu.c | 18 ++
 1 file changed, 14 insertions(+), 4 deletions(-)

diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c
index 7d4bc562b2a3..bcdc932cd473 100644
--- a/drivers/iommu/mtk_iommu.c
+++ b/drivers/iommu/mtk_iommu.c
@@ -834,7 +834,7 @@ static const struct component_master_ops mtk_iommu_com_ops 
= {
 static int mtk_iommu_mm_dts_parse(struct device *dev, struct component_match 
**match,
  struct mtk_iommu_data *data)
 {
-   struct device_node *larbnode, *smicomm_node;
+   struct device_node *larbnode, *smicomm_node, *smi_subcomm_node;
struct platform_device *plarbdev;
struct device_link *link;
int i, larb_nr, ret;
@@ -874,11 +874,21 @@ static int mtk_iommu_mm_dts_parse(struct device *dev, 
struct component_match **m
component_compare_of, larbnode);
}
 
-   /* Get smi-common dev from the last larb. */
-   smicomm_node = of_parse_phandle(larbnode, "mediatek,smi", 0);
-   if (!smicomm_node)
+   /* Get smi-(sub)-common dev from the last larb. */
+   smi_subcomm_node = of_parse_phandle(larbnode, "mediatek,smi", 0);
+   if (!smi_subcomm_node)
return -EINVAL;
 
+   /*
+* It may have two level smi-common. the node is smi-sub-common if it
+* has a new mediatek,smi property. otherwise it is smi-commmon.
+*/
+   smicomm_node = of_parse_phandle(smi_subcomm_node, "mediatek,smi", 0);
+   if (smicomm_node)
+   of_node_put(smi_subcomm_node);
+   else
+   smicomm_node = smi_subcomm_node;
+
plarbdev = of_find_device_by_node(smicomm_node);
of_node_put(smicomm_node);
data->smicomm_dev = >dev;
-- 
2.18.0

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


[PATCH v7 17/36] iommu/mediatek: Contain MM IOMMU flow with the MM TYPE

2022-05-03 Thread Yong Wu via iommu
Prepare for supporting INFRA_IOMMU, and APU_IOMMU later.

For Infra IOMMU/APU IOMMU, it doesn't have the "larb""port". thus, Use
the MM flag contain the MM_IOMMU special flow, Also, it moves a big
chunk code about parsing the mediatek,larbs into a function, this is
only needed for MM IOMMU. and all the current SoC are MM_IOMMU.

The device link between iommu consumer device and smi-larb device only
is needed in MM iommu case.

Signed-off-by: Yong Wu 
Reviewed-by: AngeloGioacchino Del Regno 

---
 drivers/iommu/mtk_iommu.c | 213 ++
 1 file changed, 122 insertions(+), 91 deletions(-)

diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c
index b5b95d9a372e..7d4bc562b2a3 100644
--- a/drivers/iommu/mtk_iommu.c
+++ b/drivers/iommu/mtk_iommu.c
@@ -138,6 +138,8 @@
 #define MTK_IOMMU_IS_TYPE(pdata, _x)   MTK_IOMMU_HAS_FLAG_MASK(pdata, _x,\
MTK_IOMMU_TYPE_MASK)
 
+#define MTK_INVALID_LARBID MTK_LARB_NR_MAX
+
 struct mtk_iommu_domain {
struct io_pgtable_cfg   cfg;
struct io_pgtable_ops   *iop;
@@ -274,7 +276,7 @@ static irqreturn_t mtk_iommu_isr(int irq, void *dev_id)
 {
struct mtk_iommu_data *data = dev_id;
struct mtk_iommu_domain *dom = data->m4u_dom;
-   unsigned int fault_larb, fault_port, sub_comm = 0;
+   unsigned int fault_larb = MTK_INVALID_LARBID, fault_port = 0, sub_comm 
= 0;
u32 int_state, regval, va34_32, pa34_32;
u64 fault_iova, fault_pa;
bool layer, write;
@@ -300,17 +302,19 @@ static irqreturn_t mtk_iommu_isr(int irq, void *dev_id)
pa34_32 = FIELD_GET(F_MMU_INVAL_PA_34_32_MASK, fault_iova);
fault_pa |= (u64)pa34_32 << 32;
 
-   fault_port = F_MMU_INT_ID_PORT_ID(regval);
-   if (MTK_IOMMU_HAS_FLAG(data->plat_data, HAS_SUB_COMM_2BITS)) {
-   fault_larb = F_MMU_INT_ID_COMM_ID(regval);
-   sub_comm = F_MMU_INT_ID_SUB_COMM_ID(regval);
-   } else if (MTK_IOMMU_HAS_FLAG(data->plat_data, HAS_SUB_COMM_3BITS)) {
-   fault_larb = F_MMU_INT_ID_COMM_ID_EXT(regval);
-   sub_comm = F_MMU_INT_ID_SUB_COMM_ID_EXT(regval);
-   } else {
-   fault_larb = F_MMU_INT_ID_LARB_ID(regval);
+   if (MTK_IOMMU_IS_TYPE(data->plat_data, MTK_IOMMU_TYPE_MM)) {
+   fault_port = F_MMU_INT_ID_PORT_ID(regval);
+   if (MTK_IOMMU_HAS_FLAG(data->plat_data, HAS_SUB_COMM_2BITS)) {
+   fault_larb = F_MMU_INT_ID_COMM_ID(regval);
+   sub_comm = F_MMU_INT_ID_SUB_COMM_ID(regval);
+   } else if (MTK_IOMMU_HAS_FLAG(data->plat_data, 
HAS_SUB_COMM_3BITS)) {
+   fault_larb = F_MMU_INT_ID_COMM_ID_EXT(regval);
+   sub_comm = F_MMU_INT_ID_SUB_COMM_ID_EXT(regval);
+   } else {
+   fault_larb = F_MMU_INT_ID_LARB_ID(regval);
+   }
+   fault_larb = 
data->plat_data->larbid_remap[fault_larb][sub_comm];
}
-   fault_larb = data->plat_data->larbid_remap[fault_larb][sub_comm];
 
if (report_iommu_fault(>domain, data->dev, fault_iova,
   write ? IOMMU_FAULT_WRITE : IOMMU_FAULT_READ)) {
@@ -374,19 +378,21 @@ static void mtk_iommu_config(struct mtk_iommu_data *data, 
struct device *dev,
larbid = MTK_M4U_TO_LARB(fwspec->ids[i]);
portid = MTK_M4U_TO_PORT(fwspec->ids[i]);
 
-   larb_mmu = >larb_imu[larbid];
+   if (MTK_IOMMU_IS_TYPE(data->plat_data, MTK_IOMMU_TYPE_MM)) {
+   larb_mmu = >larb_imu[larbid];
 
-   region = data->plat_data->iova_region + domid;
-   larb_mmu->bank[portid] = upper_32_bits(region->iova_base);
+   region = data->plat_data->iova_region + domid;
+   larb_mmu->bank[portid] = 
upper_32_bits(region->iova_base);
 
-   dev_dbg(dev, "%s iommu for larb(%s) port %d dom %d bank %d.\n",
-   enable ? "enable" : "disable", dev_name(larb_mmu->dev),
-   portid, domid, larb_mmu->bank[portid]);
+   dev_dbg(dev, "%s iommu for larb(%s) port %d dom %d bank 
%d.\n",
+   enable ? "enable" : "disable", 
dev_name(larb_mmu->dev),
+   portid, domid, larb_mmu->bank[portid]);
 
-   if (enable)
-   larb_mmu->mmu |= MTK_SMI_MMU_EN(portid);
-   else
-   larb_mmu->mmu &= ~MTK_SMI_MMU_EN(portid);
+   if (enable)
+   larb_mmu->mmu |= MTK_SMI_MMU_EN(portid);
+   else
+   larb_mmu->mmu &= ~MTK_SMI_MMU_EN(portid);
+   }
}
 }
 
@@ -593,6 +599,9 @@ static struct iommu_device *mtk_iommu_probe_device(struct 
device *dev)
 
data = 

[PATCH v7 16/36] iommu/mediatek: Add IOMMU_TYPE flag

2022-05-03 Thread Yong Wu via iommu
Add IOMMU_TYPE definition. In the mt8195, we have another IOMMU_TYPE:
infra iommu, also there will be another APU_IOMMU, thus, use 2bits for the
IOMMU_TYPE.

Signed-off-by: Yong Wu 
Reviewed-by: AngeloGioacchino Del Regno 

---
 drivers/iommu/mtk_iommu.c | 12 ++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c
index 937478cd8966..b5b95d9a372e 100644
--- a/drivers/iommu/mtk_iommu.c
+++ b/drivers/iommu/mtk_iommu.c
@@ -126,9 +126,17 @@
 #define SHARE_PGTABLE  BIT(10) /* 2 HW share pgtable */
 #define DCM_DISABLEBIT(11)
 #define STD_AXI_MODE   BIT(12) /* For non MM iommu */
+/* 2 bits: iommu type */
+#define MTK_IOMMU_TYPE_MM  (0x0 << 13)
+#define MTK_IOMMU_TYPE_INFRA   (0x1 << 13)
+#define MTK_IOMMU_TYPE_MASK(0x3 << 13)
 
-#define MTK_IOMMU_HAS_FLAG(pdata, _x) \
-   pdata)->flags) & (_x)) == (_x))
+#define MTK_IOMMU_HAS_FLAG_MASK(pdata, _x, mask)   \
+   pdata)->flags) & (mask)) == (_x))
+
+#define MTK_IOMMU_HAS_FLAG(pdata, _x)  MTK_IOMMU_HAS_FLAG_MASK(pdata, _x, _x)
+#define MTK_IOMMU_IS_TYPE(pdata, _x)   MTK_IOMMU_HAS_FLAG_MASK(pdata, _x,\
+   MTK_IOMMU_TYPE_MASK)
 
 struct mtk_iommu_domain {
struct io_pgtable_cfg   cfg;
-- 
2.18.0

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


[PATCH v7 15/36] iommu/mediatek: Add SUB_COMMON_3BITS flag

2022-05-03 Thread Yong Wu via iommu
In prevous SoC, the sub common id occupy 2 bits. the mt8195's sub common
id has 3bits. Add a new flag for this. and rename the previous flag to
_2BITS. For readable, I put these two flags together, then move the
other flags. no functional change.

Signed-off-by: Yong Wu 
Reviewed-by: AngeloGioacchino Del Regno 

---
 drivers/iommu/mtk_iommu.c | 26 --
 drivers/iommu/mtk_iommu.h |  2 +-
 2 files changed, 17 insertions(+), 11 deletions(-)

diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c
index d9689e041336..937478cd8966 100644
--- a/drivers/iommu/mtk_iommu.c
+++ b/drivers/iommu/mtk_iommu.c
@@ -105,6 +105,8 @@
 #define REG_MMU1_INT_ID0x154
 #define F_MMU_INT_ID_COMM_ID(a)(((a) >> 9) & 0x7)
 #define F_MMU_INT_ID_SUB_COMM_ID(a)(((a) >> 7) & 0x3)
+#define F_MMU_INT_ID_COMM_ID_EXT(a)(((a) >> 10) & 0x7)
+#define F_MMU_INT_ID_SUB_COMM_ID_EXT(a)(((a) >> 7) & 0x7)
 #define F_MMU_INT_ID_LARB_ID(a)(((a) >> 7) & 0x7)
 #define F_MMU_INT_ID_PORT_ID(a)(((a) >> 2) & 0x1f)
 
@@ -116,13 +118,14 @@
 #define HAS_VLD_PA_RNG BIT(2)
 #define RESET_AXI  BIT(3)
 #define OUT_ORDER_WR_ENBIT(4)
-#define HAS_SUB_COMM   BIT(5)
-#define WR_THROT_ENBIT(6)
-#define HAS_LEGACY_IVRP_PADDR  BIT(7)
-#define IOVA_34_EN BIT(8)
-#define SHARE_PGTABLE  BIT(9) /* 2 HW share pgtable */
-#define DCM_DISABLEBIT(10)
-#define STD_AXI_MODE   BIT(11) /* For non MM iommu */
+#define HAS_SUB_COMM_2BITS BIT(5)
+#define HAS_SUB_COMM_3BITS BIT(6)
+#define WR_THROT_ENBIT(7)
+#define HAS_LEGACY_IVRP_PADDR  BIT(8)
+#define IOVA_34_EN BIT(9)
+#define SHARE_PGTABLE  BIT(10) /* 2 HW share pgtable */
+#define DCM_DISABLEBIT(11)
+#define STD_AXI_MODE   BIT(12) /* For non MM iommu */
 
 #define MTK_IOMMU_HAS_FLAG(pdata, _x) \
pdata)->flags) & (_x)) == (_x))
@@ -290,9 +293,12 @@ static irqreturn_t mtk_iommu_isr(int irq, void *dev_id)
fault_pa |= (u64)pa34_32 << 32;
 
fault_port = F_MMU_INT_ID_PORT_ID(regval);
-   if (MTK_IOMMU_HAS_FLAG(data->plat_data, HAS_SUB_COMM)) {
+   if (MTK_IOMMU_HAS_FLAG(data->plat_data, HAS_SUB_COMM_2BITS)) {
fault_larb = F_MMU_INT_ID_COMM_ID(regval);
sub_comm = F_MMU_INT_ID_SUB_COMM_ID(regval);
+   } else if (MTK_IOMMU_HAS_FLAG(data->plat_data, HAS_SUB_COMM_3BITS)) {
+   fault_larb = F_MMU_INT_ID_COMM_ID_EXT(regval);
+   sub_comm = F_MMU_INT_ID_SUB_COMM_ID_EXT(regval);
} else {
fault_larb = F_MMU_INT_ID_LARB_ID(regval);
}
@@ -1068,7 +1074,7 @@ static const struct mtk_iommu_plat_data mt2712_data = {
 
 static const struct mtk_iommu_plat_data mt6779_data = {
.m4u_plat  = M4U_MT6779,
-   .flags = HAS_SUB_COMM | OUT_ORDER_WR_EN | WR_THROT_EN,
+   .flags = HAS_SUB_COMM_2BITS | OUT_ORDER_WR_EN | WR_THROT_EN,
.inv_sel_reg   = REG_MMU_INV_SEL_GEN2,
.iova_region   = single_domain,
.iova_region_nr = ARRAY_SIZE(single_domain),
@@ -1105,7 +,7 @@ static const struct mtk_iommu_plat_data mt8183_data = {
 
 static const struct mtk_iommu_plat_data mt8192_data = {
.m4u_plat   = M4U_MT8192,
-   .flags  = HAS_BCLK | HAS_SUB_COMM | OUT_ORDER_WR_EN |
+   .flags  = HAS_BCLK | HAS_SUB_COMM_2BITS | OUT_ORDER_WR_EN |
  WR_THROT_EN | IOVA_34_EN,
.inv_sel_reg= REG_MMU_INV_SEL_GEN2,
.iova_region= mt8192_multi_dom,
diff --git a/drivers/iommu/mtk_iommu.h b/drivers/iommu/mtk_iommu.h
index dc868fce0d2a..f41e32252056 100644
--- a/drivers/iommu/mtk_iommu.h
+++ b/drivers/iommu/mtk_iommu.h
@@ -20,7 +20,7 @@
 #include 
 
 #define MTK_LARB_COM_MAX   8
-#define MTK_LARB_SUBCOM_MAX4
+#define MTK_LARB_SUBCOM_MAX8
 
 #define MTK_IOMMU_GROUP_MAX8
 
-- 
2.18.0

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


[PATCH v7 14/36] iommu/mediatek: Always enable output PA over 32bits in isr

2022-05-03 Thread Yong Wu via iommu
Currently the output PA[32:33] is contained by the flag IOVA_34.
This is not right. the iova_34 has no relation with pa[32:33], the 32bits
iova still could map to pa[32:33]. Move it out from the flag.

No need fix tag since currently only mt8192 use the calulation and it
always has this IOVA_34 flag.

Prepare for the IOMMU that still use IOVA 32bits but its dram size may be
over 4GB.

Signed-off-by: Yong Wu 
Reviewed-by: AngeloGioacchino Del Regno 

---
 drivers/iommu/mtk_iommu.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c
index ca77e7f1ce5d..d9689e041336 100644
--- a/drivers/iommu/mtk_iommu.c
+++ b/drivers/iommu/mtk_iommu.c
@@ -283,11 +283,11 @@ static irqreturn_t mtk_iommu_isr(int irq, void *dev_id)
write = fault_iova & F_MMU_FAULT_VA_WRITE_BIT;
if (MTK_IOMMU_HAS_FLAG(data->plat_data, IOVA_34_EN)) {
va34_32 = FIELD_GET(F_MMU_INVAL_VA_34_32_MASK, fault_iova);
-   pa34_32 = FIELD_GET(F_MMU_INVAL_PA_34_32_MASK, fault_iova);
fault_iova = fault_iova & F_MMU_INVAL_VA_31_12_MASK;
fault_iova |= (u64)va34_32 << 32;
-   fault_pa |= (u64)pa34_32 << 32;
}
+   pa34_32 = FIELD_GET(F_MMU_INVAL_PA_34_32_MASK, fault_iova);
+   fault_pa |= (u64)pa34_32 << 32;
 
fault_port = F_MMU_INT_ID_PORT_ID(regval);
if (MTK_IOMMU_HAS_FLAG(data->plat_data, HAS_SUB_COMM)) {
-- 
2.18.0

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


[PATCH v7 13/36] iommu/mediatek: Remove the granule in the tlb flush

2022-05-03 Thread Yong Wu via iommu
The MediaTek IOMMU doesn't care about granule when tlb flushing.
Remove this variable.

Signed-off-by: Yong Wu 
Reviewed-by: AngeloGioacchino Del Regno 

---
 drivers/iommu/mtk_iommu.c | 6 ++
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c
index 22e2b104e3ee..ca77e7f1ce5d 100644
--- a/drivers/iommu/mtk_iommu.c
+++ b/drivers/iommu/mtk_iommu.c
@@ -219,7 +219,6 @@ static void mtk_iommu_tlb_flush_all(struct mtk_iommu_data 
*data)
 }
 
 static void mtk_iommu_tlb_flush_range_sync(unsigned long iova, size_t size,
-  size_t granule,
   struct mtk_iommu_data *data)
 {
struct list_head *head = data->hw_list;
@@ -541,8 +540,7 @@ static void mtk_iommu_iotlb_sync(struct iommu_domain 
*domain,
struct mtk_iommu_domain *dom = to_mtk_domain(domain);
size_t length = gather->end - gather->start + 1;
 
-   mtk_iommu_tlb_flush_range_sync(gather->start, length, gather->pgsize,
-  dom->data);
+   mtk_iommu_tlb_flush_range_sync(gather->start, length, dom->data);
 }
 
 static void mtk_iommu_sync_map(struct iommu_domain *domain, unsigned long iova,
@@ -550,7 +548,7 @@ static void mtk_iommu_sync_map(struct iommu_domain *domain, 
unsigned long iova,
 {
struct mtk_iommu_domain *dom = to_mtk_domain(domain);
 
-   mtk_iommu_tlb_flush_range_sync(iova, size, size, dom->data);
+   mtk_iommu_tlb_flush_range_sync(iova, size, dom->data);
 }
 
 static phys_addr_t mtk_iommu_iova_to_phys(struct iommu_domain *domain,
-- 
2.18.0

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


[PATCH v7 12/36] iommu/mediatek: Add a flag STD_AXI_MODE

2022-05-03 Thread Yong Wu via iommu
Add a new flag STD_AXI_MODE which is prepared for infra and apu iommu
which use the standard axi mode. All the current SoC don't use this flag.

Signed-off-by: Yong Wu 
Reviewed-by: AngeloGioacchino Del Regno 

---
 drivers/iommu/mtk_iommu.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c
index 92f172a772d1..22e2b104e3ee 100644
--- a/drivers/iommu/mtk_iommu.c
+++ b/drivers/iommu/mtk_iommu.c
@@ -122,6 +122,7 @@
 #define IOVA_34_EN BIT(8)
 #define SHARE_PGTABLE  BIT(9) /* 2 HW share pgtable */
 #define DCM_DISABLEBIT(10)
+#define STD_AXI_MODE   BIT(11) /* For non MM iommu */
 
 #define MTK_IOMMU_HAS_FLAG(pdata, _x) \
pdata)->flags) & (_x)) == (_x))
@@ -785,7 +786,8 @@ static int mtk_iommu_hw_init(const struct mtk_iommu_data 
*data)
regval = 0;
} else {
regval = readl_relaxed(data->base + REG_MMU_MISC_CTRL);
-   regval &= ~F_MMU_STANDARD_AXI_MODE_MASK;
+   if (!MTK_IOMMU_HAS_FLAG(data->plat_data, STD_AXI_MODE))
+   regval &= ~F_MMU_STANDARD_AXI_MODE_MASK;
if (MTK_IOMMU_HAS_FLAG(data->plat_data, OUT_ORDER_WR_EN))
regval &= ~F_MMU_IN_ORDER_WR_EN_MASK;
}
-- 
2.18.0

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


[PATCH v7 11/36] iommu/mediatek: Add a flag DCM_DISABLE

2022-05-03 Thread Yong Wu via iommu
In the infra iommu, we should disable DCM. add a new flag for this.

Signed-off-by: Yong Wu 
Reviewed-by: AngeloGioacchino Del Regno 

---
 drivers/iommu/mtk_iommu.c | 9 -
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c
index d91a0c138536..92f172a772d1 100644
--- a/drivers/iommu/mtk_iommu.c
+++ b/drivers/iommu/mtk_iommu.c
@@ -51,6 +51,8 @@
 #define F_MMU_STANDARD_AXI_MODE_MASK   (BIT(3) | BIT(19))
 
 #define REG_MMU_DCM_DIS0x050
+#define F_MMU_DCM  BIT(8)
+
 #define REG_MMU_WR_LEN_CTRL0x054
 #define F_MMU_WR_THROT_DIS_MASK(BIT(5) | BIT(21))
 
@@ -119,6 +121,7 @@
 #define HAS_LEGACY_IVRP_PADDR  BIT(7)
 #define IOVA_34_EN BIT(8)
 #define SHARE_PGTABLE  BIT(9) /* 2 HW share pgtable */
+#define DCM_DISABLEBIT(10)
 
 #define MTK_IOMMU_HAS_FLAG(pdata, _x) \
pdata)->flags) & (_x)) == (_x))
@@ -765,7 +768,11 @@ static int mtk_iommu_hw_init(const struct mtk_iommu_data 
*data)
regval = F_MMU_VLD_PA_RNG(7, 4);
writel_relaxed(regval, data->base + REG_MMU_VLD_PA_RNG);
}
-   writel_relaxed(0, data->base + REG_MMU_DCM_DIS);
+   if (MTK_IOMMU_HAS_FLAG(data->plat_data, DCM_DISABLE))
+   writel_relaxed(F_MMU_DCM, data->base + REG_MMU_DCM_DIS);
+   else
+   writel_relaxed(0, data->base + REG_MMU_DCM_DIS);
+
if (MTK_IOMMU_HAS_FLAG(data->plat_data, WR_THROT_EN)) {
/* write command throttling mode */
regval = readl_relaxed(data->base + REG_MMU_WR_LEN_CTRL);
-- 
2.18.0

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


[PATCH v7 10/36] iommu/mediatek: Add 12G~16G support for multi domains

2022-05-03 Thread Yong Wu via iommu
In mt8192, we preassign 0-4G; 4G-8G; 8G-12G for different multimedia
engines. This depends on the "dma-ranges=" in the iommu consumer's dtsi
node.

Adds 12G-16G region here. and reword the previous comment. we don't limit
which master locate in which region.

CCU still is 8G-12G. Don't change it here.

Signed-off-by: Yong Wu 
Reviewed-by: AngeloGioacchino Del Regno 

---
 drivers/iommu/mtk_iommu.c | 8 +---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c
index 1b8e4405dd0f..d91a0c138536 100644
--- a/drivers/iommu/mtk_iommu.c
+++ b/drivers/iommu/mtk_iommu.c
@@ -180,10 +180,12 @@ static const struct mtk_iommu_iova_region single_domain[] 
= {
 };
 
 static const struct mtk_iommu_iova_region mt8192_multi_dom[] = {
-   { .iova_base = 0x0, .size = SZ_4G}, /* disp: 0 ~ 4G 
*/
+   { .iova_base = 0x0, .size = SZ_4G}, /* 0 ~ 4G */
#if IS_ENABLED(CONFIG_ARCH_DMA_ADDR_T_64BIT)
-   { .iova_base = SZ_4G,   .size = SZ_4G}, /* vdec: 4G ~ 
8G */
-   { .iova_base = SZ_4G * 2,   .size = SZ_4G}, /* CAM/MDP: 8G 
~ 12G */
+   { .iova_base = SZ_4G,   .size = SZ_4G}, /* 4G ~ 8G */
+   { .iova_base = SZ_4G * 2,   .size = SZ_4G}, /* 8G ~ 12G */
+   { .iova_base = SZ_4G * 3,   .size = SZ_4G}, /* 12G ~ 16G */
+
{ .iova_base = 0x24000ULL,  .size = 0x400}, /* CCU0 */
{ .iova_base = 0x24400ULL,  .size = 0x400}, /* CCU1 */
#endif
-- 
2.18.0

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


[PATCH v7 09/36] iommu/mediatek: Adapt sharing and non-sharing pgtable case

2022-05-03 Thread Yong Wu via iommu
In previous mt2712, Both IOMMUs are MM IOMMU, and they will share pgtable.
However in the latest SoC, another is infra IOMMU, there is no reason to
share pgtable between MM with INFRA IOMMU. This patch manage to
implement the two case(sharing and non-sharing pgtable).

Currently we use for_each_m4u to loop the 2 HWs. Add the list_head into
this macro.
In the sharing pgtable case, the list_head is the global "m4ulist".
In the non-sharing pgtable case, the list_head is hw_list_head which is a
variable in the "data". then for_each_m4u will only loop itself.

Signed-off-by: Yong Wu 
Reviewed-by: AngeloGioacchino Del Regno 

---
 drivers/iommu/mtk_iommu.c | 43 +--
 drivers/iommu/mtk_iommu.h |  7 +++
 2 files changed, 30 insertions(+), 20 deletions(-)

diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c
index ecdce5d3e8cf..1b8e4405dd0f 100644
--- a/drivers/iommu/mtk_iommu.c
+++ b/drivers/iommu/mtk_iommu.c
@@ -118,6 +118,7 @@
 #define WR_THROT_ENBIT(6)
 #define HAS_LEGACY_IVRP_PADDR  BIT(7)
 #define IOVA_34_EN BIT(8)
+#define SHARE_PGTABLE  BIT(9) /* 2 HW share pgtable */
 
 #define MTK_IOMMU_HAS_FLAG(pdata, _x) \
pdata)->flags) & (_x)) == (_x))
@@ -167,7 +168,7 @@ static int mtk_iommu_hw_init(const struct mtk_iommu_data 
*data);
 
 static LIST_HEAD(m4ulist); /* List all the M4U HWs */
 
-#define for_each_m4u(data) list_for_each_entry(data, , list)
+#define for_each_m4u(data, head)  list_for_each_entry(data, head, list)
 
 struct mtk_iommu_iova_region {
dma_addr_t  iova_base;
@@ -188,21 +189,10 @@ static const struct mtk_iommu_iova_region 
mt8192_multi_dom[] = {
#endif
 };
 
-/*
- * There may be 1 or 2 M4U HWs, But we always expect they are in the same 
domain
- * for the performance.
- *
- * Here always return the mtk_iommu_data of the first probed M4U where the
- * iommu domain information is recorded.
- */
-static struct mtk_iommu_data *mtk_iommu_get_m4u_data(void)
+/* If 2 M4U share a domain(use the same hwlist), Put the corresponding info in 
first data.*/
+static struct mtk_iommu_data *mtk_iommu_get_frst_data(struct list_head *hwlist)
 {
-   struct mtk_iommu_data *data;
-
-   for_each_m4u(data)
-   return data;
-
-   return NULL;
+   return list_first_entry(hwlist, struct mtk_iommu_data, list);
 }
 
 static struct mtk_iommu_domain *to_mtk_domain(struct iommu_domain *dom)
@@ -226,11 +216,12 @@ static void mtk_iommu_tlb_flush_range_sync(unsigned long 
iova, size_t size,
   size_t granule,
   struct mtk_iommu_data *data)
 {
+   struct list_head *head = data->hw_list;
unsigned long flags;
int ret;
u32 tmp;
 
-   for_each_m4u(data) {
+   for_each_m4u(data, head) {
if (pm_runtime_get_if_in_use(data->dev) <= 0)
continue;
 
@@ -451,6 +442,7 @@ static int mtk_iommu_attach_device(struct iommu_domain 
*domain,
 {
struct mtk_iommu_data *data = dev_iommu_priv_get(dev), *frstdata;
struct mtk_iommu_domain *dom = to_mtk_domain(domain);
+   struct list_head *hw_list = data->hw_list;
struct device *m4udev = data->dev;
int ret, domid;
 
@@ -461,7 +453,7 @@ static int mtk_iommu_attach_device(struct iommu_domain 
*domain,
mutex_lock(>mutex);
if (!dom->data) {
/* Data is in the frstdata in sharing pgtable case. */
-   frstdata = mtk_iommu_get_m4u_data();
+   frstdata = mtk_iommu_get_frst_data(hw_list);
 
ret = mtk_iommu_domain_finalise(dom, frstdata, domid);
if (ret) {
@@ -625,10 +617,12 @@ static void mtk_iommu_release_device(struct device *dev)
 
 static struct iommu_group *mtk_iommu_device_group(struct device *dev)
 {
-   struct mtk_iommu_data *data = mtk_iommu_get_m4u_data();
+   struct mtk_iommu_data *c_data = dev_iommu_priv_get(dev), *data;
+   struct list_head *hw_list = c_data->hw_list;
struct iommu_group *group;
int domid;
 
+   data = mtk_iommu_get_frst_data(hw_list);
if (!data)
return ERR_PTR(-ENODEV);
 
@@ -938,7 +932,15 @@ static int mtk_iommu_probe(struct platform_device *pdev)
goto out_sysfs_remove;
 
spin_lock_init(>tlb_lock);
-   list_add_tail(>list, );
+
+   if (MTK_IOMMU_HAS_FLAG(data->plat_data, SHARE_PGTABLE)) {
+   list_add_tail(>list, data->plat_data->hw_list);
+   data->hw_list = data->plat_data->hw_list;
+   } else {
+   INIT_LIST_HEAD(>hw_list_head);
+   list_add_tail(>list, >hw_list_head);
+   data->hw_list = >hw_list_head;
+   }
 
if (!iommu_present(_bus_type)) {
ret = bus_set_iommu(_bus_type, _iommu_ops);
@@ -1047,7 +1049,8 @@ static const struct 

[PATCH v7 08/36] iommu/mediatek: Add mutex for data in the mtk_iommu_domain

2022-05-03 Thread Yong Wu via iommu
Same with the previous patch, add a mutex for the "data" in the
mtk_iommu_domain. Just improve the safety for multi devices
enter attach_device at the same time. We don't get the real issue
for this.

Signed-off-by: Yong Wu 
Reviewed-by: AngeloGioacchino Del Regno 

---
 drivers/iommu/mtk_iommu.c | 10 +-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c
index 3413cc98e57e..ecdce5d3e8cf 100644
--- a/drivers/iommu/mtk_iommu.c
+++ b/drivers/iommu/mtk_iommu.c
@@ -128,6 +128,8 @@ struct mtk_iommu_domain {
 
struct mtk_iommu_data   *data;
struct iommu_domain domain;
+
+   struct mutexmutex; /* Protect "data" in this 
structure */
 };
 
 static const struct iommu_ops mtk_iommu_ops;
@@ -434,6 +436,7 @@ static struct iommu_domain *mtk_iommu_domain_alloc(unsigned 
type)
dom = kzalloc(sizeof(*dom), GFP_KERNEL);
if (!dom)
return NULL;
+   mutex_init(>mutex);
 
return >domain;
 }
@@ -455,14 +458,19 @@ static int mtk_iommu_attach_device(struct iommu_domain 
*domain,
if (domid < 0)
return domid;
 
+   mutex_lock(>mutex);
if (!dom->data) {
/* Data is in the frstdata in sharing pgtable case. */
frstdata = mtk_iommu_get_m4u_data();
 
-   if (mtk_iommu_domain_finalise(dom, frstdata, domid))
+   ret = mtk_iommu_domain_finalise(dom, frstdata, domid);
+   if (ret) {
+   mutex_unlock(>mutex);
return -ENODEV;
+   }
dom->data = data;
}
+   mutex_unlock(>mutex);
 
mutex_lock(>mutex);
if (!data->m4u_dom) { /* Initialize the M4U HW */
-- 
2.18.0

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


[PATCH v7 07/36] iommu/mediatek: Add mutex for m4u_group and m4u_dom in data

2022-05-03 Thread Yong Wu via iommu
Add a mutex to protect the data in the structure mtk_iommu_data,
like ->"m4u_group" ->"m4u_dom". For the internal data, we should
protect it in ourselves driver. Add a mutex for this.
This could be a fix for the multi-groups support.

Fixes: c3045f39244e ("iommu/mediatek: Support for multi domains")
Signed-off-by: Yunfei Wang 
Signed-off-by: Yong Wu 
Reviewed-by: AngeloGioacchino Del Regno 

---
 drivers/iommu/mtk_iommu.c | 13 +++--
 drivers/iommu/mtk_iommu.h |  2 ++
 2 files changed, 13 insertions(+), 2 deletions(-)

diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c
index 81b8db450eac..3413cc98e57e 100644
--- a/drivers/iommu/mtk_iommu.c
+++ b/drivers/iommu/mtk_iommu.c
@@ -464,15 +464,16 @@ static int mtk_iommu_attach_device(struct iommu_domain 
*domain,
dom->data = data;
}
 
+   mutex_lock(>mutex);
if (!data->m4u_dom) { /* Initialize the M4U HW */
ret = pm_runtime_resume_and_get(m4udev);
if (ret < 0)
-   return ret;
+   goto err_unlock;
 
ret = mtk_iommu_hw_init(data);
if (ret) {
pm_runtime_put(m4udev);
-   return ret;
+   goto err_unlock;
}
data->m4u_dom = dom;
writel(dom->cfg.arm_v7s_cfg.ttbr & MMU_PT_ADDR_MASK,
@@ -480,9 +481,14 @@ static int mtk_iommu_attach_device(struct iommu_domain 
*domain,
 
pm_runtime_put(m4udev);
}
+   mutex_unlock(>mutex);
 
mtk_iommu_config(data, dev, true, domid);
return 0;
+
+err_unlock:
+   mutex_unlock(>mutex);
+   return ret;
 }
 
 static void mtk_iommu_detach_device(struct iommu_domain *domain,
@@ -622,6 +628,7 @@ static struct iommu_group *mtk_iommu_device_group(struct 
device *dev)
if (domid < 0)
return ERR_PTR(domid);
 
+   mutex_lock(>mutex);
group = data->m4u_group[domid];
if (!group) {
group = iommu_group_alloc();
@@ -630,6 +637,7 @@ static struct iommu_group *mtk_iommu_device_group(struct 
device *dev)
} else {
iommu_group_ref_get(group);
}
+   mutex_unlock(>mutex);
return group;
 }
 
@@ -910,6 +918,7 @@ static int mtk_iommu_probe(struct platform_device *pdev)
}
 
platform_set_drvdata(pdev, data);
+   mutex_init(>mutex);
 
ret = iommu_device_sysfs_add(>iommu, dev, NULL,
 "mtk-iommu.%pa", );
diff --git a/drivers/iommu/mtk_iommu.h b/drivers/iommu/mtk_iommu.h
index b742432220c5..5e8da947affc 100644
--- a/drivers/iommu/mtk_iommu.h
+++ b/drivers/iommu/mtk_iommu.h
@@ -80,6 +80,8 @@ struct mtk_iommu_data {
 
struct dma_iommu_mapping*mapping; /* For mtk_iommu_v1.c */
 
+   struct mutexmutex; /* Protect m4u_group/m4u_dom 
above */
+
struct list_headlist;
struct mtk_smi_larb_iommu   larb_imu[MTK_LARB_NR_MAX];
 };
-- 
2.18.0

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


[PATCH v7 05/36] iommu/mediatek: Add list_del in mtk_iommu_remove

2022-05-03 Thread Yong Wu via iommu
Lack the list_del in the mtk_iommu_remove, and remove
bus_set_iommu(*, NULL) since there may be several iommu HWs.
we can not bus_set_iommu null when one iommu driver unbind.

This could be a fix for mt2712 which support 2 M4U HW and list them.

Fixes: 7c3a2ec02806 ("iommu/mediatek: Merge 2 M4U HWs into one iommu domain")
Signed-off-by: Yong Wu 
Reviewed-by: AngeloGioacchino Del Regno 

---
 drivers/iommu/mtk_iommu.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c
index 95c82b8bcc35..e4b4ebbcb73f 100644
--- a/drivers/iommu/mtk_iommu.c
+++ b/drivers/iommu/mtk_iommu.c
@@ -955,8 +955,7 @@ static int mtk_iommu_remove(struct platform_device *pdev)
iommu_device_sysfs_remove(>iommu);
iommu_device_unregister(>iommu);
 
-   if (iommu_present(_bus_type))
-   bus_set_iommu(_bus_type, NULL);
+   list_del(>list);
 
clk_disable_unprepare(data->bclk);
device_link_remove(data->smicomm_dev, >dev);
-- 
2.18.0

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


[PATCH v7 06/36] iommu/mediatek: Remove clk_disable in mtk_iommu_remove

2022-05-03 Thread Yong Wu via iommu
After the commit b34ea31fe013 ("iommu/mediatek: Always enable the clk on
resume"), the iommu clock is controlled by the runtime callback.
thus remove the clk control in the mtk_iommu_remove.

Otherwise, it will warning like:

echo 14018000.iommu > /sys/bus/platform/drivers/mtk-iommu/unbind

[   51.413044] [ cut here ]
[   51.413648] vpp0_smi_iommu already disabled
[   51.414233] WARNING: CPU: 2 PID: 157 at */v5.15-rc1/kernel/mediatek/
  drivers/clk/clk.c:952 clk_core_disable+0xb0/0xb8
[   51.417174] Hardware name: MT8195V/C(ENG) (DT)
[   51.418635] pc : clk_core_disable+0xb0/0xb8
[   51.419177] lr : clk_core_disable+0xb0/0xb8
...
[   51.429375] Call trace:
[   51.429694]  clk_core_disable+0xb0/0xb8
[   51.430193]  clk_core_disable_lock+0x24/0x40
[   51.430745]  clk_disable+0x20/0x30
[   51.431189]  mtk_iommu_remove+0x58/0x118
[   51.431705]  platform_remove+0x28/0x60
[   51.432197]  device_release_driver_internal+0x110/0x1f0
[   51.432873]  device_driver_detach+0x18/0x28
[   51.433418]  unbind_store+0xd4/0x108
[   51.433886]  drv_attr_store+0x24/0x38
[   51.434363]  sysfs_kf_write+0x40/0x58
[   51.434843]  kernfs_fop_write_iter+0x164/0x1e0

Fixes: b34ea31fe013 ("iommu/mediatek: Always enable the clk on resume")
Reported-by: Hsin-Yi Wang 
Signed-off-by: Yong Wu 
Reviewed-by: AngeloGioacchino Del Regno 

---
 drivers/iommu/mtk_iommu.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c
index e4b4ebbcb73f..81b8db450eac 100644
--- a/drivers/iommu/mtk_iommu.c
+++ b/drivers/iommu/mtk_iommu.c
@@ -957,7 +957,6 @@ static int mtk_iommu_remove(struct platform_device *pdev)
 
list_del(>list);
 
-   clk_disable_unprepare(data->bclk);
device_link_remove(data->smicomm_dev, >dev);
pm_runtime_disable(>dev);
devm_free_irq(>dev, data->irq, data);
-- 
2.18.0

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


[PATCH v7 04/36] iommu/mediatek: Fix 2 HW sharing pgtable issue

2022-05-03 Thread Yong Wu via iommu
In the commit 4f956c97d26b ("iommu/mediatek: Move domain_finalise into
attach_device"), I overlooked the sharing pgtable case.
After that commit, the "data" in the mtk_iommu_domain_finalise always is
the data of the current IOMMU HW. Fix this for the sharing pgtable case.

Only affect mt2712 which is the only SoC that share pgtable currently.

Fixes: 4f956c97d26b ("iommu/mediatek: Move domain_finalise into attach_device")
Signed-off-by: Yong Wu 
Reviewed-by: AngeloGioacchino Del Regno 

---
 drivers/iommu/mtk_iommu.c | 7 +--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c
index 6fd75a60abd6..95c82b8bcc35 100644
--- a/drivers/iommu/mtk_iommu.c
+++ b/drivers/iommu/mtk_iommu.c
@@ -446,7 +446,7 @@ static void mtk_iommu_domain_free(struct iommu_domain 
*domain)
 static int mtk_iommu_attach_device(struct iommu_domain *domain,
   struct device *dev)
 {
-   struct mtk_iommu_data *data = dev_iommu_priv_get(dev);
+   struct mtk_iommu_data *data = dev_iommu_priv_get(dev), *frstdata;
struct mtk_iommu_domain *dom = to_mtk_domain(domain);
struct device *m4udev = data->dev;
int ret, domid;
@@ -456,7 +456,10 @@ static int mtk_iommu_attach_device(struct iommu_domain 
*domain,
return domid;
 
if (!dom->data) {
-   if (mtk_iommu_domain_finalise(dom, data, domid))
+   /* Data is in the frstdata in sharing pgtable case. */
+   frstdata = mtk_iommu_get_m4u_data();
+
+   if (mtk_iommu_domain_finalise(dom, frstdata, domid))
return -ENODEV;
dom->data = data;
}
-- 
2.18.0

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


[PATCH v7 03/36] dt-bindings: mediatek: mt8186: Add binding for MM iommu

2022-05-03 Thread Yong Wu via iommu
Add mt8186 iommu binding. "-mm" means the iommu is for Multimedia.

Signed-off-by: Yong Wu 
Acked-by: Krzysztof Kozlowski 
Reviewed-by: Rob Herring 
Reviewed-by: Matthias Brugger 
Reviewed-by: AngeloGioacchino Del Regno 

---
 .../bindings/iommu/mediatek,iommu.yaml|   4 +
 .../dt-bindings/memory/mt8186-memory-port.h   | 217 ++
 2 files changed, 221 insertions(+)
 create mode 100644 include/dt-bindings/memory/mt8186-memory-port.h

diff --git a/Documentation/devicetree/bindings/iommu/mediatek,iommu.yaml 
b/Documentation/devicetree/bindings/iommu/mediatek,iommu.yaml
index eed59ec00e78..91a3629a8e6e 100644
--- a/Documentation/devicetree/bindings/iommu/mediatek,iommu.yaml
+++ b/Documentation/devicetree/bindings/iommu/mediatek,iommu.yaml
@@ -76,6 +76,7 @@ properties:
   - mediatek,mt8167-m4u  # generation two
   - mediatek,mt8173-m4u  # generation two
   - mediatek,mt8183-m4u  # generation two
+  - mediatek,mt8186-iommu-mm # generation two
   - mediatek,mt8192-m4u  # generation two
   - mediatek,mt8195-iommu-vdo# generation two
   - mediatek,mt8195-iommu-vpp# generation two
@@ -122,6 +123,7 @@ properties:
   dt-binding/memory/mt8167-larb-port.h for mt8167,
   dt-binding/memory/mt8173-larb-port.h for mt8173,
   dt-binding/memory/mt8183-larb-port.h for mt8183,
+  dt-binding/memory/mt8186-memory-port.h for mt8186,
   dt-binding/memory/mt8192-larb-port.h for mt8192.
   dt-binding/memory/mt8195-memory-port.h for mt8195.
 
@@ -143,6 +145,7 @@ allOf:
   - mediatek,mt2701-m4u
   - mediatek,mt2712-m4u
   - mediatek,mt8173-m4u
+  - mediatek,mt8186-iommu-mm
   - mediatek,mt8192-m4u
   - mediatek,mt8195-iommu-vdo
   - mediatek,mt8195-iommu-vpp
@@ -155,6 +158,7 @@ allOf:
   properties:
 compatible:
   enum:
+- mediatek,mt8186-iommu-mm
 - mediatek,mt8192-m4u
 - mediatek,mt8195-iommu-vdo
 - mediatek,mt8195-iommu-vpp
diff --git a/include/dt-bindings/memory/mt8186-memory-port.h 
b/include/dt-bindings/memory/mt8186-memory-port.h
new file mode 100644
index ..2bc6e4433048
--- /dev/null
+++ b/include/dt-bindings/memory/mt8186-memory-port.h
@@ -0,0 +1,217 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2022 MediaTek Inc.
+ *
+ * Author: Anan Sun 
+ * Author: Yong Wu 
+ */
+#ifndef _DT_BINDINGS_MEMORY_MT8186_LARB_PORT_H_
+#define _DT_BINDINGS_MEMORY_MT8186_LARB_PORT_H_
+
+#include 
+
+/*
+ * MM IOMMU supports 16GB dma address. We separate it to four ranges:
+ * 0 ~ 4G; 4G ~ 8G; 8G ~ 12G; 12G ~ 16G, we could adjust these masters
+ * locate in anyone region. BUT:
+ * a) Make sure all the ports inside a larb are in one range.
+ * b) The iova of any master can NOT cross the 4G/8G/12G boundary.
+ *
+ * This is the suggested mapping in this SoC:
+ *
+ * modulesdma-address-region   larbs-ports
+ * disp 0 ~ 4G  larb0/1/2
+ * vcodec  4G ~ 8G  larb4/7
+ * cam/mdp 8G ~ 12G the other larbs.
+ * N/A 12G ~ 16G
+ * CCU0   0x24000_ ~ 0x243ff_   larb13: port 9/10
+ * CCU1   0x24400_ ~ 0x247ff_   larb14: port 4/5
+ */
+
+/* MM IOMMU ports */
+/* LARB 0 -- MMSYS */
+#define IOMMU_PORT_L0_DISP_POSTMASK0   MTK_M4U_ID(0, 0)
+#define IOMMU_PORT_L0_REVERSED MTK_M4U_ID(0, 1)
+#define IOMMU_PORT_L0_OVL_RDMA0MTK_M4U_ID(0, 2)
+#define IOMMU_PORT_L0_DISP_FAKE0   MTK_M4U_ID(0, 3)
+
+/* LARB 1 -- MMSYS */
+#define IOMMU_PORT_L1_DISP_RDMA1   MTK_M4U_ID(1, 0)
+#define IOMMU_PORT_L1_OVL_2L_RDMA0 MTK_M4U_ID(1, 1)
+#define IOMMU_PORT_L1_DISP_RDMA0   MTK_M4U_ID(1, 2)
+#define IOMMU_PORT_L1_DISP_WDMA0   MTK_M4U_ID(1, 3)
+#define IOMMU_PORT_L1_DISP_FAKE1   MTK_M4U_ID(1, 4)
+
+/* LARB 2 -- MMSYS */
+#define IOMMU_PORT_L2_MDP_RDMA0MTK_M4U_ID(2, 0)
+#define IOMMU_PORT_L2_MDP_RDMA1MTK_M4U_ID(2, 1)
+#define IOMMU_PORT_L2_MDP_WROT0MTK_M4U_ID(2, 2)
+#define IOMMU_PORT_L2_MDP_WROT1MTK_M4U_ID(2, 3)
+#define IOMMU_PORT_L2_DISP_FAKE0   MTK_M4U_ID(2, 4)
+
+/* LARB 4 -- VDEC */
+#define IOMMU_PORT_L4_HW_VDEC_MC_EXT   MTK_M4U_ID(4, 0)
+#define IOMMU_PORT_L4_HW_VDEC_UFO_EXT  MTK_M4U_ID(4, 1)
+#define IOMMU_PORT_L4_HW_VDEC_PP_EXT   MTK_M4U_ID(4, 2)
+#define IOMMU_PORT_L4_HW_VDEC_PRED_RD_EXT  MTK_M4U_ID(4, 3)
+#define IOMMU_PORT_L4_HW_VDEC_PRED_WR_EXT  MTK_M4U_ID(4, 4)
+#define IOMMU_PORT_L4_HW_VDEC_PPWRAP_EXT   MTK_M4U_ID(4, 5)
+#define IOMMU_PORT_L4_HW_VDEC_TILE_EXT MTK_M4U_ID(4, 6)
+#define IOMMU_PORT_L4_HW_VDEC_VLD_EXT  MTK_M4U_ID(4, 7)
+#define IOMMU_PORT_L4_HW_VDEC_VLD2_EXT MTK_M4U_ID(4, 8)
+#define IOMMU_PORT_L4_HW_VDEC_AVC_MV_EXT   MTK_M4U_ID(4, 9)
+#define IOMMU_PORT_L4_HW_VDEC_UFO_ENC_EXT  

[PATCH v7 02/36] dt-bindings: mediatek: mt8195: Add binding for infra IOMMU

2022-05-03 Thread Yong Wu via iommu
In mt8195, we have a new IOMMU that is for INFRA IOMMU. its masters
mainly are PCIe and USB. Different with MM IOMMU, all these masters
connect with IOMMU directly, there is no mediatek,larbs property for
infra IOMMU.

Another thing is about PCIe ports. currently the function
"of_iommu_configure_dev_id" only support the id number is 1, But our
PCIe have two ports, one is for reading and the other is for writing.
see more about the PCIe patch in this patchset. Thus, I only list
the reading id here and add the other id in our driver.

Signed-off-by: Yong Wu 
Acked-by: Krzysztof Kozlowski 
Reviewed-by: Rob Herring 
---
 .../bindings/iommu/mediatek,iommu.yaml | 13 -
 .../dt-bindings/memory/mt8195-memory-port.h| 18 ++
 include/dt-bindings/memory/mtk-memory-port.h   |  2 ++
 3 files changed, 32 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/iommu/mediatek,iommu.yaml 
b/Documentation/devicetree/bindings/iommu/mediatek,iommu.yaml
index 2223408e91a9..eed59ec00e78 100644
--- a/Documentation/devicetree/bindings/iommu/mediatek,iommu.yaml
+++ b/Documentation/devicetree/bindings/iommu/mediatek,iommu.yaml
@@ -79,6 +79,7 @@ properties:
   - mediatek,mt8192-m4u  # generation two
   - mediatek,mt8195-iommu-vdo# generation two
   - mediatek,mt8195-iommu-vpp# generation two
+  - mediatek,mt8195-iommu-infra  # generation two
 
   - description: mt7623 generation one
 items:
@@ -131,7 +132,6 @@ required:
   - compatible
   - reg
   - interrupts
-  - mediatek,larbs
   - '#iommu-cells'
 
 allOf:
@@ -163,6 +163,17 @@ allOf:
   required:
 - power-domains
 
+  - if: # The IOMMUs don't have larbs.
+  not:
+properties:
+  compatible:
+contains:
+  const: mediatek,mt8195-iommu-infra
+
+then:
+  required:
+- mediatek,larbs
+
 additionalProperties: false
 
 examples:
diff --git a/include/dt-bindings/memory/mt8195-memory-port.h 
b/include/dt-bindings/memory/mt8195-memory-port.h
index c10e8b61f1e8..70ba9f498eeb 100644
--- a/include/dt-bindings/memory/mt8195-memory-port.h
+++ b/include/dt-bindings/memory/mt8195-memory-port.h
@@ -387,4 +387,22 @@
 #define M4U_PORT_L28_CAM_DRZS4NO_R1MTK_M4U_ID(28, 5)
 #define M4U_PORT_L28_CAM_TNCSO_R1  MTK_M4U_ID(28, 6)
 
+/* Infra iommu ports */
+/* PCIe1: read: BIT16; write BIT17. */
+#define IOMMU_PORT_INFRA_PCIE1 MTK_IFAIOMMU_PERI_ID(16)
+/* PCIe0: read: BIT18; write BIT19. */
+#define IOMMU_PORT_INFRA_PCIE0 MTK_IFAIOMMU_PERI_ID(18)
+#define IOMMU_PORT_INFRA_SSUSB_P3_RMTK_IFAIOMMU_PERI_ID(20)
+#define IOMMU_PORT_INFRA_SSUSB_P3_WMTK_IFAIOMMU_PERI_ID(21)
+#define IOMMU_PORT_INFRA_SSUSB_P2_RMTK_IFAIOMMU_PERI_ID(22)
+#define IOMMU_PORT_INFRA_SSUSB_P2_WMTK_IFAIOMMU_PERI_ID(23)
+#define IOMMU_PORT_INFRA_SSUSB_P1_1_R  MTK_IFAIOMMU_PERI_ID(24)
+#define IOMMU_PORT_INFRA_SSUSB_P1_1_W  MTK_IFAIOMMU_PERI_ID(25)
+#define IOMMU_PORT_INFRA_SSUSB_P1_0_R  MTK_IFAIOMMU_PERI_ID(26)
+#define IOMMU_PORT_INFRA_SSUSB_P1_0_W  MTK_IFAIOMMU_PERI_ID(27)
+#define IOMMU_PORT_INFRA_SSUSB2_R  MTK_IFAIOMMU_PERI_ID(28)
+#define IOMMU_PORT_INFRA_SSUSB2_W  MTK_IFAIOMMU_PERI_ID(29)
+#define IOMMU_PORT_INFRA_SSUSB_R   MTK_IFAIOMMU_PERI_ID(30)
+#define IOMMU_PORT_INFRA_SSUSB_W   MTK_IFAIOMMU_PERI_ID(31)
+
 #endif
diff --git a/include/dt-bindings/memory/mtk-memory-port.h 
b/include/dt-bindings/memory/mtk-memory-port.h
index 7d64103209af..2f68a0511a25 100644
--- a/include/dt-bindings/memory/mtk-memory-port.h
+++ b/include/dt-bindings/memory/mtk-memory-port.h
@@ -12,4 +12,6 @@
 #define MTK_M4U_TO_LARB(id)(((id) >> 5) & 0x1f)
 #define MTK_M4U_TO_PORT(id)((id) & 0x1f)
 
+#define MTK_IFAIOMMU_PERI_ID(port) MTK_M4U_ID(0, port)
+
 #endif
-- 
2.18.0

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


[PATCH v7 01/36] dt-bindings: mediatek: mt8195: Add binding for MM IOMMU

2022-05-03 Thread Yong Wu via iommu
This patch adds descriptions for mt8195 IOMMU which also use ARM
Short-Descriptor translation table format.

In mt8195, there are two smi-common HW and IOMMU, one is for vdo(video
output), the other is for vpp(video processing pipe). They connects
with different smi-larbs, then some setting(larbid_remap) is different.
Differentiate them with the compatible string.

Something like this:

IOMMU(VDO)  IOMMU(VPP)
   |   |
  SMI_COMMON_VDO  SMI_COMMON_VPP
  --- 
  |  |   ...  |  | ...
larb0 larb2  ...larb1 larb3...

Another change is that we have a new IOMMU that is for infra master like
PCIe and USB. The infra master don't have the larb and ports, thus we
rename the port header file to mt8195-memory-port.h rather than
mt8195-larb-port.h.

Also, the IOMMU is not only for MM, thus, we don't call it "m4u" which
means "MultiMedia Memory Management UNIT". thus, use the "iommu" as the
compatiable string.

Signed-off-by: Yong Wu 
Acked-by: Krzysztof Kozlowski 
Reviewed-by: Rob Herring 
---
 .../bindings/iommu/mediatek,iommu.yaml|   7 +
 .../dt-bindings/memory/mt8195-memory-port.h   | 390 ++
 2 files changed, 397 insertions(+)
 create mode 100644 include/dt-bindings/memory/mt8195-memory-port.h

diff --git a/Documentation/devicetree/bindings/iommu/mediatek,iommu.yaml 
b/Documentation/devicetree/bindings/iommu/mediatek,iommu.yaml
index 97e8c471a5e8..2223408e91a9 100644
--- a/Documentation/devicetree/bindings/iommu/mediatek,iommu.yaml
+++ b/Documentation/devicetree/bindings/iommu/mediatek,iommu.yaml
@@ -77,6 +77,8 @@ properties:
   - mediatek,mt8173-m4u  # generation two
   - mediatek,mt8183-m4u  # generation two
   - mediatek,mt8192-m4u  # generation two
+  - mediatek,mt8195-iommu-vdo# generation two
+  - mediatek,mt8195-iommu-vpp# generation two
 
   - description: mt7623 generation one
 items:
@@ -120,6 +122,7 @@ properties:
   dt-binding/memory/mt8173-larb-port.h for mt8173,
   dt-binding/memory/mt8183-larb-port.h for mt8183,
   dt-binding/memory/mt8192-larb-port.h for mt8192.
+  dt-binding/memory/mt8195-memory-port.h for mt8195.
 
   power-domains:
 maxItems: 1
@@ -141,6 +144,8 @@ allOf:
   - mediatek,mt2712-m4u
   - mediatek,mt8173-m4u
   - mediatek,mt8192-m4u
+  - mediatek,mt8195-iommu-vdo
+  - mediatek,mt8195-iommu-vpp
 
 then:
   required:
@@ -151,6 +156,8 @@ allOf:
 compatible:
   enum:
 - mediatek,mt8192-m4u
+- mediatek,mt8195-iommu-vdo
+- mediatek,mt8195-iommu-vpp
 
 then:
   required:
diff --git a/include/dt-bindings/memory/mt8195-memory-port.h 
b/include/dt-bindings/memory/mt8195-memory-port.h
new file mode 100644
index ..c10e8b61f1e8
--- /dev/null
+++ b/include/dt-bindings/memory/mt8195-memory-port.h
@@ -0,0 +1,390 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2022 MediaTek Inc.
+ * Author: Yong Wu 
+ */
+#ifndef _DT_BINDINGS_MEMORY_MT8195_LARB_PORT_H_
+#define _DT_BINDINGS_MEMORY_MT8195_LARB_PORT_H_
+
+#include 
+
+/*
+ * MM IOMMU supports 16GB dma address. We separate it to four ranges:
+ * 0 ~ 4G; 4G ~ 8G; 8G ~ 12G; 12G ~ 16G, we could adjust these masters
+ * locate in anyone region. BUT:
+ * a) Make sure all the ports inside a larb are in one range.
+ * b) The iova of any master can NOT cross the 4G/8G/12G boundary.
+ *
+ * This is the suggested mapping in this SoC:
+ *
+ * modulesdma-address-region   larbs-ports
+ * disp 0 ~ 4G  larb0/1/2/3
+ * vcodec  4G ~ 8G  larb19/20/21/22/23/24
+ * cam/mdp 8G ~ 12G the other larbs.
+ * N/A 12G ~ 16G
+ * CCU0   0x24000_ ~ 0x243ff_   larb18: port 0/1
+ * CCU1   0x24400_ ~ 0x247ff_   larb18: port 2/3
+ *
+ * This SoC have two IOMMU HWs, this is the detailed connected information:
+ * iommu-vdo: larb0/2/5/7/9/10/11/13/17/19/21/24/25/28
+ * iommu-vpp: larb1/3/4/6/8/12/14/16/18/20/22/23/26/27
+ */
+
+/* MM IOMMU ports */
+/* larb0 */
+#define M4U_PORT_L0_DISP_RDMA0 MTK_M4U_ID(0, 0)
+#define M4U_PORT_L0_DISP_WDMA0 MTK_M4U_ID(0, 1)
+#define M4U_PORT_L0_DISP_OVL0_RDMA0MTK_M4U_ID(0, 2)
+#define M4U_PORT_L0_DISP_OVL0_RDMA1MTK_M4U_ID(0, 3)
+#define M4U_PORT_L0_DISP_OVL0_HDR  MTK_M4U_ID(0, 4)
+#define M4U_PORT_L0_DISP_FAKE0 MTK_M4U_ID(0, 5)
+
+/* larb1 */
+#define M4U_PORT_L1_DISP_RDMA0 MTK_M4U_ID(1, 0)
+#define M4U_PORT_L1_DISP_WDMA0 MTK_M4U_ID(1, 1)
+#define M4U_PORT_L1_DISP_OVL0_RDMA0MTK_M4U_ID(1, 2)
+#define M4U_PORT_L1_DISP_OVL0_RDMA1MTK_M4U_ID(1, 3)
+#define M4U_PORT_L1_DISP_OVL0_HDR  MTK_M4U_ID(1, 4)
+#define M4U_PORT_L1_DISP_FAKE0 MTK_M4U_ID(1, 

[PATCH v7 00/36] MT8195 and MT8186 IOMMU SUPPORT

2022-05-03 Thread Yong Wu via iommu
This patchset adds MT8195 and MT8186 iommu support.

MT8195 have 3 IOMMU HWs. 2 IOMMU HW is for multimedia, and 1 IOMMU HW is
for infra-master, like PCIe/USB.

About the 2 MM IOMMU HW, something like this:

IOMMU(VDO)  IOMMU(VPP)
   |   |
  SMI_COMMON(VDO)  SMI_COMMON(VPP)
  --- 
  |  |   ...  |  | ...
larb0 larb2  ...larb1 larb3...

these two MM IOMMU HW share a pgtable.

About the INFRA IOMMU, it don't have larbs, the master connects the iommu
directly. It use a independent pgtable.

Also, mt8195 IOMMU bank supports. Normally the IOMMU register size only
is 0x1000. In this IOMMU HW, the register size is 5 * 0x1000. each 0x1000
is a bank. the banks' register look like this:
 
 |bank0  | bank1 | bank2 | bank3 | bank4|
 
 |global |
 |control| null
 |regs   |
 -
 |bank   |bank   |bank   |bank   |bank   |
 |regs   |regs   |regs   |regs   |regs   |
 |   |   |   |   |   |
 -
All the banks share some global control registers, and each bank have its
special bank registers, like pgtable base register, tlb operation registers,
the fault status registers.
 
In mt8195, we enable this bank feature for infra iommu, We put PCIe in bank0
and USB in bank4. they have independent pgtable.

MT8186 is based on MT8195, it just has two patches.

Change note:
v7: 1) Update the changes from Matthias. like add a new function for 
readability.
2) Add mt8186 into this patchset, It may be helpful for maintainer to apply.

v6: 
https://lore.kernel.org/linux-iommu/20220407075726.17771-1-yong...@mediatek.com/
Rebase on v5.18-rc1.

v5: 
https://lore.kernel.org/linux-iommu/20220217113453.13658-1-yong...@mediatek.com
   1) Base on next-20220216
   2) Remove a patch for kmalloc for protect buffer. keep the kzalloc for it.
   3) minor fix from AngeloGioacchino, like rename the error label name
   (data_unlock to err_unlock).
   Note, keep the TODO for component compare_of[26/34].

v4: 
https://lore.kernel.org/linux-iommu/20220125085634.17972-1-yong...@mediatek.com/
   1) Base on v5.16-rc1
   2) Base on tlb logic 2 patchset, some patches in v3 has already gone
   through that patchset.
   3) Due to the unreadable union for v1/v2(comment in 26/33 of v3), I
   separate mtk_iommu_data for v1 and v2 totally, then remove mtk_iommu.h.
   please see patch[26/35][27/35].
   4) add two mutex for the internal data. patch[6/35][7/35].
   5) add a new flag PM_CLK_AO.

v3: 
https://lore.kernel.org/linux-mediatek/20210923115840.17813-1-yong...@mediatek.com/
1) base on v5.15-rc1
2) Adjust devlink with smi-common, not use the property(sub-sommon).
3) Adjust tlb_flush_all flow,
   a) Fix tlb_flush_all only is supported in bank0.
   b) add tlb-flush-all in the resume callback.
   c) remove the pm status checking in tlb-flush-all.
   The reason are showed in the commit message.
4) Allow IOMMU_DOMAIN_UNMANAGED since PCIe VFIO use that.
5) Fix a clk warning and a null abort when unbind the iommu driver.

v2: 
https://lore.kernel.org/linux-mediatek/20210813065324.29220-1-yong...@mediatek.com/
1) Base on v5.14-rc1.
2) Fix build fail for arm32.
3) Fix dt-binding issue from Rob.
4) Fix the bank issue when tlb flush. v1 always use bank->base.
5) adjust devlink with smi-common since the node may be smi-sub-common.
6) other changes: like reword some commit message(removing many
   "This patch..."); seperate serveral patches.

v1: 
https://lore.kernel.org/linux-mediatek/20210630023504.18177-1-yong...@mediatek.com/
Base on v5.13-rc1

Yong Wu (36):
  dt-bindings: mediatek: mt8195: Add binding for MM IOMMU
  dt-bindings: mediatek: mt8195: Add binding for infra IOMMU
  dt-bindings: mediatek: mt8186: Add binding for MM iommu
  iommu/mediatek: Fix 2 HW sharing pgtable issue
  iommu/mediatek: Add list_del in mtk_iommu_remove
  iommu/mediatek: Remove clk_disable in mtk_iommu_remove
  iommu/mediatek: Add mutex for m4u_group and m4u_dom in data
  iommu/mediatek: Add mutex for data in the mtk_iommu_domain
  iommu/mediatek: Adapt sharing and non-sharing pgtable case
  iommu/mediatek: Add 12G~16G support for multi domains
  iommu/mediatek: Add a flag DCM_DISABLE
  iommu/mediatek: Add a flag STD_AXI_MODE
  iommu/mediatek: Remove the granule in the tlb flush
  iommu/mediatek: Always enable output PA over 32bits in isr
  iommu/mediatek: Add SUB_COMMON_3BITS flag
  iommu/mediatek: Add IOMMU_TYPE flag
  iommu/mediatek: Contain MM IOMMU flow with the MM TYPE
  iommu/mediatek: Adjust device link when it is sub-common
  iommu/mediatek: Allow IOMMU_DOMAIN_UNMANAGED for PCIe VFIO
  iommu/mediatek: Add a PM_CLK_AO flag for infra iommu
  iommu/mediatek: Add infra iommu support
  

[PATCH v2 4/4] iommu: dart: Support t6000 variant

2022-05-03 Thread Janne Grunau
From: Sven Peter 

The M1 Pro/Max/Ultra SoCs come with a new variant of DART which
supports a larger physical address space with a different PTE format.
Pass through the correct paddr address space size and the PTE format
to the io-pgtable code which will take care of the rest.

Signed-off-by: Sven Peter 
Co-developed-by: Janne Grunau 
Signed-off-by: Janne Grunau 

---
Changes since v1:
 - use APPLE_DART PTE format for dart-t6000
---
 drivers/iommu/apple-dart.c | 24 +---
 1 file changed, 21 insertions(+), 3 deletions(-)

diff --git a/drivers/iommu/apple-dart.c b/drivers/iommu/apple-dart.c
index decafb07ad08..fe0dedd67fd8 100644
--- a/drivers/iommu/apple-dart.c
+++ b/drivers/iommu/apple-dart.c
@@ -81,10 +81,16 @@
 #define DART_TTBR_VALID BIT(31)
 #define DART_TTBR_SHIFT 12
 
+struct apple_dart_hw {
+   u32 oas;
+   enum io_pgtable_fmt fmt;
+};
+
 /*
  * Private structure associated with each DART device.
  *
  * @dev: device struct
+ * @hw: SoC-specific hardware data
  * @regs: mapped MMIO region
  * @irq: interrupt number, can be shared with other DARTs
  * @clks: clocks associated with this DART
@@ -98,6 +104,7 @@
  */
 struct apple_dart {
struct device *dev;
+   const struct apple_dart_hw *hw;
 
void __iomem *regs;
 
@@ -421,13 +428,13 @@ static int apple_dart_finalize_domain(struct iommu_domain 
*domain,
pgtbl_cfg = (struct io_pgtable_cfg){
.pgsize_bitmap = dart->pgsize,
.ias = 32,
-   .oas = 36,
+   .oas = dart->hw->oas,
.coherent_walk = 1,
.iommu_dev = dart->dev,
};
 
dart_domain->pgtbl_ops =
-   alloc_io_pgtable_ops(APPLE_DART, _cfg, domain);
+   alloc_io_pgtable_ops(dart->hw->fmt, _cfg, domain);
if (!dart_domain->pgtbl_ops) {
ret = -ENOMEM;
goto done;
@@ -857,6 +864,7 @@ static int apple_dart_probe(struct platform_device *pdev)
return -ENOMEM;
 
dart->dev = dev;
+   dart->hw = of_device_get_match_data(dev);
spin_lock_init(>lock);
 
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -946,8 +954,18 @@ static int apple_dart_remove(struct platform_device *pdev)
return 0;
 }
 
+static const struct apple_dart_hw apple_dart_hw_t8103 = {
+   .oas = 36,
+   .fmt = APPLE_DART,
+};
+static const struct apple_dart_hw apple_dart_hw_t6000 = {
+   .oas = 42,
+   .fmt = APPLE_DART2,
+};
+
 static const struct of_device_id apple_dart_of_match[] = {
-   { .compatible = "apple,t8103-dart", .data = NULL },
+   { .compatible = "apple,t8103-dart", .data = _dart_hw_t8103 },
+   { .compatible = "apple,t6000-dart", .data = _dart_hw_t6000 },
{},
 };
 MODULE_DEVICE_TABLE(of, apple_dart_of_match);
-- 
2.35.1

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


[PATCH v2 1/4] dt-bindings: iommu: dart: add t6000 compatible

2022-05-03 Thread Janne Grunau
From: Sven Peter 

The M1 Max/Pro SoCs come with a new DART variant that is incompatible with
the previous one. Add a new compatible for those.

Signed-off-by: Sven Peter 
Acked-by: Rob Herring 

---
v2 changes:
 - added Rob's Acked-by:
---
 Documentation/devicetree/bindings/iommu/apple,dart.yaml | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/iommu/apple,dart.yaml 
b/Documentation/devicetree/bindings/iommu/apple,dart.yaml
index 82ad669feef7..06af2bacbe97 100644
--- a/Documentation/devicetree/bindings/iommu/apple,dart.yaml
+++ b/Documentation/devicetree/bindings/iommu/apple,dart.yaml
@@ -22,7 +22,9 @@ description: |+
 
 properties:
   compatible:
-const: apple,t8103-dart
+enum:
+  - apple,t8103-dart
+  - apple,t6000-dart
 
   reg:
 maxItems: 1
-- 
2.35.1

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


[PATCH v2 0/4] iommu: M1 Pro/Max DART support

2022-05-03 Thread Janne Grunau
Hej,

I've taken over this series to add support for DART on M1 Pro/Max from
Sven.

Since v1 we have discovered further differences in the PTE format. It
has four differences which makes it incompatible with the one in the
M1:

  - the physical addresses are shifted left by 4 bits and and have 2 more
bits inside the PTE entries
  - the read/write protection flags are at a different position
  - the subpage protection feature is now mandatory. For Linux we can
just configure it to always allow access to the entire page.
  - BIT(1) tags "uncached" mappings (used for the display controller)

The last difference is the most troublesome since it makes the PTE format
incomaptible with iopte_type(). Handling this inside io-pgtable-arm.c
seems manageable since DART supports just a single block size. It opens
the question at which point we decide that DART uses its own
io_pgtable_ops.

There is second type of DART (t8110) present on M1 Pro/Max SoCs which
uses the same PTE format as t6000.

Janne

Sven Peter (4):
  dt-bindings: iommu: dart: add t6000 compatible
  iommu/io-pgtable: Add DART subpage protection support
  iommu/io-pgtable: Add DART PTE support for t6000
  iommu: dart: Support t6000 variant

 .../devicetree/bindings/iommu/apple,dart.yaml |  4 +-
 drivers/iommu/apple-dart.c| 24 +-
 drivers/iommu/io-pgtable-arm.c| 76 ++-
 drivers/iommu/io-pgtable.c|  1 +
 include/linux/io-pgtable.h|  3 +
 5 files changed, 101 insertions(+), 7 deletions(-)


base-commit: 3123109284176b1532874591f7c81f3837bbdc17
-- 
2.35.1

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


[PATCH v2 3/4] iommu/io-pgtable: Add DART PTE support for t6000

2022-05-03 Thread Janne Grunau
From: Sven Peter 

The DARTs present in the M1 Pro/Max/Ultra SoC use a diffent PTE format.
They support a 42bit physical address space by shifting the paddr and
extending its mask inside the PTE.
PTE flags are incompatible with iopte_type() since BIT(1) in the PTE
tags "uncached" mappings.
They also come with mandatory sub-page protection now which we just
configure to always allow access to the entire page. This feature is
already present but optional on the previous DARTs which allows to
unconditionally configure it.

Signed-off-by: Sven Peter 
Co-developed-by: Janne Grunau 
Signed-off-by: Janne Grunau 

---
Changes since v1:
 - add APPLE_DART2 PTE format
---
 drivers/iommu/io-pgtable-arm.c | 68 --
 drivers/iommu/io-pgtable.c |  1 +
 include/linux/io-pgtable.h |  3 ++
 3 files changed, 68 insertions(+), 4 deletions(-)

diff --git a/drivers/iommu/io-pgtable-arm.c b/drivers/iommu/io-pgtable-arm.c
index 71570bbc9096..f9121251fb57 100644
--- a/drivers/iommu/io-pgtable-arm.c
+++ b/drivers/iommu/io-pgtable-arm.c
@@ -134,9 +134,20 @@
 #define APPLE_DART_PTE_PROT_NO_WRITE (1<<7)
 #define APPLE_DART_PTE_PROT_NO_READ (1<<8)
 
+#define APPLE_DART_PTE_VALID BIT(0) // identical to ARM_LPAE_PTE_TYPE_BLOCK
+
+#define APPLE_DART2_PTE_PROT_NO_CACHE BIT(1)
+#define APPLE_DART2_PTE_PROT_NO_WRITE BIT(2)
+#define APPLE_DART2_PTE_PROT_NO_READ BIT(3)
+
 #define APPLE_DART_PTE_SUBPAGE_START   GENMASK_ULL(63, 52)
 #define APPLE_DART_PTE_SUBPAGE_END GENMASK_ULL(51, 40)
 
+#define APPLE_DART_PADDR_MASK_PS_36BIT GENMASK_ULL(35, 12)
+#define APPLE_DART_PADDR_SHIFT_PS_36BIT(0)
+#define APPLE_DART_PADDR_MASK_PS_42BIT GENMASK_ULL(37, 10)
+#define APPLE_DART_PADDR_SHIFT_PS_42BIT(4)
+
 /* IOPTE accessors */
 #define iopte_deref(pte,d) __va(iopte_to_paddr(pte, d))
 
@@ -160,6 +171,10 @@ typedef u64 arm_lpae_iopte;
 static inline bool iopte_leaf(arm_lpae_iopte pte, int lvl,
  enum io_pgtable_fmt fmt)
 {
+   if (fmt == APPLE_DART2)
+   return lvl == (ARM_LPAE_MAX_LEVELS - 1) &&
+   FIELD_GET(APPLE_DART_PTE_VALID, pte);
+
if (lvl == (ARM_LPAE_MAX_LEVELS - 1) && fmt != ARM_MALI_LPAE)
return iopte_type(pte) == ARM_LPAE_PTE_TYPE_PAGE;
 
@@ -171,6 +186,13 @@ static arm_lpae_iopte paddr_to_iopte(phys_addr_t paddr,
 {
arm_lpae_iopte pte = paddr;
 
+   if (data->iop.fmt == APPLE_DART || data->iop.fmt == APPLE_DART2) {
+   pte = paddr >> data->iop.cfg.apple_dart_cfg.paddr_shift;
+   pte &= data->iop.cfg.apple_dart_cfg.paddr_mask;
+
+   return pte;
+   }
+
/* Of the bits which overlap, either 51:48 or 15:12 are always RES0 */
return (pte | (pte >> (48 - 12))) & ARM_LPAE_PTE_ADDR_MASK;
 }
@@ -180,6 +202,12 @@ static phys_addr_t iopte_to_paddr(arm_lpae_iopte pte,
 {
u64 paddr = pte & ARM_LPAE_PTE_ADDR_MASK;
 
+   if (data->iop.fmt == APPLE_DART || data->iop.fmt == APPLE_DART2) {
+   paddr = pte & data->iop.cfg.apple_dart_cfg.paddr_mask;
+   paddr <<= data->iop.cfg.apple_dart_cfg.paddr_shift;
+   return paddr;
+   }
+
if (ARM_LPAE_GRANULE(data) < SZ_64K)
return paddr;
 
@@ -272,12 +300,13 @@ static void __arm_lpae_init_pte(struct 
arm_lpae_io_pgtable *data,
size_t sz = ARM_LPAE_BLOCK_SIZE(lvl, data);
int i;
 
-   if (data->iop.fmt != ARM_MALI_LPAE && lvl == ARM_LPAE_MAX_LEVELS - 1)
+   if ((data->iop.fmt != ARM_MALI_LPAE && data->iop.fmt != APPLE_DART2) &&
+   lvl == ARM_LPAE_MAX_LEVELS - 1)
pte |= ARM_LPAE_PTE_TYPE_PAGE;
else
pte |= ARM_LPAE_PTE_TYPE_BLOCK;
 
-   if (data->iop.fmt == APPLE_DART) {
+   if (data->iop.fmt == APPLE_DART || data->iop.fmt == APPLE_DART2) {
/* subpage protection: always allow access to the entire page */
pte |= FIELD_PREP(APPLE_DART_PTE_SUBPAGE_START, 0);
pte |= FIELD_PREP(APPLE_DART_PTE_SUBPAGE_END, 0xfff);
@@ -330,7 +359,18 @@ static arm_lpae_iopte 
arm_lpae_install_table(arm_lpae_iopte *table,
arm_lpae_iopte old, new;
struct io_pgtable_cfg *cfg = >iop.cfg;
 
-   new = paddr_to_iopte(__pa(table), data) | ARM_LPAE_PTE_TYPE_TABLE;
+   new = paddr_to_iopte(__pa(table), data);
+   /*
+* The APPLE_DART2 PTE format is incompatible with ARM_LPAE_PTE_TYPE_*
+* since BIT(1) is used to tag "uncached" mappings.
+* This is the only place where ARM_LPAE_PTE_TYPE_TABLE has to be
+* taken into account since APPLE_DART2 supports only a single block
+* size.
+*/
+   if (data->iop.fmt == APPLE_DART2)
+   new |= APPLE_DART_PTE_VALID;
+   else
+   new |= ARM_LPAE_PTE_TYPE_TABLE;
if (cfg->quirks & IO_PGTABLE_QUIRK_ARM_NS)
new |= ARM_LPAE_PTE_NSTABLE;
 
@@ -424,6 +464,16 @@ static arm_lpae_iopte 

[PATCH v2 2/4] iommu/io-pgtable: Add DART subpage protection support

2022-05-03 Thread Janne Grunau
From: Sven Peter 

DART allows to only expose a subpage to the device. While this is an
optional feature on the M1 DARTs the new ones present on the Pro/Max
models require this field in every PTE.

Signed-off-by: Sven Peter 
---
 drivers/iommu/io-pgtable-arm.c | 10 ++
 1 file changed, 10 insertions(+)

diff --git a/drivers/iommu/io-pgtable-arm.c b/drivers/iommu/io-pgtable-arm.c
index 94ff319ae8ac..71570bbc9096 100644
--- a/drivers/iommu/io-pgtable-arm.c
+++ b/drivers/iommu/io-pgtable-arm.c
@@ -10,6 +10,7 @@
 #define pr_fmt(fmt)"arm-lpae io-pgtable: " fmt
 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -133,6 +134,9 @@
 #define APPLE_DART_PTE_PROT_NO_WRITE (1<<7)
 #define APPLE_DART_PTE_PROT_NO_READ (1<<8)
 
+#define APPLE_DART_PTE_SUBPAGE_START   GENMASK_ULL(63, 52)
+#define APPLE_DART_PTE_SUBPAGE_END GENMASK_ULL(51, 40)
+
 /* IOPTE accessors */
 #define iopte_deref(pte,d) __va(iopte_to_paddr(pte, d))
 
@@ -273,6 +277,12 @@ static void __arm_lpae_init_pte(struct arm_lpae_io_pgtable 
*data,
else
pte |= ARM_LPAE_PTE_TYPE_BLOCK;
 
+   if (data->iop.fmt == APPLE_DART) {
+   /* subpage protection: always allow access to the entire page */
+   pte |= FIELD_PREP(APPLE_DART_PTE_SUBPAGE_START, 0);
+   pte |= FIELD_PREP(APPLE_DART_PTE_SUBPAGE_END, 0xfff);
+   }
+
for (i = 0; i < num_entries; i++)
ptep[i] = pte | paddr_to_iopte(paddr + i * sz, data);
 
-- 
2.35.1

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