Re: [RFC 6/7] iommu/vt-d: convert the intel iommu driver to the dma-iommu ops api

2019-05-04 Thread Lu Baolu

Hi,

On 5/4/19 9:23 PM, Tom Murphy wrote:

static int intel_iommu_add_device(struct device *dev)
  {
+   struct dmar_domain *dmar_domain;
+   struct iommu_domain *domain;
struct intel_iommu *iommu;
struct iommu_group *group;
-   struct iommu_domain *domain;
+   dma_addr_t base;
u8 bus, devfn;
  
  	iommu = device_to_iommu(dev, , );

@@ -4871,9 +4514,12 @@ static int intel_iommu_add_device(struct device *dev)
if (IS_ERR(group))
return PTR_ERR(group);
  
+	base = IOVA_START_PFN << VTD_PAGE_SHIFT;

domain = iommu_get_domain_for_dev(dev);
+   dmar_domain = to_dmar_domain(domain);
if (domain->type == IOMMU_DOMAIN_DMA)
-   dev->dma_ops = _dma_ops;
+   iommu_setup_dma_ops(dev, base,
+   __DOMAIN_MAX_ADDR(dmar_domain->gaw) - base);


I didn't find the implementation of iommu_setup_dma_ops() in this
series. Will the iova resource be initialized in this function?

If so, will this block iommu_group_create_direct_mappings() which
reserves and maps the reserved iova ranges.

  
  	iommu_group_put(group);

return 0;
@@ -5002,19 +4648,6 @@ int intel_iommu_enable_pasid(struct intel_iommu *iommu, 
struct intel_svm_dev *sd
return ret;
  }
  
-static void intel_iommu_apply_resv_region(struct device *dev,

- struct iommu_domain *domain,
- struct iommu_resv_region *region)
-{
-   struct dmar_domain *dmar_domain = to_dmar_domain(domain);
-   unsigned long start, end;
-
-   start = IOVA_PFN(region->start);
-   end   = IOVA_PFN(region->start + region->length - 1);
-
-   WARN_ON_ONCE(!reserve_iova(_domain->iovad, start, end));
-}
-
  struct intel_iommu *intel_svm_device_to_iommu(struct device *dev)
  {
struct intel_iommu *iommu;
@@ -5050,13 +4683,13 @@ const struct iommu_ops intel_iommu_ops = {
.detach_dev = intel_iommu_detach_device,
.map= intel_iommu_map,
.unmap  = intel_iommu_unmap,
+   .flush_iotlb_all= iommu_flush_iova,
.flush_iotlb_range  = intel_iommu_flush_iotlb_range,
.iova_to_phys   = intel_iommu_iova_to_phys,
.add_device = intel_iommu_add_device,
.remove_device  = intel_iommu_remove_device,
.get_resv_regions   = intel_iommu_get_resv_regions,
.put_resv_regions   = intel_iommu_put_resv_regions,
-   .apply_resv_region  = intel_iommu_apply_resv_region,


With this removed, how will iommu_group_create_direct_mappings() work?

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


Re: [RFC 2/7] iommu/vt-d: Remove iova handling code from non-dma ops path

2019-05-04 Thread Lu Baolu

Hi,

On 5/5/19 9:19 AM, Lu Baolu wrote:

Hi,

On 5/4/19 9:23 PM, Tom Murphy via iommu wrote:
@@ -4181,58 +4168,37 @@ static int intel_iommu_memory_notifier(struct 
notifier_block *nb,

 unsigned long val, void *v)
  {
  struct memory_notify *mhp = v;
-    unsigned long long start, end;
-    unsigned long start_vpfn, last_vpfn;
+    unsigned long start_vpfn = mm_to_dma_pfn(mhp->start_pfn);
+    unsigned long last_vpfn = mm_to_dma_pfn(mhp->start_pfn +
+    mhp->nr_pages - 1);
  switch (val) {
  case MEM_GOING_ONLINE:
-    start = mhp->start_pfn << PAGE_SHIFT;
-    end = ((mhp->start_pfn + mhp->nr_pages) << PAGE_SHIFT) - 1;
-    if (iommu_domain_identity_map(si_domain, start, end)) {
-    pr_warn("Failed to build identity map for [%llx-%llx]\n",
-    start, end);
+    if (iommu_domain_identity_map(si_domain, start_vpfn,
+    last_vpfn)) {
+    pr_warn("Failed to build identity map for [%lx-%lx]\n",
+    start_vpfn, last_vpfn);
  return NOTIFY_BAD;
  }
  break;


Actually we don't need to update the si_domain if iommu hardware
supports pass-through mode. This should be made in a separated patch
anyway.


Oh! please ignore it.

This callback is only registered when hardware doesn't support pass
through mode.

if (si_domain && !hw_pass_through)
register_memory_notifier(_iommu_memory_nb);

Best regards,
Lu Baolu

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

Re: [RFC 2/7] iommu/vt-d: Remove iova handling code from non-dma ops path

2019-05-04 Thread Lu Baolu

Hi,

On 5/4/19 9:23 PM, Tom Murphy via iommu wrote:

@@ -4181,58 +4168,37 @@ static int intel_iommu_memory_notifier(struct 
notifier_block *nb,
   unsigned long val, void *v)
  {
struct memory_notify *mhp = v;
-   unsigned long long start, end;
-   unsigned long start_vpfn, last_vpfn;
+   unsigned long start_vpfn = mm_to_dma_pfn(mhp->start_pfn);
+   unsigned long last_vpfn = mm_to_dma_pfn(mhp->start_pfn +
+   mhp->nr_pages - 1);
  
  	switch (val) {

case MEM_GOING_ONLINE:
-   start = mhp->start_pfn << PAGE_SHIFT;
-   end = ((mhp->start_pfn + mhp->nr_pages) << PAGE_SHIFT) - 1;
-   if (iommu_domain_identity_map(si_domain, start, end)) {
-   pr_warn("Failed to build identity map for 
[%llx-%llx]\n",
-   start, end);
+   if (iommu_domain_identity_map(si_domain, start_vpfn,
+   last_vpfn)) {
+   pr_warn("Failed to build identity map for [%lx-%lx]\n",
+   start_vpfn, last_vpfn);
return NOTIFY_BAD;
}
break;


Actually we don't need to update the si_domain if iommu hardware
supports pass-through mode. This should be made in a separated patch
anyway.

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


[RFC 5/7] iommu/dma-iommu: add wrapper for iommu_dma_free_cpu_cached_iovas

2019-05-04 Thread Tom Murphy via iommu
Add a wrapper for iommu_dma_free_cpu_cached_iovas in the dma-iommu api
path to help with the intel-iommu driver conversion to the dma-iommu api
path

Signed-off-by: Tom Murphy 
---
 drivers/iommu/dma-iommu.c | 9 +
 include/linux/dma-iommu.h | 3 +++
 2 files changed, 12 insertions(+)

diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c
index 82ba500886b4..1415b6f068c1 100644
--- a/drivers/iommu/dma-iommu.c
+++ b/drivers/iommu/dma-iommu.c
@@ -49,6 +49,15 @@ struct iommu_dma_cookie {
struct iommu_domain *fq_domain;
 };
 
+void iommu_dma_free_cpu_cached_iovas(unsigned int cpu,
+   struct iommu_domain *domain)
+{
+   struct iommu_dma_cookie *cookie = domain->iova_cookie;
+   struct iova_domain *iovad = >iovad;
+
+   free_cpu_cached_iovas(cpu, iovad);
+}
+
 static void iommu_dma_entry_dtor(unsigned long data)
 {
struct page *freelist = (struct page *)data;
diff --git a/include/linux/dma-iommu.h b/include/linux/dma-iommu.h
index 3fc76918e9bf..1e5bee193feb 100644
--- a/include/linux/dma-iommu.h
+++ b/include/linux/dma-iommu.h
@@ -25,6 +25,9 @@ void iommu_setup_dma_ops(struct device *dev, u64 dma_base, 
u64 size);
 void iommu_dma_map_msi_msg(int irq, struct msi_msg *msg);
 void iommu_dma_get_resv_regions(struct device *dev, struct list_head *list);
 
+void iommu_dma_free_cpu_cached_iovas(unsigned int cpu,
+   struct iommu_domain *domain);
+
 #else /* CONFIG_IOMMU_DMA */
 
 struct iommu_domain;
-- 
2.17.1

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


[RFC 6/7] iommu/vt-d: convert the intel iommu driver to the dma-iommu ops api

2019-05-04 Thread Tom Murphy via iommu
Convert the intel iommu driver to the dma-iommu api to allow us to
remove the iova handling code and the reserved region code

Signed-off-by: Tom Murphy 
---
 drivers/iommu/Kconfig   |   1 +
 drivers/iommu/intel-iommu.c | 405 ++--
 include/linux/intel-iommu.h |   1 -
 3 files changed, 20 insertions(+), 387 deletions(-)

diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index 6f07f3b21816..dfed97f55b6e 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -180,6 +180,7 @@ config INTEL_IOMMU
select IOMMU_IOVA
select NEED_DMA_MAP_STATE
select DMAR_TABLE
+   select IOMMU_DMA
help
  DMA remapping (DMAR) devices support enables independent address
  translations for Direct Memory Access (DMA) from devices.
diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 87622a28b854..980fc4816d72 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -39,6 +39,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -1180,13 +1181,6 @@ static void dma_free_pagelist(struct page *freelist)
}
 }
 
-static void iova_entry_free(unsigned long data)
-{
-   struct page *freelist = (struct page *)data;
-
-   dma_free_pagelist(freelist);
-}
-
 /* iommu handling */
 static int iommu_alloc_root_entry(struct intel_iommu *iommu)
 {
@@ -1530,16 +1524,14 @@ static inline void __mapping_notify_one(struct 
intel_iommu *iommu,
iommu_flush_write_buffer(iommu);
 }
 
-static void iommu_flush_iova(struct iova_domain *iovad)
+static void iommu_flush_iova(struct iommu_domain *domain)
 {
-   struct dmar_domain *domain;
+   struct dmar_domain *dmar_domain = to_dmar_domain(domain);
int idx;
 
-   domain = container_of(iovad, struct dmar_domain, iovad);
-
-   for_each_domain_iommu(idx, domain) {
+   for_each_domain_iommu(idx, dmar_domain) {
struct intel_iommu *iommu = g_iommus[idx];
-   u16 did = domain->iommu_did[iommu->seq_id];
+   u16 did = dmar_domain->iommu_did[iommu->seq_id];
 
iommu->flush.flush_iotlb(iommu, did, 0, 0, DMA_TLB_DSI_FLUSH);
 
@@ -1804,48 +1796,6 @@ static int domain_detach_iommu(struct dmar_domain 
*domain,
return count;
 }
 
-static struct iova_domain reserved_iova_list;
-static struct lock_class_key reserved_rbtree_key;
-
-static int dmar_init_reserved_ranges(void)
-{
-   struct pci_dev *pdev = NULL;
-   struct iova *iova;
-   int i;
-
-   init_iova_domain(_iova_list, VTD_PAGE_SIZE, IOVA_START_PFN);
-
-   lockdep_set_class(_iova_list.iova_rbtree_lock,
-   _rbtree_key);
-
-   /* IOAPIC ranges shouldn't be accessed by DMA */
-   iova = reserve_iova(_iova_list, IOVA_PFN(IOAPIC_RANGE_START),
-   IOVA_PFN(IOAPIC_RANGE_END));
-   if (!iova) {
-   pr_err("Reserve IOAPIC range failed\n");
-   return -ENODEV;
-   }
-
-   /* Reserve all PCI MMIO to avoid peer-to-peer access */
-   for_each_pci_dev(pdev) {
-   struct resource *r;
-
-   for (i = 0; i < PCI_NUM_RESOURCES; i++) {
-   r = >resource[i];
-   if (!r->flags || !(r->flags & IORESOURCE_MEM))
-   continue;
-   iova = reserve_iova(_iova_list,
-   IOVA_PFN(r->start),
-   IOVA_PFN(r->end));
-   if (!iova) {
-   pci_err(pdev, "Reserve iova for %pR failed\n", 
r);
-   return -ENODEV;
-   }
-   }
-   }
-   return 0;
-}
-
 static inline int guestwidth_to_adjustwidth(int gaw)
 {
int agaw;
@@ -1871,7 +1821,7 @@ static void domain_exit(struct dmar_domain *domain)
 
/* destroy iovas */
if (domain->domain.type == IOMMU_DOMAIN_DMA)
-   put_iova_domain(>iovad);
+   iommu_put_dma_cookie(>domain);
 
freelist = domain_unmap(domain, 0, DOMAIN_MAX_PFN(domain->gaw), NULL);
 
@@ -3213,296 +3163,6 @@ static int __init init_dmars(void)
return ret;
 }
 
-/* This takes a number of _MM_ pages, not VTD pages */
-static unsigned long intel_alloc_iova(struct device *dev,
-struct dmar_domain *domain,
-unsigned long nrpages, uint64_t dma_mask)
-{
-   unsigned long iova_pfn;
-
-   /* Restrict dma_mask to the width that the iommu can handle */
-   dma_mask = min_t(uint64_t, DOMAIN_MAX_ADDR(domain->gaw), dma_mask);
-   /* Ensure we reserve the whole size-aligned region */
-   nrpages = __roundup_pow_of_two(nrpages);
-
-   if (!dmar_forcedac && dma_mask > DMA_BIT_MASK(32)) {
-   /*
-* First try to allocate an io virtual address in
-   

[RFC 7/7] iommu/vt-d: Always set DMA_PTE_READ if the iommu doens't support zero length reads

2019-05-04 Thread Tom Murphy via iommu
To match the dma-ops api path the DMA_PTE_READ should be set if ZLR
isn't supported in the iommu

Signed-off-by: Tom Murphy 
---
 drivers/iommu/intel-iommu.c | 13 -
 1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 980fc4816d72..e78b056d 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -4378,6 +4378,17 @@ static void intel_iommu_detach_device(struct 
iommu_domain *domain,
dmar_remove_one_dev_info(dev);
 }
 
+static bool supports_zlr(struct dmar_domain *domain)
+{
+   int i;
+
+   for_each_domain_iommu(i, domain) {
+   if (cap_zlr(g_iommus[i]->cap))
+   return true;
+   }
+   return false;
+}
+
 static int intel_iommu_map(struct iommu_domain *domain,
   unsigned long iova, phys_addr_t hpa,
   size_t size, int iommu_prot)
@@ -4391,7 +4402,7 @@ static int intel_iommu_map(struct iommu_domain *domain,
if (dmar_domain == si_domain && hw_pass_through)
return 0;
 
-   if (iommu_prot & IOMMU_READ)
+   if (iommu_prot & IOMMU_READ || !supports_zlr(dmar_domain))
prot |= DMA_PTE_READ;
if (iommu_prot & IOMMU_WRITE)
prot |= DMA_PTE_WRITE;
-- 
2.17.1

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


[RFC 2/7] iommu/vt-d: Remove iova handling code from non-dma ops path

2019-05-04 Thread Tom Murphy via iommu
There is no reason to keep track of the iovas in the non-dma ops path.
All this code seems to be pointless and can be removed.

Signed-off-by: Tom Murphy 
---
 drivers/iommu/intel-iommu.c | 94 +
 1 file changed, 33 insertions(+), 61 deletions(-)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 2db1dc47e7e4..77895cd89f29 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -1846,11 +1846,6 @@ static int dmar_init_reserved_ranges(void)
return 0;
 }
 
-static void domain_reserve_special_ranges(struct dmar_domain *domain)
-{
-   copy_reserved_iova(_iova_list, >iovad);
-}
-
 static inline int guestwidth_to_adjustwidth(int gaw)
 {
int agaw;
@@ -1875,7 +1870,8 @@ static void domain_exit(struct dmar_domain *domain)
rcu_read_unlock();
 
/* destroy iovas */
-   put_iova_domain(>iovad);
+   if (domain->domain.type == IOMMU_DOMAIN_DMA)
+   put_iova_domain(>iovad);
 
freelist = domain_unmap(domain, 0, DOMAIN_MAX_PFN(domain->gaw));
 
@@ -2554,19 +2550,9 @@ static struct dmar_domain 
*dmar_insert_one_dev_info(struct intel_iommu *iommu,
 }
 
 static int iommu_domain_identity_map(struct dmar_domain *domain,
-unsigned long long start,
-unsigned long long end)
+unsigned long first_vpfn,
+unsigned long last_vpfn)
 {
-   unsigned long first_vpfn = start >> VTD_PAGE_SHIFT;
-   unsigned long last_vpfn = end >> VTD_PAGE_SHIFT;
-
-   if (!reserve_iova(>iovad, dma_to_mm_pfn(first_vpfn),
- dma_to_mm_pfn(last_vpfn))) {
-   pr_err("Reserving iova failed\n");
-   return -ENOMEM;
-   }
-
-   pr_debug("Mapping reserved region %llx-%llx\n", start, end);
/*
 * RMRR range might have overlap with physical memory range,
 * clear it first
@@ -2613,7 +2599,8 @@ static int __init si_domain_init(int hw)
 
for_each_mem_pfn_range(i, nid, _pfn, _pfn, NULL) {
ret = iommu_domain_identity_map(si_domain,
-   PFN_PHYS(start_pfn), PFN_PHYS(end_pfn));
+   mm_to_dma_pfn(start_pfn),
+   mm_to_dma_pfn(end_pfn));
if (ret)
return ret;
}
@@ -4181,58 +4168,37 @@ static int intel_iommu_memory_notifier(struct 
notifier_block *nb,
   unsigned long val, void *v)
 {
struct memory_notify *mhp = v;
-   unsigned long long start, end;
-   unsigned long start_vpfn, last_vpfn;
+   unsigned long start_vpfn = mm_to_dma_pfn(mhp->start_pfn);
+   unsigned long last_vpfn = mm_to_dma_pfn(mhp->start_pfn +
+   mhp->nr_pages - 1);
 
switch (val) {
case MEM_GOING_ONLINE:
-   start = mhp->start_pfn << PAGE_SHIFT;
-   end = ((mhp->start_pfn + mhp->nr_pages) << PAGE_SHIFT) - 1;
-   if (iommu_domain_identity_map(si_domain, start, end)) {
-   pr_warn("Failed to build identity map for 
[%llx-%llx]\n",
-   start, end);
+   if (iommu_domain_identity_map(si_domain, start_vpfn,
+   last_vpfn)) {
+   pr_warn("Failed to build identity map for [%lx-%lx]\n",
+   start_vpfn, last_vpfn);
return NOTIFY_BAD;
}
break;
 
case MEM_OFFLINE:
case MEM_CANCEL_ONLINE:
-   start_vpfn = mm_to_dma_pfn(mhp->start_pfn);
-   last_vpfn = mm_to_dma_pfn(mhp->start_pfn + mhp->nr_pages - 1);
-   while (start_vpfn <= last_vpfn) {
-   struct iova *iova;
+   {
struct dmar_drhd_unit *drhd;
struct intel_iommu *iommu;
struct page *freelist;
 
-   iova = find_iova(_domain->iovad, start_vpfn);
-   if (iova == NULL) {
-   pr_debug("Failed get IOVA for PFN %lx\n",
-start_vpfn);
-   break;
-   }
-
-   iova = split_and_remove_iova(_domain->iovad, iova,
-start_vpfn, last_vpfn);
-   if (iova == NULL) {
-   pr_warn("Failed to split IOVA PFN [%lx-%lx]\n",
-   start_vpfn, last_vpfn);
-   return NOTIFY_BAD;
-   }
-
-   freelist = domain_unmap(si_domain, iova->pfn_lo,
- 

[RFC 4/7] iommu/dma-iommu: Handle freelists in the dma-iommu api path

2019-05-04 Thread Tom Murphy via iommu
Currently the iova flush queue implementation in the dma-iommu api path
doesn't handle freelists. Change the unmap_fast code to allow it to
return any freelists which need to be handled.

Signed-off-by: Tom Murphy 
---
 drivers/iommu/dma-iommu.c   | 39 +++--
 drivers/iommu/iommu.c   | 10 +
 drivers/vfio/vfio_iommu_type1.c |  2 +-
 include/linux/iommu.h   |  3 ++-
 4 files changed, 36 insertions(+), 18 deletions(-)

diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c
index fa5713a4f6f8..82ba500886b4 100644
--- a/drivers/iommu/dma-iommu.c
+++ b/drivers/iommu/dma-iommu.c
@@ -49,6 +49,18 @@ struct iommu_dma_cookie {
struct iommu_domain *fq_domain;
 };
 
+static void iommu_dma_entry_dtor(unsigned long data)
+{
+   struct page *freelist = (struct page *)data;
+
+   while (freelist != NULL) {
+   unsigned long p = (unsigned long)page_address(freelist);
+
+   freelist = freelist->freelist;
+   free_page(p);
+   }
+}
+
 static inline size_t cookie_msi_granule(struct iommu_dma_cookie *cookie)
 {
if (cookie->type == IOMMU_DMA_IOVA_COOKIE)
@@ -313,7 +325,8 @@ static int iommu_dma_init_domain(struct iommu_domain 
*domain, dma_addr_t base,
if (!cookie->fq_domain && !iommu_domain_get_attr(domain,
DOMAIN_ATTR_DMA_USE_FLUSH_QUEUE, ) && attr) {
cookie->fq_domain = domain;
-   init_iova_flush_queue(iovad, iommu_dma_flush_iotlb_all, NULL);
+   init_iova_flush_queue(iovad, iommu_dma_flush_iotlb_all,
+   iommu_dma_entry_dtor);
}
 
if (!dev)
@@ -393,7 +406,7 @@ static dma_addr_t iommu_dma_alloc_iova(struct iommu_domain 
*domain,
 }
 
 static void iommu_dma_free_iova(struct iommu_dma_cookie *cookie,
-   dma_addr_t iova, size_t size)
+   dma_addr_t iova, size_t size, struct page *freelist)
 {
struct iova_domain *iovad = >iovad;
 
@@ -402,7 +415,8 @@ static void iommu_dma_free_iova(struct iommu_dma_cookie 
*cookie,
cookie->msi_iova -= size;
else if (cookie->fq_domain) /* non-strict mode */
queue_iova(iovad, iova_pfn(iovad, iova),
-   size >> iova_shift(iovad), 0);
+   size >> iova_shift(iovad),
+   (unsigned long) freelist);
else
free_iova_fast(iovad, iova_pfn(iovad, iova),
size >> iova_shift(iovad));
@@ -414,14 +428,15 @@ static void __iommu_dma_unmap(struct iommu_domain 
*domain, dma_addr_t dma_addr,
struct iommu_dma_cookie *cookie = domain->iova_cookie;
struct iova_domain *iovad = >iovad;
size_t iova_off = iova_offset(iovad, dma_addr);
+   struct page *freelist;
 
dma_addr -= iova_off;
size = iova_align(iovad, size + iova_off);
 
-   WARN_ON(iommu_unmap_fast(domain, dma_addr, size) != size);
+   WARN_ON(iommu_unmap_fast(domain, dma_addr, size, ) != size);
if (!cookie->fq_domain)
-   iommu_tlb_sync(domain);
-   iommu_dma_free_iova(cookie, dma_addr, size);
+   iommu_flush_iotlb_range(domain, dma_addr, size, freelist);
+   iommu_dma_free_iova(cookie, dma_addr, size, freelist);
 }
 
 static dma_addr_t __iommu_dma_map(struct device *dev, phys_addr_t phys,
@@ -441,7 +456,7 @@ static dma_addr_t __iommu_dma_map(struct device *dev, 
phys_addr_t phys,
return DMA_MAPPING_ERROR;
 
if (iommu_map(domain, iova, phys - iova_off, size, prot)) {
-   iommu_dma_free_iova(cookie, iova, size);
+   iommu_dma_free_iova(cookie, iova, size, NULL);
return DMA_MAPPING_ERROR;
}
return iova + iova_off;
@@ -600,7 +615,7 @@ static void *iommu_dma_alloc_remap(struct device *dev, 
size_t size,
struct iova_domain *iovad = >iovad;
bool coherent = dev_is_dma_coherent(dev);
int ioprot = dma_info_to_prot(DMA_BIDIRECTIONAL, coherent, attrs);
-   pgprot_t prot = arch_dma_mmap_pgprot(dev, PAGE_KERNEL, attrs);
+   pgprot_t prot = pgprot_noncached(PAGE_KERNEL);
unsigned int count, min_size, alloc_sizes = domain->pgsize_bitmap;
struct page **pages;
struct sg_table sgt;
@@ -659,7 +674,7 @@ static void *iommu_dma_alloc_remap(struct device *dev, 
size_t size,
 out_free_sg:
sg_free_table();
 out_free_iova:
-   iommu_dma_free_iova(cookie, iova, size);
+   iommu_dma_free_iova(cookie, iova, size, NULL);
 out_free_pages:
__iommu_dma_free_pages(pages, count);
return NULL;
@@ -668,7 +683,7 @@ static void *iommu_dma_alloc_remap(struct device *dev, 
size_t size,
 static void *iommu_dma_alloc_contiguous_remap(struct device *dev, size_t size,
dma_addr_t *dma_handle, gfp_t gfp, unsigned long attrs)
 {
-   pgprot_t prot = 

[RFC 0/7] Convert the Intel iommu driver to the dma-ops api

2019-05-04 Thread Tom Murphy via iommu
Convert the intel iommu driver to the dma-ops api so that we can remove a bunch 
of repeated code.

This patchset depends on the "iommu/vt-d: Delegate DMA domain to generic iommu" 
and
"iommu/amd: Convert the AMD iommu driver to the dma-iommu api" patch sets which 
haven't
yet merged so this is just a RFC to get some feedback before I do more testing.

Tom Murphy (7):
  iommu/vt-d: Set the dma_ops per device so we can remove the
iommu_no_mapping code
  iommu/vt-d: Remove iova handling code from non-dma ops path
  iommu: improve iommu iotlb flushing
  iommu/dma-iommu: Handle freelists in the dma-iommu api path
  iommu/dma-iommu: add wrapper for iommu_dma_free_cpu_cached_iovas
  iommu/vt-d: convert the intel iommu driver to the dma-iommu ops api
  iommu/vt-d: Always set DMA_PTE_READ if the iommu doens't support zero
length reads

 drivers/iommu/Kconfig   |   1 +
 drivers/iommu/amd_iommu.c   |  14 +-
 drivers/iommu/arm-smmu-v3.c |   3 +-
 drivers/iommu/arm-smmu.c|   2 +-
 drivers/iommu/dma-iommu.c   |  48 ++-
 drivers/iommu/exynos-iommu.c|   3 +-
 drivers/iommu/intel-iommu.c | 605 +---
 drivers/iommu/iommu.c   |  21 +-
 drivers/iommu/ipmmu-vmsa.c  |   2 +-
 drivers/iommu/msm_iommu.c   |   2 +-
 drivers/iommu/mtk_iommu.c   |   3 +-
 drivers/iommu/mtk_iommu_v1.c|   3 +-
 drivers/iommu/omap-iommu.c  |   2 +-
 drivers/iommu/qcom_iommu.c  |   2 +-
 drivers/iommu/rockchip-iommu.c  |   2 +-
 drivers/iommu/s390-iommu.c  |   3 +-
 drivers/iommu/tegra-gart.c  |   2 +-
 drivers/iommu/tegra-smmu.c  |   2 +-
 drivers/vfio/vfio_iommu_type1.c |   3 +-
 include/linux/dma-iommu.h   |   3 +
 include/linux/intel-iommu.h |   1 -
 include/linux/iommu.h   |  24 +-
 22 files changed, 175 insertions(+), 576 deletions(-)

-- 
2.17.1

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


[RFC 1/7] iommu/vt-d: Set the dma_ops per device so we can remove the iommu_no_mapping code

2019-05-04 Thread Tom Murphy via iommu
Set the dma_ops per device so we can remove the iommu_no_mapping code.

Signed-off-by: Tom Murphy 
---
 drivers/iommu/intel-iommu.c | 85 +++--
 1 file changed, 6 insertions(+), 79 deletions(-)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index eace915602f0..2db1dc47e7e4 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -2622,17 +2622,6 @@ static int __init si_domain_init(int hw)
return 0;
 }
 
-static int identity_mapping(struct device *dev)
-{
-   struct device_domain_info *info;
-
-   info = dev->archdata.iommu;
-   if (info && info != DUMMY_DEVICE_DOMAIN_INFO)
-   return (info->domain == si_domain);
-
-   return 0;
-}
-
 static int domain_add_dev_info(struct dmar_domain *domain, struct device *dev)
 {
struct dmar_domain *ndomain;
@@ -3270,43 +3259,6 @@ static unsigned long intel_alloc_iova(struct device *dev,
return iova_pfn;
 }
 
-/* Check if the dev needs to go through non-identity map and unmap process.*/
-static int iommu_no_mapping(struct device *dev)
-{
-   int found;
-
-   if (iommu_dummy(dev))
-   return 1;
-
-   found = identity_mapping(dev);
-   if (found) {
-   /*
-* If the device's dma_mask is less than the system's memory
-* size then this is not a candidate for identity mapping.
-*/
-   u64 dma_mask = *dev->dma_mask;
-
-   if (dev->coherent_dma_mask &&
-   dev->coherent_dma_mask < dma_mask)
-   dma_mask = dev->coherent_dma_mask;
-
-   if (dma_mask < dma_get_required_mask(dev)) {
-   /*
-* 32 bit DMA is removed from si_domain and fall back
-* to non-identity mapping.
-*/
-   dmar_remove_one_dev_info(dev);
-   dev_warn(dev, "32bit DMA uses non-identity mapping\n");
-
-   return 0;
-   }
-
-   return 1;
-   }
-
-   return 0;
-}
-
 static dma_addr_t __intel_map_single(struct device *dev, phys_addr_t paddr,
 size_t size, int dir, u64 dma_mask)
 {
@@ -3320,9 +3272,6 @@ static dma_addr_t __intel_map_single(struct device *dev, 
phys_addr_t paddr,
 
BUG_ON(dir == DMA_NONE);
 
-   if (iommu_no_mapping(dev))
-   return paddr;
-
domain = find_domain(dev);
if (!domain)
return DMA_MAPPING_ERROR;
@@ -3391,9 +3340,6 @@ static void intel_unmap(struct device *dev, dma_addr_t 
dev_addr, size_t size)
struct intel_iommu *iommu;
struct page *freelist;
 
-   if (iommu_no_mapping(dev))
-   return;
-
domain = find_domain(dev);
BUG_ON(!domain);
 
@@ -3442,9 +3388,7 @@ static void *intel_alloc_coherent(struct device *dev, 
size_t size,
size = PAGE_ALIGN(size);
order = get_order(size);
 
-   if (!iommu_no_mapping(dev))
-   flags &= ~(GFP_DMA | GFP_DMA32);
-   else if (dev->coherent_dma_mask < dma_get_required_mask(dev)) {
+   if (dev->coherent_dma_mask < dma_get_required_mask(dev)) {
if (dev->coherent_dma_mask < DMA_BIT_MASK(32))
flags |= GFP_DMA;
else
@@ -3456,11 +3400,6 @@ static void *intel_alloc_coherent(struct device *dev, 
size_t size,
 
page = dma_alloc_from_contiguous(dev, count, order,
 flags & __GFP_NOWARN);
-   if (page && iommu_no_mapping(dev) &&
-   page_to_phys(page) + size > dev->coherent_dma_mask) {
-   dma_release_from_contiguous(dev, page, count);
-   page = NULL;
-   }
}
 
if (!page)
@@ -3510,20 +3449,6 @@ static void intel_unmap_sg(struct device *dev, struct 
scatterlist *sglist,
intel_unmap(dev, startaddr, nrpages << VTD_PAGE_SHIFT);
 }
 
-static int intel_nontranslate_map_sg(struct device *hddev,
-   struct scatterlist *sglist, int nelems, int dir)
-{
-   int i;
-   struct scatterlist *sg;
-
-   for_each_sg(sglist, sg, nelems, i) {
-   BUG_ON(!sg_page(sg));
-   sg->dma_address = sg_phys(sg);
-   sg->dma_length = sg->length;
-   }
-   return nelems;
-}
-
 static int intel_map_sg(struct device *dev, struct scatterlist *sglist, int 
nelems,
enum dma_data_direction dir, unsigned long attrs)
 {
@@ -3538,8 +3463,6 @@ static int intel_map_sg(struct device *dev, struct 
scatterlist *sglist, int nele
struct intel_iommu *iommu;
 
BUG_ON(dir == DMA_NONE);
-   if (iommu_no_mapping(dev))
-   return intel_nontranslate_map_sg(dev, sglist, nelems, dir);
 
domain = find_domain(dev);
if (!domain)
@@ -4570,7 

Re: [PATCH v6 0/1] iommu: enhance IOMMU dma mode build options

2019-05-04 Thread Leizhen (ThunderTown)
Hi all,
  Can anybody review or comment?


On 2019/4/18 21:57, Zhen Lei wrote:
> v5 --> v6:
> 1. give up adding boot option iommu.dma_mode
> 
> v4 --> v5:
> As Hanjun and Thomas Gleixner's suggestion:
> 1. Keep the old ARCH specific boot options no change.
> 2. Keep build option CONFIG_IOMMU_DEFAULT_PASSTHROUGH no change.
> 
> v4:
> As Robin Murphy's suggestion:
> "It's also not necessarily obvious to the user how this interacts with
> IOMMU_DEFAULT_PASSTHROUGH, so if we really do go down this route, maybe it
> would be better to refactor the whole lot into a single selection of something
> like IOMMU_DEFAULT_MODE anyway."
> 
> In this version, I tried to normalize the IOMMU dma mode boot options for all
> ARCHs. When IOMMU is enabled, there are 3 dma modes: paasthrough(bypass),
> lazy(mapping but defer the IOTLB invalidation), strict. But currently each
> ARCHs defined their private boot options, different with each other. For
> example, to enable/disable "passthrough", ARM64 use iommu.passthrough=1/0,
> X86 use iommu=pt/nopt, PPC/POWERNV use iommu=nobypass.
> 
> Zhen Lei (1):
>   iommu: enhance IOMMU dma mode build options
> 
>  arch/ia64/kernel/pci-dma.c|  2 +-
>  arch/powerpc/platforms/powernv/pci-ioda.c |  3 ++-
>  arch/s390/pci/pci_dma.c   |  2 +-
>  arch/x86/kernel/pci-dma.c |  7 ++---
>  drivers/iommu/Kconfig | 44 
> ++-
>  drivers/iommu/amd_iommu_init.c|  3 ++-
>  drivers/iommu/intel-iommu.c   |  2 +-
>  drivers/iommu/iommu.c |  3 ++-
>  8 files changed, 48 insertions(+), 18 deletions(-)
> 

-- 
Thanks!
BestRegards

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