RE: [PATCH 5/6] dma-mapping: support fsl-mc bus

2018-03-05 Thread Nipun Gupta


> From: Robin Murphy [mailto:robin.mur...@arm.com]
> Sent: Tuesday, March 06, 2018 0:22
> 
> On 05/03/18 18:39, Christoph Hellwig wrote:
> > On Mon, Mar 05, 2018 at 03:48:32PM +, Robin Murphy wrote:
> >> Unfortunately for us, fsl-mc is conceptually rather like PCI in that it's
> >> software-discoverable and the only thing described in DT is the bus "host",
> >> thus we need the same sort of thing as for PCI to map from the child
> >> devices back to the bus root in order to find the appropriate firmware
> >> node. Worse than PCI, though, we wouldn't even have the option of
> >> describing child devices statically in firmware at all, since it's actually
> >> one of these runtime-configurable "build your own network accelerator"
> >> hardware pools where userspace gets to create and destroy "devices" as it
> >> likes.
> >
> > I really hate the PCI special case just as much.  Maybe we just
> > need a dma_configure method on the bus, and move PCI as well as fsl-mc
> > to it.
> 
> Hmm, on reflection, 100% ack to that idea. It would neatly supersede
> bus->force_dma *and* mean that we don't have to effectively pull pci.h
> into everything, which I've never liked. In hindsight dma_configure()
> does feel like it's grown into this odd choke point where we munge
> everything in just for it to awkwardly unpick things again.
> 
> Robin.

+1 to the idea.

Sorry for asking a trivial question - looking into dma_configure() I see that
PCI is used in the start and the end of the API.
In the end part pci_put_host_bridge_device() is called.
So are two bus callbacks something like 'dma_config_start' & 'dma_config_end'
will be required where the former one will return "dma_dev"?

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


[PATCH v7 13/14] iommu/rockchip: Add runtime PM support

2018-03-05 Thread Jeffy Chen
When the power domain is powered off, the IOMMU cannot be accessed and
register programming must be deferred until the power domain becomes
enabled.

Add runtime PM support, and use runtime PM device link from IOMMU to
master to startup and shutdown IOMMU.

Signed-off-by: Jeffy Chen 
---

Changes in v7:
Add WARN_ON in irq isr, and modify iommu archdata comment.

Changes in v6: None
Changes in v5:
Avoid race about pm_runtime_get_if_in_use() and pm_runtime_enabled().

Changes in v4: None
Changes in v3:
Only call startup() and shutdown() when iommu attached.
Remove pm_mutex.
Check runtime PM disabled.
Check pm_runtime in rk_iommu_irq().

Changes in v2: None

 drivers/iommu/rockchip-iommu.c | 189 -
 1 file changed, 148 insertions(+), 41 deletions(-)

diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c
index 2448a0528e39..db08978203f7 100644
--- a/drivers/iommu/rockchip-iommu.c
+++ b/drivers/iommu/rockchip-iommu.c
@@ -22,6 +22,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 
@@ -105,7 +106,14 @@ struct rk_iommu {
struct iommu_domain *domain; /* domain to which iommu is attached */
 };
 
+/**
+ * struct rk_iommudata - iommu archdata of master device.
+ * @link:  device link with runtime PM integration from the master
+ * (consumer) to the IOMMU (supplier).
+ * @iommu: IOMMU of the master device.
+ */
 struct rk_iommudata {
+   struct device_link *link;
struct rk_iommu *iommu;
 };
 
@@ -518,7 +526,13 @@ static irqreturn_t rk_iommu_irq(int irq, void *dev_id)
u32 int_status;
dma_addr_t iova;
irqreturn_t ret = IRQ_NONE;
-   int i;
+   bool need_runtime_put;
+   int i, err;
+
+   err = pm_runtime_get_if_in_use(iommu->dev);
+   if (WARN_ON(err <= 0 && err != -EINVAL))
+   return ret;
+   need_runtime_put = err > 0;
 
WARN_ON(clk_bulk_enable(iommu->num_clocks, iommu->clocks));
 
@@ -570,6 +584,9 @@ static irqreturn_t rk_iommu_irq(int irq, void *dev_id)
 
clk_bulk_disable(iommu->num_clocks, iommu->clocks);
 
+   if (need_runtime_put)
+   pm_runtime_put(iommu->dev);
+
return ret;
 }
 
@@ -611,10 +628,20 @@ static void rk_iommu_zap_iova(struct rk_iommu_domain 
*rk_domain,
spin_lock_irqsave(_domain->iommus_lock, flags);
list_for_each(pos, _domain->iommus) {
struct rk_iommu *iommu;
+   int ret;
+
iommu = list_entry(pos, struct rk_iommu, node);
-   WARN_ON(clk_bulk_enable(iommu->num_clocks, iommu->clocks));
-   rk_iommu_zap_lines(iommu, iova, size);
-   clk_bulk_disable(iommu->num_clocks, iommu->clocks);
+
+   /* Only zap TLBs of IOMMUs that are powered on. */
+   ret = pm_runtime_get_if_in_use(iommu->dev);
+   if (ret > 0 || ret == -EINVAL) {
+   WARN_ON(clk_bulk_enable(iommu->num_clocks,
+   iommu->clocks));
+   rk_iommu_zap_lines(iommu, iova, size);
+   clk_bulk_disable(iommu->num_clocks, iommu->clocks);
+   }
+   if (ret > 0)
+   pm_runtime_put(iommu->dev);
}
spin_unlock_irqrestore(_domain->iommus_lock, flags);
 }
@@ -817,22 +844,30 @@ static struct rk_iommu *rk_iommu_from_dev(struct device 
*dev)
return data ? data->iommu : NULL;
 }
 
-static int rk_iommu_attach_device(struct iommu_domain *domain,
- struct device *dev)
+/* Must be called with iommu powered on and attached */
+static void rk_iommu_shutdown(struct rk_iommu *iommu)
 {
-   struct rk_iommu *iommu;
+   int i;
+
+   /* Ignore error while disabling, just keep going */
+   WARN_ON(clk_bulk_enable(iommu->num_clocks, iommu->clocks));
+   rk_iommu_enable_stall(iommu);
+   rk_iommu_disable_paging(iommu);
+   for (i = 0; i < iommu->num_mmu; i++) {
+   rk_iommu_write(iommu->bases[i], RK_MMU_INT_MASK, 0);
+   rk_iommu_write(iommu->bases[i], RK_MMU_DTE_ADDR, 0);
+   }
+   rk_iommu_disable_stall(iommu);
+   clk_bulk_disable(iommu->num_clocks, iommu->clocks);
+}
+
+/* Must be called with iommu powered on and attached */
+static int rk_iommu_startup(struct rk_iommu *iommu)
+{
+   struct iommu_domain *domain = iommu->domain;
struct rk_iommu_domain *rk_domain = to_rk_domain(domain);
-   unsigned long flags;
int ret, i;
 
-   /*
-* Allow 'virtual devices' (e.g., drm) to attach to domain.
-* Such a device does not belong to an iommu group.
-*/
-   iommu = rk_iommu_from_dev(dev);
-   if (!iommu)
-   return 0;
-
ret = clk_bulk_enable(iommu->num_clocks, iommu->clocks);
if (ret)
return ret;
@@ -845,8 +880,6 @@ static int 

[PATCH v7 12/14] iommu/rockchip: Fix error handling in init

2018-03-05 Thread Jeffy Chen
It's hard to undo bus_set_iommu() in the error path, so move it to the
end of rk_iommu_probe().

Signed-off-by: Jeffy Chen 
Reviewed-by: Tomasz Figa 
Reviewed-by: Robin Murphy 
---

Changes in v7: None
Changes in v6: None
Changes in v5: None
Changes in v4: None
Changes in v3: None
Changes in v2:
Move bus_set_iommu() to rk_iommu_probe().

 drivers/iommu/rockchip-iommu.c | 15 ++-
 1 file changed, 2 insertions(+), 13 deletions(-)

diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c
index 1346bbb8a3e7..2448a0528e39 100644
--- a/drivers/iommu/rockchip-iommu.c
+++ b/drivers/iommu/rockchip-iommu.c
@@ -1133,6 +1133,8 @@ static int rk_iommu_probe(struct platform_device *pdev)
if (!dma_dev)
dma_dev = >dev;
 
+   bus_set_iommu(_bus_type, _iommu_ops);
+
return 0;
 err_remove_sysfs:
iommu_device_sysfs_remove(>iommu);
@@ -1158,19 +1160,6 @@ static struct platform_driver rk_iommu_driver = {
 
 static int __init rk_iommu_init(void)
 {
-   struct device_node *np;
-   int ret;
-
-   np = of_find_matching_node(NULL, rk_iommu_dt_ids);
-   if (!np)
-   return 0;
-
-   of_node_put(np);
-
-   ret = bus_set_iommu(_bus_type, _iommu_ops);
-   if (ret)
-   return ret;
-
return platform_driver_register(_iommu_driver);
 }
 subsys_initcall(rk_iommu_init);
-- 
2.11.0


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


[PATCH v7 11/14] iommu/rockchip: Use OF_IOMMU to attach devices automatically

2018-03-05 Thread Jeffy Chen
Converts the rockchip-iommu driver to use the OF_IOMMU infrastructure,
which allows attaching master devices to their IOMMUs automatically
according to DT properties.

Signed-off-by: Jeffy Chen 
Reviewed-by: Robin Murphy 
---

Changes in v7: None
Changes in v6: None
Changes in v5: None
Changes in v4: None
Changes in v3:
Add struct rk_iommudata.
Squash iommu/rockchip: Use iommu_group_get_for_dev() for add_device

Changes in v2: None

 drivers/iommu/rockchip-iommu.c | 135 -
 1 file changed, 40 insertions(+), 95 deletions(-)

diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c
index 6789e11b7087..1346bbb8a3e7 100644
--- a/drivers/iommu/rockchip-iommu.c
+++ b/drivers/iommu/rockchip-iommu.c
@@ -19,6 +19,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -104,6 +105,10 @@ struct rk_iommu {
struct iommu_domain *domain; /* domain to which iommu is attached */
 };
 
+struct rk_iommudata {
+   struct rk_iommu *iommu;
+};
+
 static struct device *dma_dev;
 
 static inline void rk_table_flush(struct rk_iommu_domain *dom, dma_addr_t dma,
@@ -807,18 +812,9 @@ static size_t rk_iommu_unmap(struct iommu_domain *domain, 
unsigned long _iova,
 
 static struct rk_iommu *rk_iommu_from_dev(struct device *dev)
 {
-   struct iommu_group *group;
-   struct device *iommu_dev;
-   struct rk_iommu *rk_iommu;
+   struct rk_iommudata *data = dev->archdata.iommu;
 
-   group = iommu_group_get(dev);
-   if (!group)
-   return NULL;
-   iommu_dev = iommu_group_get_iommudata(group);
-   rk_iommu = dev_get_drvdata(iommu_dev);
-   iommu_group_put(group);
-
-   return rk_iommu;
+   return data ? data->iommu : NULL;
 }
 
 static int rk_iommu_attach_device(struct iommu_domain *domain,
@@ -989,110 +985,53 @@ static void rk_iommu_domain_free(struct iommu_domain 
*domain)
iommu_put_dma_cookie(_domain->domain);
 }
 
-static bool rk_iommu_is_dev_iommu_master(struct device *dev)
-{
-   struct device_node *np = dev->of_node;
-   int ret;
-
-   /*
-* An iommu master has an iommus property containing a list of phandles
-* to iommu nodes, each with an #iommu-cells property with value 0.
-*/
-   ret = of_count_phandle_with_args(np, "iommus", "#iommu-cells");
-   return (ret > 0);
-}
-
-static int rk_iommu_group_set_iommudata(struct iommu_group *group,
-   struct device *dev)
+static int rk_iommu_add_device(struct device *dev)
 {
-   struct device_node *np = dev->of_node;
-   struct platform_device *pd;
-   int ret;
-   struct of_phandle_args args;
+   struct iommu_group *group;
+   struct rk_iommu *iommu;
 
-   /*
-* An iommu master has an iommus property containing a list of phandles
-* to iommu nodes, each with an #iommu-cells property with value 0.
-*/
-   ret = of_parse_phandle_with_args(np, "iommus", "#iommu-cells", 0,
-);
-   if (ret) {
-   dev_err(dev, "of_parse_phandle_with_args(%pOF) => %d\n",
-   np, ret);
-   return ret;
-   }
-   if (args.args_count != 0) {
-   dev_err(dev, "incorrect number of iommu params found for %pOF 
(found %d, expected 0)\n",
-   args.np, args.args_count);
-   return -EINVAL;
-   }
+   iommu = rk_iommu_from_dev(dev);
+   if (!iommu)
+   return -ENODEV;
 
-   pd = of_find_device_by_node(args.np);
-   of_node_put(args.np);
-   if (!pd) {
-   dev_err(dev, "iommu %pOF not found\n", args.np);
-   return -EPROBE_DEFER;
-   }
+   group = iommu_group_get_for_dev(dev);
+   if (IS_ERR(group))
+   return PTR_ERR(group);
+   iommu_group_put(group);
 
-   /* TODO(djkurtz): handle multiple slave iommus for a single master */
-   iommu_group_set_iommudata(group, >dev, NULL);
+   iommu_device_link(>iommu, dev);
 
return 0;
 }
 
-static int rk_iommu_add_device(struct device *dev)
+static void rk_iommu_remove_device(struct device *dev)
 {
-   struct iommu_group *group;
struct rk_iommu *iommu;
-   int ret;
-
-   if (!rk_iommu_is_dev_iommu_master(dev))
-   return -ENODEV;
-
-   group = iommu_group_get(dev);
-   if (!group) {
-   group = iommu_group_alloc();
-   if (IS_ERR(group)) {
-   dev_err(dev, "Failed to allocate IOMMU group\n");
-   return PTR_ERR(group);
-   }
-   }
-
-   ret = iommu_group_add_device(group, dev);
-   if (ret)
-   goto err_put_group;
-
-   ret = rk_iommu_group_set_iommudata(group, dev);
-   if (ret)
-   goto err_remove_device;
 
iommu = 

[PATCH v7 14/14] iommu/rockchip: Support sharing IOMMU between masters

2018-03-05 Thread Jeffy Chen
There would be some masters sharing the same IOMMU device. Put them in
the same iommu group and share the same iommu domain.

Signed-off-by: Jeffy Chen 
Reviewed-by: Robin Murphy 
---

Changes in v7:
Use iommu_group_ref_get to avoid ref leak

Changes in v6: None
Changes in v5: None
Changes in v4: None
Changes in v3:
Remove rk_iommudata->domain.

Changes in v2: None

 drivers/iommu/rockchip-iommu.c | 22 --
 1 file changed, 20 insertions(+), 2 deletions(-)

diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c
index db08978203f7..6a1c7efa7c17 100644
--- a/drivers/iommu/rockchip-iommu.c
+++ b/drivers/iommu/rockchip-iommu.c
@@ -104,6 +104,7 @@ struct rk_iommu {
struct iommu_device iommu;
struct list_head node; /* entry in rk_iommu_domain.iommus */
struct iommu_domain *domain; /* domain to which iommu is attached */
+   struct iommu_group *group;
 };
 
 /**
@@ -1091,6 +1092,15 @@ static void rk_iommu_remove_device(struct device *dev)
iommu_group_remove_device(dev);
 }
 
+static struct iommu_group *rk_iommu_device_group(struct device *dev)
+{
+   struct rk_iommu *iommu;
+
+   iommu = rk_iommu_from_dev(dev);
+
+   return iommu_group_ref_get(iommu->group);
+}
+
 static int rk_iommu_of_xlate(struct device *dev,
 struct of_phandle_args *args)
 {
@@ -1122,7 +1132,7 @@ static const struct iommu_ops rk_iommu_ops = {
.add_device = rk_iommu_add_device,
.remove_device = rk_iommu_remove_device,
.iova_to_phys = rk_iommu_iova_to_phys,
-   .device_group = generic_device_group,
+   .device_group = rk_iommu_device_group,
.pgsize_bitmap = RK_IOMMU_PGSIZE_BITMAP,
.of_xlate = rk_iommu_of_xlate,
 };
@@ -1191,9 +1201,15 @@ static int rk_iommu_probe(struct platform_device *pdev)
if (err)
return err;
 
+   iommu->group = iommu_group_alloc();
+   if (IS_ERR(iommu->group)) {
+   err = PTR_ERR(iommu->group);
+   goto err_unprepare_clocks;
+   }
+
err = iommu_device_sysfs_add(>iommu, dev, NULL, dev_name(dev));
if (err)
-   goto err_unprepare_clocks;
+   goto err_put_group;
 
iommu_device_set_ops(>iommu, _iommu_ops);
iommu_device_set_fwnode(>iommu, >of_node->fwnode);
@@ -1217,6 +1233,8 @@ static int rk_iommu_probe(struct platform_device *pdev)
return 0;
 err_remove_sysfs:
iommu_device_sysfs_remove(>iommu);
+err_put_group:
+   iommu_group_put(iommu->group);
 err_unprepare_clocks:
clk_bulk_unprepare(iommu->num_clocks, iommu->clocks);
return err;
-- 
2.11.0


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


[PATCH v7 10/14] iommu/rockchip: Use IOMMU device for dma mapping operations

2018-03-05 Thread Jeffy Chen
Use the first registered IOMMU device for dma mapping operations, and
drop the domain platform device.

This is similar to exynos iommu driver.

Signed-off-by: Jeffy Chen 
Reviewed-by: Tomasz Figa 
Reviewed-by: Robin Murphy 
---

Changes in v7: None
Changes in v6: None
Changes in v5: None
Changes in v4: None
Changes in v3: None
Changes in v2: None

 drivers/iommu/rockchip-iommu.c | 85 --
 1 file changed, 24 insertions(+), 61 deletions(-)

diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c
index 6c6275589bd5..6789e11b7087 100644
--- a/drivers/iommu/rockchip-iommu.c
+++ b/drivers/iommu/rockchip-iommu.c
@@ -79,7 +79,6 @@
 
 struct rk_iommu_domain {
struct list_head iommus;
-   struct platform_device *pdev;
u32 *dt; /* page directory table */
dma_addr_t dt_dma;
spinlock_t iommus_lock; /* lock for iommus list */
@@ -105,12 +104,14 @@ struct rk_iommu {
struct iommu_domain *domain; /* domain to which iommu is attached */
 };
 
+static struct device *dma_dev;
+
 static inline void rk_table_flush(struct rk_iommu_domain *dom, dma_addr_t dma,
  unsigned int count)
 {
size_t size = count * sizeof(u32); /* count of u32 entry */
 
-   dma_sync_single_for_device(>pdev->dev, dma, size, DMA_TO_DEVICE);
+   dma_sync_single_for_device(dma_dev, dma, size, DMA_TO_DEVICE);
 }
 
 static struct rk_iommu_domain *to_rk_domain(struct iommu_domain *dom)
@@ -625,7 +626,6 @@ static void rk_iommu_zap_iova_first_last(struct 
rk_iommu_domain *rk_domain,
 static u32 *rk_dte_get_page_table(struct rk_iommu_domain *rk_domain,
  dma_addr_t iova)
 {
-   struct device *dev = _domain->pdev->dev;
u32 *page_table, *dte_addr;
u32 dte_index, dte;
phys_addr_t pt_phys;
@@ -643,9 +643,9 @@ static u32 *rk_dte_get_page_table(struct rk_iommu_domain 
*rk_domain,
if (!page_table)
return ERR_PTR(-ENOMEM);
 
-   pt_dma = dma_map_single(dev, page_table, SPAGE_SIZE, DMA_TO_DEVICE);
-   if (dma_mapping_error(dev, pt_dma)) {
-   dev_err(dev, "DMA mapping error while allocating page table\n");
+   pt_dma = dma_map_single(dma_dev, page_table, SPAGE_SIZE, DMA_TO_DEVICE);
+   if (dma_mapping_error(dma_dev, pt_dma)) {
+   dev_err(dma_dev, "DMA mapping error while allocating page 
table\n");
free_page((unsigned long)page_table);
return ERR_PTR(-ENOMEM);
}
@@ -911,29 +911,20 @@ static void rk_iommu_detach_device(struct iommu_domain 
*domain,
 static struct iommu_domain *rk_iommu_domain_alloc(unsigned type)
 {
struct rk_iommu_domain *rk_domain;
-   struct platform_device *pdev;
-   struct device *iommu_dev;
 
if (type != IOMMU_DOMAIN_UNMANAGED && type != IOMMU_DOMAIN_DMA)
return NULL;
 
-   /* Register a pdev per domain, so DMA API can base on this *dev
-* even some virtual master doesn't have an iommu slave
-*/
-   pdev = platform_device_register_simple("rk_iommu_domain",
-  PLATFORM_DEVID_AUTO, NULL, 0);
-   if (IS_ERR(pdev))
+   if (!dma_dev)
return NULL;
 
-   rk_domain = devm_kzalloc(>dev, sizeof(*rk_domain), GFP_KERNEL);
+   rk_domain = devm_kzalloc(dma_dev, sizeof(*rk_domain), GFP_KERNEL);
if (!rk_domain)
-   goto err_unreg_pdev;
-
-   rk_domain->pdev = pdev;
+   return NULL;
 
if (type == IOMMU_DOMAIN_DMA &&
iommu_get_dma_cookie(_domain->domain))
-   goto err_unreg_pdev;
+   return NULL;
 
/*
 * rk32xx iommus use a 2 level pagetable.
@@ -944,11 +935,10 @@ static struct iommu_domain 
*rk_iommu_domain_alloc(unsigned type)
if (!rk_domain->dt)
goto err_put_cookie;
 
-   iommu_dev = >dev;
-   rk_domain->dt_dma = dma_map_single(iommu_dev, rk_domain->dt,
+   rk_domain->dt_dma = dma_map_single(dma_dev, rk_domain->dt,
   SPAGE_SIZE, DMA_TO_DEVICE);
-   if (dma_mapping_error(iommu_dev, rk_domain->dt_dma)) {
-   dev_err(iommu_dev, "DMA map error for DT\n");
+   if (dma_mapping_error(dma_dev, rk_domain->dt_dma)) {
+   dev_err(dma_dev, "DMA map error for DT\n");
goto err_free_dt;
}
 
@@ -969,8 +959,6 @@ static struct iommu_domain *rk_iommu_domain_alloc(unsigned 
type)
 err_put_cookie:
if (type == IOMMU_DOMAIN_DMA)
iommu_put_dma_cookie(_domain->domain);
-err_unreg_pdev:
-   platform_device_unregister(pdev);
 
return NULL;
 }
@@ -987,20 +975,18 @@ static void rk_iommu_domain_free(struct iommu_domain 
*domain)
if (rk_dte_is_pt_valid(dte)) {
phys_addr_t pt_phys 

[PATCH v7 09/14] dt-bindings: iommu/rockchip: Add clock property

2018-03-05 Thread Jeffy Chen
Add clock property, since we are going to control clocks in rockchip
iommu driver.

Signed-off-by: Jeffy Chen 
Reviewed-by: Rob Herring 
---

Changes in v7: None
Changes in v6:
Fix dt-binding as Robin suggested.
Use aclk and iface clk as Rob and Robin suggested, and split binding
patch.

Changes in v5: None
Changes in v4: None
Changes in v3: None
Changes in v2: None

 Documentation/devicetree/bindings/iommu/rockchip,iommu.txt | 7 +++
 1 file changed, 7 insertions(+)

diff --git a/Documentation/devicetree/bindings/iommu/rockchip,iommu.txt 
b/Documentation/devicetree/bindings/iommu/rockchip,iommu.txt
index 2098f7732264..6ecefea1c6f9 100644
--- a/Documentation/devicetree/bindings/iommu/rockchip,iommu.txt
+++ b/Documentation/devicetree/bindings/iommu/rockchip,iommu.txt
@@ -14,6 +14,11 @@ Required properties:
 "single-master" device, and needs no additional information
 to associate with its master device.  See:
 Documentation/devicetree/bindings/iommu/iommu.txt
+- clocks  : A list of clocks required for the IOMMU to be accessible by
+the host CPU.
+- clock-names : Should contain the following:
+   "iface" - Main peripheral bus clock (PCLK/HCL) (required)
+   "aclk"  - AXI bus clock (required)
 
 Optional properties:
 - rockchip,disable-mmu-reset : Don't use the mmu reset operation.
@@ -27,5 +32,7 @@ Example:
reg = <0xff940300 0x100>;
interrupts = ;
interrupt-names = "vopl_mmu";
+   clocks = < ACLK_VOP1>, < HCLK_VOP1>;
+   clock-names = "aclk", "iface";
#iommu-cells = <0>;
};
-- 
2.11.0


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


[PATCH v7 08/14] iommu/rockchip: Control clocks needed to access the IOMMU

2018-03-05 Thread Jeffy Chen
From: Tomasz Figa 

Current code relies on master driver enabling necessary clocks before
IOMMU is accessed, however there are cases when the IOMMU should be
accessed while the master is not running yet, for example allocating
V4L2 videobuf2 buffers, which is done by the VB2 framework using DMA
mapping API and doesn't engage the master driver at all.

This patch fixes the problem by letting clocks needed for IOMMU
operation to be listed in Device Tree and making the driver enable them
for the time of accessing the hardware.

Signed-off-by: Jeffy Chen 
Signed-off-by: Tomasz Figa 
Acked-by: Robin Murphy 
---

Changes in v7: None
Changes in v6:
Fix dt-binding as Robin suggested.
Use aclk and iface clk as Rob and Robin suggested, and split binding
patch.

Changes in v5:
Use clk_bulk APIs.

Changes in v4: None
Changes in v3: None
Changes in v2: None

 drivers/iommu/rockchip-iommu.c | 54 +-
 1 file changed, 48 insertions(+), 6 deletions(-)

diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c
index c4131ca792e0..6c6275589bd5 100644
--- a/drivers/iommu/rockchip-iommu.c
+++ b/drivers/iommu/rockchip-iommu.c
@@ -4,6 +4,7 @@
  * published by the Free Software Foundation.
  */
 
+#include 
 #include 
 #include 
 #include 
@@ -87,10 +88,17 @@ struct rk_iommu_domain {
struct iommu_domain domain;
 };
 
+/* list of clocks required by IOMMU */
+static const char * const rk_iommu_clocks[] = {
+   "aclk", "iface",
+};
+
 struct rk_iommu {
struct device *dev;
void __iomem **bases;
int num_mmu;
+   struct clk_bulk_data *clocks;
+   int num_clocks;
bool reset_disabled;
struct iommu_device iommu;
struct list_head node; /* entry in rk_iommu_domain.iommus */
@@ -506,6 +514,8 @@ static irqreturn_t rk_iommu_irq(int irq, void *dev_id)
irqreturn_t ret = IRQ_NONE;
int i;
 
+   WARN_ON(clk_bulk_enable(iommu->num_clocks, iommu->clocks));
+
for (i = 0; i < iommu->num_mmu; i++) {
int_status = rk_iommu_read(iommu->bases[i], RK_MMU_INT_STATUS);
if (int_status == 0)
@@ -552,6 +562,8 @@ static irqreturn_t rk_iommu_irq(int irq, void *dev_id)
rk_iommu_write(iommu->bases[i], RK_MMU_INT_CLEAR, int_status);
}
 
+   clk_bulk_disable(iommu->num_clocks, iommu->clocks);
+
return ret;
 }
 
@@ -594,7 +606,9 @@ static void rk_iommu_zap_iova(struct rk_iommu_domain 
*rk_domain,
list_for_each(pos, _domain->iommus) {
struct rk_iommu *iommu;
iommu = list_entry(pos, struct rk_iommu, node);
+   WARN_ON(clk_bulk_enable(iommu->num_clocks, iommu->clocks));
rk_iommu_zap_lines(iommu, iova, size);
+   clk_bulk_disable(iommu->num_clocks, iommu->clocks);
}
spin_unlock_irqrestore(_domain->iommus_lock, flags);
 }
@@ -823,10 +837,14 @@ static int rk_iommu_attach_device(struct iommu_domain 
*domain,
if (!iommu)
return 0;
 
-   ret = rk_iommu_enable_stall(iommu);
+   ret = clk_bulk_enable(iommu->num_clocks, iommu->clocks);
if (ret)
return ret;
 
+   ret = rk_iommu_enable_stall(iommu);
+   if (ret)
+   goto out_disable_clocks;
+
ret = rk_iommu_force_reset(iommu);
if (ret)
goto out_disable_stall;
@@ -852,6 +870,8 @@ static int rk_iommu_attach_device(struct iommu_domain 
*domain,
 
 out_disable_stall:
rk_iommu_disable_stall(iommu);
+out_disable_clocks:
+   clk_bulk_disable(iommu->num_clocks, iommu->clocks);
return ret;
 }
 
@@ -873,6 +893,7 @@ static void rk_iommu_detach_device(struct iommu_domain 
*domain,
spin_unlock_irqrestore(_domain->iommus_lock, flags);
 
/* Ignore error while disabling, just keep going */
+   WARN_ON(clk_bulk_enable(iommu->num_clocks, iommu->clocks));
rk_iommu_enable_stall(iommu);
rk_iommu_disable_paging(iommu);
for (i = 0; i < iommu->num_mmu; i++) {
@@ -880,6 +901,7 @@ static void rk_iommu_detach_device(struct iommu_domain 
*domain,
rk_iommu_write(iommu->bases[i], RK_MMU_DTE_ADDR, 0);
}
rk_iommu_disable_stall(iommu);
+   clk_bulk_disable(iommu->num_clocks, iommu->clocks);
 
iommu->domain = NULL;
 
@@ -1172,18 +1194,38 @@ static int rk_iommu_probe(struct platform_device *pdev)
iommu->reset_disabled = device_property_read_bool(dev,
"rockchip,disable-mmu-reset");
 
-   err = iommu_device_sysfs_add(>iommu, dev, NULL, dev_name(dev));
+   iommu->num_clocks = ARRAY_SIZE(rk_iommu_clocks);
+   iommu->clocks = devm_kcalloc(iommu->dev, iommu->num_clocks,
+sizeof(*iommu->clocks), GFP_KERNEL);
+   if (!iommu->clocks)
+   return -ENOMEM;
+

[PATCH v7 05/14] iommu/rockchip: Use iopoll helpers to wait for hardware

2018-03-05 Thread Jeffy Chen
From: Tomasz Figa 

This patch converts the rockchip-iommu driver to use the in-kernel
iopoll helpers to wait for certain status bits to change in registers
instead of an open-coded custom macro.

Signed-off-by: Tomasz Figa 
Signed-off-by: Jeffy Chen 
Reviewed-by: Robin Murphy 
---

Changes in v7: None
Changes in v6: None
Changes in v5:
Use RK_MMU_POLL_PERIOD_US instead of 100.

Changes in v4: None
Changes in v3: None
Changes in v2: None

 drivers/iommu/rockchip-iommu.c | 75 ++
 1 file changed, 39 insertions(+), 36 deletions(-)

diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c
index f7ff3a3645ea..baba283ccdf9 100644
--- a/drivers/iommu/rockchip-iommu.c
+++ b/drivers/iommu/rockchip-iommu.c
@@ -13,7 +13,7 @@
 #include 
 #include 
 #include 
-#include 
+#include 
 #include 
 #include 
 #include 
@@ -36,7 +36,10 @@
 #define RK_MMU_AUTO_GATING 0x24
 
 #define DTE_ADDR_DUMMY 0xCAFEBABE
-#define FORCE_RESET_TIMEOUT100 /* ms */
+
+#define RK_MMU_POLL_PERIOD_US  100
+#define RK_MMU_FORCE_RESET_TIMEOUT_US  10
+#define RK_MMU_POLL_TIMEOUT_US 1000
 
 /* RK_MMU_STATUS fields */
 #define RK_MMU_STATUS_PAGING_ENABLED   BIT(0)
@@ -73,8 +76,6 @@
   */
 #define RK_IOMMU_PGSIZE_BITMAP 0x007ff000
 
-#define IOMMU_REG_POLL_COUNT_FAST 1000
-
 struct rk_iommu_domain {
struct list_head iommus;
struct platform_device *pdev;
@@ -109,27 +110,6 @@ static struct rk_iommu_domain *to_rk_domain(struct 
iommu_domain *dom)
return container_of(dom, struct rk_iommu_domain, domain);
 }
 
-/**
- * Inspired by _wait_for in intel_drv.h
- * This is NOT safe for use in interrupt context.
- *
- * Note that it's important that we check the condition again after having
- * timed out, since the timeout could be due to preemption or similar and
- * we've never had a chance to check the condition before the timeout.
- */
-#define rk_wait_for(COND, MS) ({ \
-   unsigned long timeout__ = jiffies + msecs_to_jiffies(MS) + 1;   \
-   int ret__ = 0;  \
-   while (!(COND)) {   \
-   if (time_after(jiffies, timeout__)) {   \
-   ret__ = (COND) ? 0 : -ETIMEDOUT;\
-   break;  \
-   }   \
-   usleep_range(50, 100);  \
-   }   \
-   ret__;  \
-})
-
 /*
  * The Rockchip rk3288 iommu uses a 2-level page table.
  * The first level is the "Directory Table" (DT).
@@ -333,9 +313,21 @@ static bool rk_iommu_is_paging_enabled(struct rk_iommu 
*iommu)
return enable;
 }
 
+static bool rk_iommu_is_reset_done(struct rk_iommu *iommu)
+{
+   bool done = true;
+   int i;
+
+   for (i = 0; i < iommu->num_mmu; i++)
+   done &= rk_iommu_read(iommu->bases[i], RK_MMU_DTE_ADDR) == 0;
+
+   return done;
+}
+
 static int rk_iommu_enable_stall(struct rk_iommu *iommu)
 {
int ret, i;
+   bool val;
 
if (rk_iommu_is_stall_active(iommu))
return 0;
@@ -346,7 +338,9 @@ static int rk_iommu_enable_stall(struct rk_iommu *iommu)
 
rk_iommu_command(iommu, RK_MMU_CMD_ENABLE_STALL);
 
-   ret = rk_wait_for(rk_iommu_is_stall_active(iommu), 1);
+   ret = readx_poll_timeout(rk_iommu_is_stall_active, iommu, val,
+val, RK_MMU_POLL_PERIOD_US,
+RK_MMU_POLL_TIMEOUT_US);
if (ret)
for (i = 0; i < iommu->num_mmu; i++)
dev_err(iommu->dev, "Enable stall request timed out, 
status: %#08x\n",
@@ -358,13 +352,16 @@ static int rk_iommu_enable_stall(struct rk_iommu *iommu)
 static int rk_iommu_disable_stall(struct rk_iommu *iommu)
 {
int ret, i;
+   bool val;
 
if (!rk_iommu_is_stall_active(iommu))
return 0;
 
rk_iommu_command(iommu, RK_MMU_CMD_DISABLE_STALL);
 
-   ret = rk_wait_for(!rk_iommu_is_stall_active(iommu), 1);
+   ret = readx_poll_timeout(rk_iommu_is_stall_active, iommu, val,
+!val, RK_MMU_POLL_PERIOD_US,
+RK_MMU_POLL_TIMEOUT_US);
if (ret)
for (i = 0; i < iommu->num_mmu; i++)
dev_err(iommu->dev, "Disable stall request timed out, 
status: %#08x\n",
@@ -376,13 +373,16 @@ static int rk_iommu_disable_stall(struct rk_iommu *iommu)
 static int rk_iommu_enable_paging(struct rk_iommu *iommu)
 {
int ret, i;
+   bool val;
 
if (rk_iommu_is_paging_enabled(iommu))

[PATCH v7 06/14] iommu/rockchip: Fix TLB flush of secondary IOMMUs

2018-03-05 Thread Jeffy Chen
From: Tomasz Figa 

Due to the bug in current code, only first IOMMU has the TLB lines
flushed in rk_iommu_zap_lines. This patch fixes the inner loop to
execute for all IOMMUs and properly flush the TLB.

Signed-off-by: Tomasz Figa 
Signed-off-by: Jeffy Chen 
---

Changes in v7: None
Changes in v6: None
Changes in v5: None
Changes in v4: None
Changes in v3: None
Changes in v2: None

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

diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c
index baba283ccdf9..c4131ca792e0 100644
--- a/drivers/iommu/rockchip-iommu.c
+++ b/drivers/iommu/rockchip-iommu.c
@@ -274,19 +274,21 @@ static void rk_iommu_base_command(void __iomem *base, u32 
command)
 {
writel(command, base + RK_MMU_COMMAND);
 }
-static void rk_iommu_zap_lines(struct rk_iommu *iommu, dma_addr_t iova,
+static void rk_iommu_zap_lines(struct rk_iommu *iommu, dma_addr_t iova_start,
   size_t size)
 {
int i;
-
-   dma_addr_t iova_end = iova + size;
+   dma_addr_t iova_end = iova_start + size;
/*
 * TODO(djkurtz): Figure out when it is more efficient to shootdown the
 * entire iotlb rather than iterate over individual iovas.
 */
-   for (i = 0; i < iommu->num_mmu; i++)
-   for (; iova < iova_end; iova += SPAGE_SIZE)
+   for (i = 0; i < iommu->num_mmu; i++) {
+   dma_addr_t iova;
+
+   for (iova = iova_start; iova < iova_end; iova += SPAGE_SIZE)
rk_iommu_write(iommu->bases[i], RK_MMU_ZAP_ONE_LINE, 
iova);
+   }
 }
 
 static bool rk_iommu_is_stall_active(struct rk_iommu *iommu)
-- 
2.11.0


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


[PATCH v7 04/14] iommu/rockchip: Fix error handling in attach

2018-03-05 Thread Jeffy Chen
From: Tomasz Figa 

Currently if the driver encounters an error while attaching device, it
will leave the IOMMU in an inconsistent state. Even though it shouldn't
really happen in reality, let's just add proper error path to keep
things consistent.

Signed-off-by: Tomasz Figa 
Signed-off-by: Jeffy Chen 
Reviewed-by: Robin Murphy 
---

Changes in v7: None
Changes in v6: None
Changes in v5:
Use out labels to save the duplication between the error and success paths.

Changes in v4: None
Changes in v3: None
Changes in v2:
Move irq request to probe(in patch[0])

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

diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c
index b743d82e6fe1..f7ff3a3645ea 100644
--- a/drivers/iommu/rockchip-iommu.c
+++ b/drivers/iommu/rockchip-iommu.c
@@ -824,7 +824,7 @@ static int rk_iommu_attach_device(struct iommu_domain 
*domain,
 
ret = rk_iommu_force_reset(iommu);
if (ret)
-   return ret;
+   goto out_disable_stall;
 
iommu->domain = domain;
 
@@ -837,7 +837,7 @@ static int rk_iommu_attach_device(struct iommu_domain 
*domain,
 
ret = rk_iommu_enable_paging(iommu);
if (ret)
-   return ret;
+   goto out_disable_stall;
 
spin_lock_irqsave(_domain->iommus_lock, flags);
list_add_tail(>node, _domain->iommus);
@@ -845,9 +845,9 @@ static int rk_iommu_attach_device(struct iommu_domain 
*domain,
 
dev_dbg(dev, "Attached to iommu domain\n");
 
+out_disable_stall:
rk_iommu_disable_stall(iommu);
-
-   return 0;
+   return ret;
 }
 
 static void rk_iommu_detach_device(struct iommu_domain *domain,
-- 
2.11.0


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


[PATCH v7 03/14] iommu/rockchip: Request irqs in rk_iommu_probe()

2018-03-05 Thread Jeffy Chen
Move request_irq to the end of rk_iommu_probe().

Suggested-by: Robin Murphy 
Signed-off-by: Jeffy Chen 
Reviewed-by: Tomasz Figa 
---

Changes in v7: None
Changes in v6: None
Changes in v5: None
Changes in v4: None
Changes in v3:
Loop platform_get_irq() as Robin suggested.

Changes in v2: None

 drivers/iommu/rockchip-iommu.c | 38 +-
 1 file changed, 9 insertions(+), 29 deletions(-)

diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c
index c2ef3cbd4401..b743d82e6fe1 100644
--- a/drivers/iommu/rockchip-iommu.c
+++ b/drivers/iommu/rockchip-iommu.c
@@ -90,8 +90,6 @@ struct rk_iommu {
struct device *dev;
void __iomem **bases;
int num_mmu;
-   int *irq;
-   int num_irq;
bool reset_disabled;
struct iommu_device iommu;
struct list_head node; /* entry in rk_iommu_domain.iommus */
@@ -830,13 +828,6 @@ static int rk_iommu_attach_device(struct iommu_domain 
*domain,
 
iommu->domain = domain;
 
-   for (i = 0; i < iommu->num_irq; i++) {
-   ret = devm_request_irq(iommu->dev, iommu->irq[i], rk_iommu_irq,
-  IRQF_SHARED, dev_name(dev), iommu);
-   if (ret)
-   return ret;
-   }
-
for (i = 0; i < iommu->num_mmu; i++) {
rk_iommu_write(iommu->bases[i], RK_MMU_DTE_ADDR,
   rk_domain->dt_dma);
@@ -885,9 +876,6 @@ static void rk_iommu_detach_device(struct iommu_domain 
*domain,
}
rk_iommu_disable_stall(iommu);
 
-   for (i = 0; i < iommu->num_irq; i++)
-   devm_free_irq(iommu->dev, iommu->irq[i], iommu);
-
iommu->domain = NULL;
 
dev_dbg(dev, "Detached from iommu domain\n");
@@ -1138,7 +1126,7 @@ static int rk_iommu_probe(struct platform_device *pdev)
struct rk_iommu *iommu;
struct resource *res;
int num_res = pdev->num_resources;
-   int err, i;
+   int err, i, irq;
 
iommu = devm_kzalloc(dev, sizeof(*iommu), GFP_KERNEL);
if (!iommu)
@@ -1165,23 +1153,15 @@ static int rk_iommu_probe(struct platform_device *pdev)
if (iommu->num_mmu == 0)
return PTR_ERR(iommu->bases[0]);
 
-   iommu->num_irq = platform_irq_count(pdev);
-   if (iommu->num_irq < 0)
-   return iommu->num_irq;
-   if (iommu->num_irq == 0)
-   return -ENXIO;
+   i = 0;
+   while ((irq = platform_get_irq(pdev, i++)) != -ENXIO) {
+   if (irq < 0)
+   return irq;
 
-   iommu->irq = devm_kcalloc(dev, iommu->num_irq, sizeof(*iommu->irq),
- GFP_KERNEL);
-   if (!iommu->irq)
-   return -ENOMEM;
-
-   for (i = 0; i < iommu->num_irq; i++) {
-   iommu->irq[i] = platform_get_irq(pdev, i);
-   if (iommu->irq[i] < 0) {
-   dev_err(dev, "Failed to get IRQ, %d\n", iommu->irq[i]);
-   return -ENXIO;
-   }
+   err = devm_request_irq(iommu->dev, irq, rk_iommu_irq,
+  IRQF_SHARED, dev_name(dev), iommu);
+   if (err)
+   return err;
}
 
iommu->reset_disabled = device_property_read_bool(dev,
-- 
2.11.0


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


[PATCH v7 01/14] iommu/rockchip: Prohibit unbind and remove

2018-03-05 Thread Jeffy Chen
Removal of IOMMUs cannot be done reliably.

This is similar to exynos iommu driver.

Signed-off-by: Jeffy Chen 
Reviewed-by: Tomasz Figa 
---

Changes in v7: None
Changes in v6: None
Changes in v5: None
Changes in v4:
Rewrite commit message.

Changes in v3:
Also remove remove() and module_exit() as Tomasz suggested.

Changes in v2: None

 drivers/iommu/rockchip-iommu.c | 21 +
 1 file changed, 1 insertion(+), 20 deletions(-)

diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c
index 9d991c2d8767..16cd8780c289 100644
--- a/drivers/iommu/rockchip-iommu.c
+++ b/drivers/iommu/rockchip-iommu.c
@@ -1197,18 +1197,6 @@ static int rk_iommu_probe(struct platform_device *pdev)
return err;
 }
 
-static int rk_iommu_remove(struct platform_device *pdev)
-{
-   struct rk_iommu *iommu = platform_get_drvdata(pdev);
-
-   if (iommu) {
-   iommu_device_sysfs_remove(>iommu);
-   iommu_device_unregister(>iommu);
-   }
-
-   return 0;
-}
-
 static const struct of_device_id rk_iommu_dt_ids[] = {
{ .compatible = "rockchip,iommu" },
{ /* sentinel */ }
@@ -1217,10 +1205,10 @@ MODULE_DEVICE_TABLE(of, rk_iommu_dt_ids);
 
 static struct platform_driver rk_iommu_driver = {
.probe = rk_iommu_probe,
-   .remove = rk_iommu_remove,
.driver = {
   .name = "rk_iommu",
   .of_match_table = rk_iommu_dt_ids,
+  .suppress_bind_attrs = true,
},
 };
 
@@ -1248,14 +1236,7 @@ static int __init rk_iommu_init(void)
platform_driver_unregister(_iommu_domain_driver);
return ret;
 }
-static void __exit rk_iommu_exit(void)
-{
-   platform_driver_unregister(_iommu_driver);
-   platform_driver_unregister(_iommu_domain_driver);
-}
-
 subsys_initcall(rk_iommu_init);
-module_exit(rk_iommu_exit);
 
 MODULE_DESCRIPTION("IOMMU API for Rockchip");
 MODULE_AUTHOR("Simon Xue  and Daniel Kurtz 
");
-- 
2.11.0


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


[PATCH v7 00/14] iommu/rockchip: Use OF_IOMMU

2018-03-05 Thread Jeffy Chen

This series fixes some issues in rockchip iommu driver, and add of_iommu
support in it.

Changes in v7:
Add WARN_ON in irq isr, and modify iommu archdata comment.
Use iommu_group_ref_get to avoid ref leak

Changes in v6:
Add clk names, and modify all iommu nodes in all existing rockchip dts
Fix dt-binding as Robin suggested.
Use aclk and iface clk as Rob and Robin suggested, and split binding
patch.
Fix dt-binding as Robin suggested.
Use aclk and iface clk as Rob and Robin suggested, and split binding
patch.

Changes in v5:
Use out labels to save the duplication between the error and success paths.
Use RK_MMU_POLL_PERIOD_US instead of 100.
Remove clk names.
Use clk_bulk APIs.
Avoid race about pm_runtime_get_if_in_use() and pm_runtime_enabled().

Changes in v4:
Rewrite commit message.

Changes in v3:
Also remove remove() and module_exit() as Tomasz suggested.
Loop platform_get_irq() as Robin suggested.
Add struct rk_iommudata.
Squash iommu/rockchip: Use iommu_group_get_for_dev() for add_device
Only call startup() and shutdown() when iommu attached.
Remove pm_mutex.
Check runtime PM disabled.
Check pm_runtime in rk_iommu_irq().
Remove rk_iommudata->domain.

Changes in v2:
Move irq request to probe(in patch[0])
Move bus_set_iommu() to rk_iommu_probe().

Jeffy Chen (10):
  iommu/rockchip: Prohibit unbind and remove
  iommu/rockchip: Fix error handling in probe
  iommu/rockchip: Request irqs in rk_iommu_probe()
  ARM: dts: rockchip: add clocks in iommu nodes
  dt-bindings: iommu/rockchip: Add clock property
  iommu/rockchip: Use IOMMU device for dma mapping operations
  iommu/rockchip: Use OF_IOMMU to attach devices automatically
  iommu/rockchip: Fix error handling in init
  iommu/rockchip: Add runtime PM support
  iommu/rockchip: Support sharing IOMMU between masters

Tomasz Figa (4):
  iommu/rockchip: Fix error handling in attach
  iommu/rockchip: Use iopoll helpers to wait for hardware
  iommu/rockchip: Fix TLB flush of secondary IOMMUs
  iommu/rockchip: Control clocks needed to access the IOMMU

 .../devicetree/bindings/iommu/rockchip,iommu.txt   |   7 +
 arch/arm/boot/dts/rk3036.dtsi  |   2 +
 arch/arm/boot/dts/rk322x.dtsi  |   8 +
 arch/arm/boot/dts/rk3288.dtsi  |  12 +
 arch/arm64/boot/dts/rockchip/rk3328.dtsi   |  10 +
 arch/arm64/boot/dts/rockchip/rk3368.dtsi   |  10 +
 arch/arm64/boot/dts/rockchip/rk3399.dtsi   |  14 +-
 drivers/iommu/rockchip-iommu.c | 608 +++--
 8 files changed, 382 insertions(+), 289 deletions(-)

-- 
2.11.0


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


[PATCH v7 02/14] iommu/rockchip: Fix error handling in probe

2018-03-05 Thread Jeffy Chen
Add missing iommu_device_sysfs_remove in error path.

Signed-off-by: Jeffy Chen 
Reviewed-by: Tomasz Figa 
---

Changes in v7: None
Changes in v6: None
Changes in v5: None
Changes in v4: None
Changes in v3: None
Changes in v2: None

 drivers/iommu/rockchip-iommu.c | 6 +-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c
index 16cd8780c289..c2ef3cbd4401 100644
--- a/drivers/iommu/rockchip-iommu.c
+++ b/drivers/iommu/rockchip-iommu.c
@@ -1193,8 +1193,12 @@ static int rk_iommu_probe(struct platform_device *pdev)
 
iommu_device_set_ops(>iommu, _iommu_ops);
err = iommu_device_register(>iommu);
+   if (err) {
+   iommu_device_sysfs_remove(>iommu);
+   return err;
+   }
 
-   return err;
+   return 0;
 }
 
 static const struct of_device_id rk_iommu_dt_ids[] = {
-- 
2.11.0


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


Re: [RESEND PATCH v6 09/14] dt-bindings: iommu/rockchip: Add clock property

2018-03-05 Thread JeffyChen

Hi Rob,

Thanks for your reply.

On 03/06/2018 10:27 AM, Rob Herring wrote:

On Thu, Mar 01, 2018 at 06:18:32PM +0800, Jeffy Chen wrote:

Add clock property, since we are going to control clocks in rockchip
iommu driver.

Signed-off-by: Jeffy Chen 
---

Changes in v6: None


Really? There was a different number of clocks before.

hmm, right, forgot to modify the change log, sorry...



Changes in v5: None
Changes in v4: None
Changes in v3: None
Changes in v2: None

  Documentation/devicetree/bindings/iommu/rockchip,iommu.txt | 7 +++
  1 file changed, 7 insertions(+)


Reviewed-by: Rob Herring 






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


Re: [RESEND PATCH v6 09/14] dt-bindings: iommu/rockchip: Add clock property

2018-03-05 Thread Rob Herring
On Thu, Mar 01, 2018 at 06:18:32PM +0800, Jeffy Chen wrote:
> Add clock property, since we are going to control clocks in rockchip
> iommu driver.
> 
> Signed-off-by: Jeffy Chen 
> ---
> 
> Changes in v6: None

Really? There was a different number of clocks before.

> Changes in v5: None
> Changes in v4: None
> Changes in v3: None
> Changes in v2: None
> 
>  Documentation/devicetree/bindings/iommu/rockchip,iommu.txt | 7 +++
>  1 file changed, 7 insertions(+)

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


Re: [RESEND PATCH v6 13/14] iommu/rockchip: Add runtime PM support

2018-03-05 Thread JeffyChen

Hi Tomasz,

Thanks for your reply.

On 03/05/2018 09:49 PM, Tomasz Figa wrote:

>  struct rk_iommudata {
>+   struct device_link *link; /* runtime PM link from IOMMU to master */

Kerneldoc comment for the struct could be added instead.

i saw this in the kerneldoc:

* An MMU device exists alongside a busmaster device, both are in the same
  power domain.  The MMU implements DMA address translation for the 
busmaster

  device and shall be runtime resumed and kept active whenever and as long
  as the busmaster device is active.  The busmaster device's driver shall
  not bind before the MMU is bound.  To achieve this, a device link with
  runtime PM integration is added from the busmaster device (consumer)
  to the MMU device (supplier).  The effect with regards to runtime PM
  is the same as if the MMU was the parent of the master device.


maybe we can use something like:
device link with runtime PM integration from the master (consumer) to 
the IOMMU (supplier).





> struct rk_iommu *iommu;
>  };
>
>@@ -518,7 +520,12 @@ static irqreturn_t rk_iommu_irq(int irq, void *dev_id)
> u32 int_status;
> dma_addr_t iova;
> irqreturn_t ret = IRQ_NONE;
>-   int i;
>+   int i, err, need_runtime_put;

nit: need_runtime_put could be a bool.

ok




>+
>+   err = pm_runtime_get_if_in_use(iommu->dev);
>+   if (err <= 0 && err != -EINVAL)
>+   return ret;
>+   need_runtime_put = err > 0;

Generally something must be really wrong if we end up with err == 0
here, because the IOMMU must be powered on to signal an interrupt. The
only case this could happen would be if the IRQ signal was shared with
some device from another power domain. Is it possible on Rockchip
SoCs? If not, perhaps we should have a WARN_ON() here for such case.
the irq could be shared between master and IOMMU, but always from the 
same power domain i think.


will add a WARN_ON()



>
> WARN_ON(clk_bulk_enable(iommu->num_clocks, iommu->clocks));
>
>@@ -570,6 +577,9 @@ static irqreturn_t rk_iommu_irq(int irq, void *dev_id)
>
> clk_bulk_disable(iommu->num_clocks, iommu->clocks);
>
>+   if (need_runtime_put)
>+   pm_runtime_put(iommu->dev);
>+
> return ret;
>  }
>
>@@ -611,10 +621,20 @@ static void rk_iommu_zap_iova(struct rk_iommu_domain 
*rk_domain,
> spin_lock_irqsave(_domain->iommus_lock, flags);
> list_for_each(pos, _domain->iommus) {
> struct rk_iommu *iommu;
>+   int ret;
>+
> iommu = list_entry(pos, struct rk_iommu, node);
>-   WARN_ON(clk_bulk_enable(iommu->num_clocks, iommu->clocks));
>-   rk_iommu_zap_lines(iommu, iova, size);
>-   clk_bulk_disable(iommu->num_clocks, iommu->clocks);
>+
>+   /* Only zap TLBs of IOMMUs that are powered on. */
>+   ret = pm_runtime_get_if_in_use(iommu->dev);
>+   if (ret > 0 || ret == -EINVAL) {
>+   WARN_ON(clk_bulk_enable(iommu->num_clocks,
>+   iommu->clocks));
>+   rk_iommu_zap_lines(iommu, iova, size);
>+   clk_bulk_disable(iommu->num_clocks, iommu->clocks);
>+   }
>+   if (ret > 0)
>+   pm_runtime_put(iommu->dev);
> }
> spin_unlock_irqrestore(_domain->iommus_lock, flags);
>  }
>@@ -817,22 +837,30 @@ static struct rk_iommu *rk_iommu_from_dev(struct device 
*dev)
> return data ? data->iommu : NULL;
>  }
>
>-static int rk_iommu_attach_device(struct iommu_domain *domain,
>- struct device *dev)
>+/* Must be called with iommu powered on and attached */
>+static void rk_iommu_shutdown(struct rk_iommu *iommu)
>  {
>-   struct rk_iommu *iommu;
>+   int i;
>+
>+   /* Ignore error while disabling, just keep going */
>+   WARN_ON(clk_bulk_enable(iommu->num_clocks, iommu->clocks));
>+   rk_iommu_enable_stall(iommu);
>+   rk_iommu_disable_paging(iommu);
>+   for (i = 0; i < iommu->num_mmu; i++) {
>+   rk_iommu_write(iommu->bases[i], RK_MMU_INT_MASK, 0);
>+   rk_iommu_write(iommu->bases[i], RK_MMU_DTE_ADDR, 0);
>+   }
>+   rk_iommu_disable_stall(iommu);
>+   clk_bulk_disable(iommu->num_clocks, iommu->clocks);
>+}
>+
>+/* Must be called with iommu powered on and attached */
>+static int rk_iommu_startup(struct rk_iommu *iommu)
>+{
>+   struct iommu_domain *domain = iommu->domain;
> struct rk_iommu_domain *rk_domain = to_rk_domain(domain);
>-   unsigned long flags;
> int ret, i;
>
>-   /*
>-* Allow 'virtual devices' (e.g., drm) to attach to domain.
>-* Such a device does not belong to an iommu group.
>-*/
>-   iommu = rk_iommu_from_dev(dev);
>-   if (!iommu)
>-   return 0;
>-
> ret = clk_bulk_enable(iommu->num_clocks, iommu->clocks);
> if 

Re: [PATCH 07/37] iommu: Add a page fault handler

2018-03-05 Thread Sinan Kaya
On 2/12/2018 1:33 PM, Jean-Philippe Brucker wrote:
> +static struct workqueue_struct *iommu_fault_queue;

Is there anyway we can make this fault queue per struct device?
Since this is common code, I think it needs some care.


-- 
Sinan Kaya
Qualcomm Datacenter Technologies, Inc. as an affiliate of Qualcomm 
Technologies, Inc.
Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux 
Foundation Collaborative Project.
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH 07/37] iommu: Add a page fault handler

2018-03-05 Thread Sinan Kaya
On 2/12/2018 1:33 PM, Jean-Philippe Brucker wrote:
> +static int iommu_queue_fault(struct iommu_domain *domain, struct device *dev,
> +  struct iommu_fault_event *evt)
> +{
> + struct iommu_fault_group *group;
> + struct iommu_fault_context *fault, *next;
> +
> + if (!iommu_fault_queue)
> + return -ENOSYS;
> +
> + if (!evt->last_req) {
> + fault = kzalloc(sizeof(*fault), GFP_KERNEL);
> + if (!fault)
> + return -ENOMEM;
> +
> + fault->evt = *evt;
> + fault->dev = dev;
> +
> + /* Non-last request of a group. Postpone until the last one */
> + spin_lock(_partial_faults_lock);
> + list_add_tail(>head, _partial_faults);
> + spin_unlock(_partial_faults_lock);
> +
> + return IOMMU_PAGE_RESP_HANDLED;
> + }
> +
> + group = kzalloc(sizeof(*group), GFP_KERNEL);
> + if (!group)
> + return -ENOMEM;

Release the requests in iommu_partial_faults here.

-- 
Sinan Kaya
Qualcomm Datacenter Technologies, Inc. as an affiliate of Qualcomm 
Technologies, Inc.
Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux 
Foundation Collaborative Project.
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH 5/8] dt-bindings: iommu/ipmmu-vmsa: Add R-Car M3-N (R8A77965)

2018-03-05 Thread Rob Herring
On Mon, Feb 26, 2018 at 06:57:13PM +0100, Jacopo Mondi wrote:
> Add Renesas R-Car M3-N (R8A77965) compat string to IPMMU DT bindings
> documentation.
> 
> Signed-off-by: Jacopo Mondi 
> ---
>  Documentation/devicetree/bindings/iommu/renesas,ipmmu-vmsa.txt | 1 +
>  1 file changed, 1 insertion(+)

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


Re: [PATCH 5/6] dma-mapping: support fsl-mc bus

2018-03-05 Thread Robin Murphy

On 05/03/18 18:39, Christoph Hellwig wrote:

On Mon, Mar 05, 2018 at 03:48:32PM +, Robin Murphy wrote:

Unfortunately for us, fsl-mc is conceptually rather like PCI in that it's
software-discoverable and the only thing described in DT is the bus "host",
thus we need the same sort of thing as for PCI to map from the child
devices back to the bus root in order to find the appropriate firmware
node. Worse than PCI, though, we wouldn't even have the option of
describing child devices statically in firmware at all, since it's actually
one of these runtime-configurable "build your own network accelerator"
hardware pools where userspace gets to create and destroy "devices" as it
likes.


I really hate the PCI special case just as much.  Maybe we just
need a dma_configure method on the bus, and move PCI as well as fsl-mc
to it.


Hmm, on reflection, 100% ack to that idea. It would neatly supersede 
bus->force_dma *and* mean that we don't have to effectively pull pci.h 
into everything, which I've never liked. In hindsight dma_configure() 
does feel like it's grown into this odd choke point where we munge 
everything in just for it to awkwardly unpick things again.


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


Re: [PATCH 5/6] dma-mapping: support fsl-mc bus

2018-03-05 Thread Christoph Hellwig
On Mon, Mar 05, 2018 at 03:48:32PM +, Robin Murphy wrote:
> Unfortunately for us, fsl-mc is conceptually rather like PCI in that it's 
> software-discoverable and the only thing described in DT is the bus "host", 
> thus we need the same sort of thing as for PCI to map from the child 
> devices back to the bus root in order to find the appropriate firmware 
> node. Worse than PCI, though, we wouldn't even have the option of 
> describing child devices statically in firmware at all, since it's actually 
> one of these runtime-configurable "build your own network accelerator" 
> hardware pools where userspace gets to create and destroy "devices" as it 
> likes.

I really hate the PCI special case just as much.  Maybe we just
need a dma_configure method on the bus, and move PCI as well as fsl-mc
to it.
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: Using dma-ranges with iommu to limit range of iova

2018-03-05 Thread Vivek Gautam

Hi Robin,


On 3/5/2018 5:46 PM, Robin Murphy wrote:

Hi Vivek,

On 05/03/18 09:06, Vivek Gautam wrote:

Hi all,

I have a question regarding usage of 'dma-ranges', can someone point 
me in the right direction?
On qcom soc, few of the master devices with iommu attached to them, 
have limitations in using the iova address range. They can allow the 
iova to be only in a certain range, e.g. video codec firmware can 
only access iova only in a first few MBs as the video's arm core 
reset starts at 0x0.
To do that, I earlier, had the understanding that we can modify the 
iommu_domain's geometry aperture. But that looks kind of a hacky way 
to get the domain for the device and modify the aperture.
I was trying to explore if we can use the dma-ranges property. But 
the iommu bindings documentation doesn't really talks much about 
usage of dma-ranges.
Can someone help me with with the answer to - can we use 'dma-ranges' 
to limit a device's iova address access? If yes, then how?


Yes, if the device has physical restrictions on what it can address, 
then "dma-ranges" is the correct way to describe that. That should be 
pretty much orthogonal to the IOMMU binding and combine in the obvious 
way, e.g.:


...
soc {
    #address-cells = <1>;
    #size-cells = <1>;
    compatible = "simple-bus";
    ranges;

    ...

    iommu@f000 {
    compatible = "iommu";
    reg = <0xf000 0x1000>;
    #iommu-cells = <0>;
    };

    ...

    subsystem {


Usually, the multimedia devices are just the device nodes without
any subsystem. Can dma-ranges, and iommus exist together for the
device?


#address-cells = <1>;
    #size-cells = <1>;
    compatible = "simple-bus";
    ranges;
    /* Devices can only drive address bits 0:23 */
    dma-ranges = <0 0 0x100>;

    device {
    iommus = <>;
    };
    };
};
...

In terms of Linux, for the straightforward platform device case 
of_dma_configure() initialises the subsystem devices' DMA masks based 
on the size covered by "dma-ranges", and the DMA API code respects the 
device's DMA mask when allocating IOVAs. The only problem is the bit 
in the middle where the device driver's dma_set_mask() call can just 
trash of_dma_configure()'s initial mask, because there's no way to 
differentiate an explicitly-specified mask from a default one.


But the drivers should ideally check for any existing dma_mask set for 
the device before calling dma_set_mask_and_coherent(). I see few of the 
drivers do check that, so we don't overwrite the dma mask.


It's also even uglier for PCI devices since the existing "pass the 
host bridge's node as the device's" bodge happens to work for the 
"dma-coherent" property but is a bit broken in general and doesn't 
work at all for "dma-ranges".


Fixing all of this (not to mention the DT/ACPI interaction aspect) has 
been hovering around #3 on my to-do list for the past couple of years 
now, but things keep sneaking in above it :(


Anything that I can take a look at, and add?

regards
Vivek


Robin.


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

[PATCH 12/13] swiotlb: remove swiotlb_set_mem_attributes

2018-03-05 Thread Christoph Hellwig
Now that set_memory_decrypted is always available we can just call it
directly.

Signed-off-by: Christoph Hellwig 
---
 arch/x86/include/asm/mem_encrypt.h |  2 --
 arch/x86/mm/mem_encrypt.c  |  9 -
 lib/swiotlb.c  | 12 ++--
 3 files changed, 6 insertions(+), 17 deletions(-)

diff --git a/arch/x86/include/asm/mem_encrypt.h 
b/arch/x86/include/asm/mem_encrypt.h
index 22c5f3e6f820..9da0b63c8fc7 100644
--- a/arch/x86/include/asm/mem_encrypt.h
+++ b/arch/x86/include/asm/mem_encrypt.h
@@ -48,8 +48,6 @@ int __init early_set_memory_encrypted(unsigned long vaddr, 
unsigned long size);
 /* Architecture __weak replacement functions */
 void __init mem_encrypt_init(void);
 
-void swiotlb_set_mem_attributes(void *vaddr, unsigned long size);
-
 bool sme_active(void);
 bool sev_active(void);
 
diff --git a/arch/x86/mm/mem_encrypt.c b/arch/x86/mm/mem_encrypt.c
index 8bfc735bbdd7..65f45e0ef496 100644
--- a/arch/x86/mm/mem_encrypt.c
+++ b/arch/x86/mm/mem_encrypt.c
@@ -379,15 +379,6 @@ void __init mem_encrypt_init(void)
 : "Secure Memory Encryption (SME)");
 }
 
-void swiotlb_set_mem_attributes(void *vaddr, unsigned long size)
-{
-   WARN(PAGE_ALIGN(size) != size,
-"size is not page-aligned (%#lx)\n", size);
-
-   /* Make the SWIOTLB buffer area decrypted */
-   set_memory_decrypted((unsigned long)vaddr, size >> PAGE_SHIFT);
-}
-
 struct sme_populate_pgd_data {
void*pgtable_area;
pgd_t   *pgd;
diff --git a/lib/swiotlb.c b/lib/swiotlb.c
index ca8eeaead925..8b06b4485e65 100644
--- a/lib/swiotlb.c
+++ b/lib/swiotlb.c
@@ -31,6 +31,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include 
 #include 
@@ -156,8 +157,6 @@ unsigned long swiotlb_size_or_default(void)
return size ? size : (IO_TLB_DEFAULT_SIZE);
 }
 
-void __weak swiotlb_set_mem_attributes(void *vaddr, unsigned long size) { }
-
 /* Note that this doesn't work with highmem page */
 static dma_addr_t swiotlb_virt_to_bus(struct device *hwdev,
  volatile void *address)
@@ -202,12 +201,12 @@ void __init swiotlb_update_mem_attributes(void)
 
vaddr = phys_to_virt(io_tlb_start);
bytes = PAGE_ALIGN(io_tlb_nslabs << IO_TLB_SHIFT);
-   swiotlb_set_mem_attributes(vaddr, bytes);
+   set_memory_decrypted((unsigned long)vaddr, bytes >> PAGE_SHIFT);
memset(vaddr, 0, bytes);
 
vaddr = phys_to_virt(io_tlb_overflow_buffer);
bytes = PAGE_ALIGN(io_tlb_overflow);
-   swiotlb_set_mem_attributes(vaddr, bytes);
+   set_memory_decrypted((unsigned long)vaddr, bytes >> PAGE_SHIFT);
memset(vaddr, 0, bytes);
 }
 
@@ -348,7 +347,7 @@ swiotlb_late_init_with_tbl(char *tlb, unsigned long nslabs)
io_tlb_start = virt_to_phys(tlb);
io_tlb_end = io_tlb_start + bytes;
 
-   swiotlb_set_mem_attributes(tlb, bytes);
+   set_memory_decrypted((unsigned long)tlb, bytes >> PAGE_SHIFT);
memset(tlb, 0, bytes);
 
/*
@@ -359,7 +358,8 @@ swiotlb_late_init_with_tbl(char *tlb, unsigned long nslabs)
if (!v_overflow_buffer)
goto cleanup2;
 
-   swiotlb_set_mem_attributes(v_overflow_buffer, io_tlb_overflow);
+   set_memory_decrypted((unsigned long)v_overflow_buffer,
+   io_tlb_overflow >> PAGE_SHIFT);
memset(v_overflow_buffer, 0, io_tlb_overflow);
io_tlb_overflow_buffer = virt_to_phys(v_overflow_buffer);
 
-- 
2.14.2

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


[PATCH 13/13] swiotlb: remove swiotlb_{alloc,free}_coherent

2018-03-05 Thread Christoph Hellwig
Unused now that everyone uses swiotlb_{alloc,free}.

Signed-off-by: Christoph Hellwig 
---
 include/linux/swiotlb.h |  8 
 lib/swiotlb.c   | 38 --
 2 files changed, 46 deletions(-)

diff --git a/include/linux/swiotlb.h b/include/linux/swiotlb.h
index 5b1f2a00491c..965be92c33b5 100644
--- a/include/linux/swiotlb.h
+++ b/include/linux/swiotlb.h
@@ -72,14 +72,6 @@ void *swiotlb_alloc(struct device *hwdev, size_t size, 
dma_addr_t *dma_handle,
 void swiotlb_free(struct device *dev, size_t size, void *vaddr,
dma_addr_t dma_addr, unsigned long attrs);
 
-extern void
-*swiotlb_alloc_coherent(struct device *hwdev, size_t size,
-   dma_addr_t *dma_handle, gfp_t flags);
-
-extern void
-swiotlb_free_coherent(struct device *hwdev, size_t size,
- void *vaddr, dma_addr_t dma_handle);
-
 extern dma_addr_t swiotlb_map_page(struct device *dev, struct page *page,
   unsigned long offset, size_t size,
   enum dma_data_direction dir,
diff --git a/lib/swiotlb.c b/lib/swiotlb.c
index 8b06b4485e65..15954b86f09e 100644
--- a/lib/swiotlb.c
+++ b/lib/swiotlb.c
@@ -157,13 +157,6 @@ unsigned long swiotlb_size_or_default(void)
return size ? size : (IO_TLB_DEFAULT_SIZE);
 }
 
-/* Note that this doesn't work with highmem page */
-static dma_addr_t swiotlb_virt_to_bus(struct device *hwdev,
- volatile void *address)
-{
-   return phys_to_dma(hwdev, virt_to_phys(address));
-}
-
 static bool no_iotlb_memory;
 
 void swiotlb_print_info(void)
@@ -752,28 +745,6 @@ swiotlb_alloc_buffer(struct device *dev, size_t size, 
dma_addr_t *dma_handle,
return NULL;
 }
 
-void *
-swiotlb_alloc_coherent(struct device *hwdev, size_t size,
-  dma_addr_t *dma_handle, gfp_t flags)
-{
-   int order = get_order(size);
-   unsigned long attrs = (flags & __GFP_NOWARN) ? DMA_ATTR_NO_WARN : 0;
-   void *ret;
-
-   ret = (void *)__get_free_pages(flags, order);
-   if (ret) {
-   *dma_handle = swiotlb_virt_to_bus(hwdev, ret);
-   if (dma_coherent_ok(hwdev, *dma_handle, size)) {
-   memset(ret, 0, size);
-   return ret;
-   }
-   free_pages((unsigned long)ret, order);
-   }
-
-   return swiotlb_alloc_buffer(hwdev, size, dma_handle, attrs);
-}
-EXPORT_SYMBOL(swiotlb_alloc_coherent);
-
 static bool swiotlb_free_buffer(struct device *dev, size_t size,
dma_addr_t dma_addr)
 {
@@ -793,15 +764,6 @@ static bool swiotlb_free_buffer(struct device *dev, size_t 
size,
return true;
 }
 
-void
-swiotlb_free_coherent(struct device *hwdev, size_t size, void *vaddr,
- dma_addr_t dev_addr)
-{
-   if (!swiotlb_free_buffer(hwdev, size, dev_addr))
-   free_pages((unsigned long)vaddr, get_order(size));
-}
-EXPORT_SYMBOL(swiotlb_free_coherent);
-
 static void
 swiotlb_full(struct device *dev, size_t size, enum dma_data_direction dir,
 int do_panic)
-- 
2.14.2

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


[PATCH 11/13] dma-direct: handle the memory encryption bit in common code

2018-03-05 Thread Christoph Hellwig
Give the basic phys_to_dma and dma_to_phys helpers a __-prefix and add
the memory encryption mask to the non-prefixed versions.  Use the
__-prefixed versions directly instead of clearing the mask again in
various places.

With that in place the generic dma-direct routines can be used to
allocate non-encrypted bounce buffers, and the x86 SEV case can use
the generic swiotlb ops.

Signed-off-by: Christoph Hellwig 
---
 arch/arm/include/asm/dma-direct.h  |  4 +-
 arch/mips/cavium-octeon/dma-octeon.c   | 10 +--
 .../include/asm/mach-cavium-octeon/dma-coherence.h |  4 +-
 .../include/asm/mach-loongson64/dma-coherence.h| 10 +--
 arch/mips/loongson64/common/dma-swiotlb.c  |  4 +-
 arch/powerpc/include/asm/dma-direct.h  |  4 +-
 arch/x86/Kconfig   |  2 +-
 arch/x86/include/asm/dma-direct.h  | 25 +---
 arch/x86/mm/mem_encrypt.c  | 73 +-
 arch/x86/pci/sta2x11-fixup.c   |  6 +-
 include/linux/dma-direct.h | 21 ++-
 lib/dma-direct.c   | 21 +--
 lib/swiotlb.c  | 25 +++-
 13 files changed, 70 insertions(+), 139 deletions(-)

diff --git a/arch/arm/include/asm/dma-direct.h 
b/arch/arm/include/asm/dma-direct.h
index 5b0a8a421894..b67e5fc1fe43 100644
--- a/arch/arm/include/asm/dma-direct.h
+++ b/arch/arm/include/asm/dma-direct.h
@@ -2,13 +2,13 @@
 #ifndef ASM_ARM_DMA_DIRECT_H
 #define ASM_ARM_DMA_DIRECT_H 1
 
-static inline dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr)
+static inline dma_addr_t __phys_to_dma(struct device *dev, phys_addr_t paddr)
 {
unsigned int offset = paddr & ~PAGE_MASK;
return pfn_to_dma(dev, __phys_to_pfn(paddr)) + offset;
 }
 
-static inline phys_addr_t dma_to_phys(struct device *dev, dma_addr_t dev_addr)
+static inline phys_addr_t __dma_to_phys(struct device *dev, dma_addr_t 
dev_addr)
 {
unsigned int offset = dev_addr & ~PAGE_MASK;
return __pfn_to_phys(dma_to_pfn(dev, dev_addr)) + offset;
diff --git a/arch/mips/cavium-octeon/dma-octeon.c 
b/arch/mips/cavium-octeon/dma-octeon.c
index c7bb8a407041..7b335ab21697 100644
--- a/arch/mips/cavium-octeon/dma-octeon.c
+++ b/arch/mips/cavium-octeon/dma-octeon.c
@@ -10,7 +10,7 @@
  * IP32 changes by Ilya.
  * Copyright (C) 2010 Cavium Networks, Inc.
  */
-#include 
+#include 
 #include 
 #include 
 #include 
@@ -182,7 +182,7 @@ struct octeon_dma_map_ops {
phys_addr_t (*dma_to_phys)(struct device *dev, dma_addr_t daddr);
 };
 
-dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr)
+dma_addr_t __phys_to_dma(struct device *dev, phys_addr_t paddr)
 {
struct octeon_dma_map_ops *ops = container_of(get_dma_ops(dev),
  struct octeon_dma_map_ops,
@@ -190,9 +190,9 @@ dma_addr_t phys_to_dma(struct device *dev, phys_addr_t 
paddr)
 
return ops->phys_to_dma(dev, paddr);
 }
-EXPORT_SYMBOL(phys_to_dma);
+EXPORT_SYMBOL(__phys_to_dma);
 
-phys_addr_t dma_to_phys(struct device *dev, dma_addr_t daddr)
+phys_addr_t __dma_to_phys(struct device *dev, dma_addr_t daddr)
 {
struct octeon_dma_map_ops *ops = container_of(get_dma_ops(dev),
  struct octeon_dma_map_ops,
@@ -200,7 +200,7 @@ phys_addr_t dma_to_phys(struct device *dev, dma_addr_t 
daddr)
 
return ops->dma_to_phys(dev, daddr);
 }
-EXPORT_SYMBOL(dma_to_phys);
+EXPORT_SYMBOL(__dma_to_phys);
 
 static struct octeon_dma_map_ops octeon_linear_dma_map_ops = {
.dma_map_ops = {
diff --git a/arch/mips/include/asm/mach-cavium-octeon/dma-coherence.h 
b/arch/mips/include/asm/mach-cavium-octeon/dma-coherence.h
index 138edf6b5b48..6eb1ee548b11 100644
--- a/arch/mips/include/asm/mach-cavium-octeon/dma-coherence.h
+++ b/arch/mips/include/asm/mach-cavium-octeon/dma-coherence.h
@@ -69,8 +69,8 @@ static inline bool dma_capable(struct device *dev, dma_addr_t 
addr, size_t size)
return addr + size - 1 <= *dev->dma_mask;
 }
 
-dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr);
-phys_addr_t dma_to_phys(struct device *dev, dma_addr_t daddr);
+dma_addr_t __phys_to_dma(struct device *dev, phys_addr_t paddr);
+phys_addr_t __dma_to_phys(struct device *dev, dma_addr_t daddr);
 
 struct dma_map_ops;
 extern const struct dma_map_ops *octeon_pci_dma_map_ops;
diff --git a/arch/mips/include/asm/mach-loongson64/dma-coherence.h 
b/arch/mips/include/asm/mach-loongson64/dma-coherence.h
index b1b575f5c6c1..64fc44dec0a8 100644
--- a/arch/mips/include/asm/mach-loongson64/dma-coherence.h
+++ b/arch/mips/include/asm/mach-loongson64/dma-coherence.h
@@ -25,13 +25,13 @@ static inline bool dma_capable(struct device *dev, 
dma_addr_t addr, size_t size)
return addr + size - 1 <= *dev->dma_mask;
 }
 
-extern dma_addr_t phys_to_dma(struct device *dev, phys_addr_t 

use generic dma-direct and swiotlb code for x86

2018-03-05 Thread Christoph Hellwig
Hi all,

this series switches the x86 code the the dma-direct implementation
for direct (non-iommu) dma and the generic swiotlb ops.  This includes
getting rid of the special ops for the AMD memory encryption case and
the STA2x11 SOC.  The generic implementations are based on the x86
code, so they provide the same functionality.
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH 10/13] set_memory.h: provide set_memory_{en,de}crypted stubs

2018-03-05 Thread Christoph Hellwig
Signed-off-by: Christoph Hellwig 
---
 include/linux/set_memory.h | 12 
 1 file changed, 12 insertions(+)

diff --git a/include/linux/set_memory.h b/include/linux/set_memory.h
index e5140648f638..da5178216da5 100644
--- a/include/linux/set_memory.h
+++ b/include/linux/set_memory.h
@@ -17,4 +17,16 @@ static inline int set_memory_x(unsigned long addr,  int 
numpages) { return 0; }
 static inline int set_memory_nx(unsigned long addr, int numpages) { return 0; }
 #endif
 
+#ifndef CONFIG_ARCH_HAS_MEM_ENCRYPT
+static inline int set_memory_encrypted(unsigned long addr, int numpages)
+{
+   return 0;
+}
+
+static inline int set_memory_decrypted(unsigned long addr, int numpages)
+{
+   return 0;
+}
+#endif /* CONFIG_ARCH_HAS_MEM_ENCRYPT */
+
 #endif /* _LINUX_SET_MEMORY_H_ */
-- 
2.14.2

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


[PATCH 07/13] iommu/amd_iommu: use dma_direct_{alloc,free}

2018-03-05 Thread Christoph Hellwig
This cleans up the code a lot by removing duplicate logic.

Signed-off-by: Christoph Hellwig 
---
 drivers/iommu/Kconfig |  1 +
 drivers/iommu/amd_iommu.c | 68 +++
 2 files changed, 22 insertions(+), 47 deletions(-)

diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index f3a21343e636..dc7c1914645d 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -107,6 +107,7 @@ config IOMMU_PGTABLES_L2
 # AMD IOMMU support
 config AMD_IOMMU
bool "AMD IOMMU support"
+   select DMA_DIRECT_OPS
select SWIOTLB
select PCI_MSI
select PCI_ATS
diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
index 0bf19423b588..83819d0cbf90 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -2600,51 +2600,32 @@ static void *alloc_coherent(struct device *dev, size_t 
size,
unsigned long attrs)
 {
u64 dma_mask = dev->coherent_dma_mask;
-   struct protection_domain *domain;
-   struct dma_ops_domain *dma_dom;
-   struct page *page;
-
-   domain = get_domain(dev);
-   if (PTR_ERR(domain) == -EINVAL) {
-   page = alloc_pages(flag, get_order(size));
-   *dma_addr = page_to_phys(page);
-   return page_address(page);
-   } else if (IS_ERR(domain))
-   return NULL;
+   struct protection_domain *domain = get_domain(dev);
+   bool is_direct = false;
+   void *virt_addr;
 
-   dma_dom   = to_dma_ops_domain(domain);
-   size  = PAGE_ALIGN(size);
-   dma_mask  = dev->coherent_dma_mask;
-   flag &= ~(__GFP_DMA | __GFP_HIGHMEM | __GFP_DMA32);
-   flag |= __GFP_ZERO;
-
-   page = alloc_pages(flag | __GFP_NOWARN,  get_order(size));
-   if (!page) {
-   if (!gfpflags_allow_blocking(flag))
-   return NULL;
-
-   page = dma_alloc_from_contiguous(dev, size >> PAGE_SHIFT,
-get_order(size), flag);
-   if (!page)
+   if (IS_ERR(domain)) {
+   if (PTR_ERR(domain) != -EINVAL)
return NULL;
+   is_direct = true;
}
 
+   virt_addr = dma_direct_alloc(dev, size, dma_addr, flag, attrs);
+   if (!virt_addr || is_direct)
+   return virt_addr;
+
if (!dma_mask)
dma_mask = *dev->dma_mask;
 
-   *dma_addr = __map_single(dev, dma_dom, page_to_phys(page),
-size, DMA_BIDIRECTIONAL, dma_mask);
-
+   *dma_addr = __map_single(dev, to_dma_ops_domain(domain),
+   virt_to_phys(virt_addr), PAGE_ALIGN(size),
+   DMA_BIDIRECTIONAL, dma_mask);
if (*dma_addr == AMD_IOMMU_MAPPING_ERROR)
goto out_free;
-
-   return page_address(page);
+   return virt_addr;
 
 out_free:
-
-   if (!dma_release_from_contiguous(dev, page, size >> PAGE_SHIFT))
-   __free_pages(page, get_order(size));
-
+   dma_direct_free(dev, size, virt_addr, *dma_addr, attrs);
return NULL;
 }
 
@@ -2655,24 +2636,17 @@ static void free_coherent(struct device *dev, size_t 
size,
  void *virt_addr, dma_addr_t dma_addr,
  unsigned long attrs)
 {
-   struct protection_domain *domain;
-   struct dma_ops_domain *dma_dom;
-   struct page *page;
+   struct protection_domain *domain = get_domain(dev);
 
-   page = virt_to_page(virt_addr);
size = PAGE_ALIGN(size);
 
-   domain = get_domain(dev);
-   if (IS_ERR(domain))
-   goto free_mem;
+   if (!IS_ERR(domain)) {
+   struct dma_ops_domain *dma_dom = to_dma_ops_domain(domain);
 
-   dma_dom = to_dma_ops_domain(domain);
-
-   __unmap_single(dma_dom, dma_addr, size, DMA_BIDIRECTIONAL);
+   __unmap_single(dma_dom, dma_addr, size, DMA_BIDIRECTIONAL);
+   }
 
-free_mem:
-   if (!dma_release_from_contiguous(dev, page, size >> PAGE_SHIFT))
-   __free_pages(page, get_order(size));
+   dma_direct_free(dev, size, virt_addr, dma_addr, attrs);
 }
 
 /*
-- 
2.14.2

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


[PATCH 02/13] x86: remove dma_alloc_coherent_mask

2018-03-05 Thread Christoph Hellwig
These days all devices (including the ISA fallback device) have a coherent
DMA mask set, so remove the workaround.

Signed-off-by: Christoph Hellwig 
---
 arch/x86/include/asm/dma-mapping.h | 18 ++
 arch/x86/kernel/pci-dma.c  | 10 --
 arch/x86/mm/mem_encrypt.c  |  4 +---
 drivers/xen/swiotlb-xen.c  | 16 +---
 4 files changed, 8 insertions(+), 40 deletions(-)

diff --git a/arch/x86/include/asm/dma-mapping.h 
b/arch/x86/include/asm/dma-mapping.h
index 6277c83c0eb1..545bf3721bc0 100644
--- a/arch/x86/include/asm/dma-mapping.h
+++ b/arch/x86/include/asm/dma-mapping.h
@@ -44,26 +44,12 @@ extern void dma_generic_free_coherent(struct device *dev, 
size_t size,
  void *vaddr, dma_addr_t dma_addr,
  unsigned long attrs);
 
-static inline unsigned long dma_alloc_coherent_mask(struct device *dev,
-   gfp_t gfp)
-{
-   unsigned long dma_mask = 0;
-
-   dma_mask = dev->coherent_dma_mask;
-   if (!dma_mask)
-   dma_mask = (gfp & GFP_DMA) ? DMA_BIT_MASK(24) : 
DMA_BIT_MASK(32);
-
-   return dma_mask;
-}
-
 static inline gfp_t dma_alloc_coherent_gfp_flags(struct device *dev, gfp_t gfp)
 {
-   unsigned long dma_mask = dma_alloc_coherent_mask(dev, gfp);
-
-   if (dma_mask <= DMA_BIT_MASK(24))
+   if (dev->coherent_dma_mask <= DMA_BIT_MASK(24))
gfp |= GFP_DMA;
 #ifdef CONFIG_X86_64
-   if (dma_mask <= DMA_BIT_MASK(32) && !(gfp & GFP_DMA))
+   if (dev->coherent_dma_mask <= DMA_BIT_MASK(32) && !(gfp & GFP_DMA))
gfp |= GFP_DMA32;
 #endif
return gfp;
diff --git a/arch/x86/kernel/pci-dma.c b/arch/x86/kernel/pci-dma.c
index df7ab02f959f..b59820872ec7 100644
--- a/arch/x86/kernel/pci-dma.c
+++ b/arch/x86/kernel/pci-dma.c
@@ -80,13 +80,10 @@ void *dma_generic_alloc_coherent(struct device *dev, size_t 
size,
 dma_addr_t *dma_addr, gfp_t flag,
 unsigned long attrs)
 {
-   unsigned long dma_mask;
struct page *page;
unsigned int count = PAGE_ALIGN(size) >> PAGE_SHIFT;
dma_addr_t addr;
 
-   dma_mask = dma_alloc_coherent_mask(dev, flag);
-
 again:
page = NULL;
/* CMA can be used only in the context which permits sleeping */
@@ -95,7 +92,7 @@ void *dma_generic_alloc_coherent(struct device *dev, size_t 
size,
 flag);
if (page) {
addr = phys_to_dma(dev, page_to_phys(page));
-   if (addr + size > dma_mask) {
+   if (addr + size > dev->coherent_dma_mask) {
dma_release_from_contiguous(dev, page, count);
page = NULL;
}
@@ -108,10 +105,11 @@ void *dma_generic_alloc_coherent(struct device *dev, 
size_t size,
return NULL;
 
addr = phys_to_dma(dev, page_to_phys(page));
-   if (addr + size > dma_mask) {
+   if (addr + size > dev->coherent_dma_mask) {
__free_pages(page, get_order(size));
 
-   if (dma_mask < DMA_BIT_MASK(32) && !(flag & GFP_DMA)) {
+   if (dev->coherent_dma_mask < DMA_BIT_MASK(32) &&
+   !(flag & GFP_DMA)) {
flag = (flag & ~GFP_DMA32) | GFP_DMA;
goto again;
}
diff --git a/arch/x86/mm/mem_encrypt.c b/arch/x86/mm/mem_encrypt.c
index 1a53071e2e17..75dc8b525c12 100644
--- a/arch/x86/mm/mem_encrypt.c
+++ b/arch/x86/mm/mem_encrypt.c
@@ -203,12 +203,10 @@ void __init sme_early_init(void)
 static void *sev_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle,
   gfp_t gfp, unsigned long attrs)
 {
-   unsigned long dma_mask;
unsigned int order;
struct page *page;
void *vaddr = NULL;
 
-   dma_mask = dma_alloc_coherent_mask(dev, gfp);
order = get_order(size);
 
/*
@@ -226,7 +224,7 @@ static void *sev_alloc(struct device *dev, size_t size, 
dma_addr_t *dma_handle,
 * mask with it already cleared.
 */
addr = __sme_clr(phys_to_dma(dev, page_to_phys(page)));
-   if ((addr + size) > dma_mask) {
+   if ((addr + size) > dev->coherent_dma_mask) {
__free_pages(page, get_order(size));
} else {
vaddr = page_address(page);
diff --git a/drivers/xen/swiotlb-xen.c b/drivers/xen/swiotlb-xen.c
index 5bb72d3f8337..e1c60899fdbc 100644
--- a/drivers/xen/swiotlb-xen.c
+++ b/drivers/xen/swiotlb-xen.c
@@ -53,20 +53,6 @@
  * API.
  */
 
-#ifndef CONFIG_X86
-static unsigned long dma_alloc_coherent_mask(struct device *dev,
-   gfp_t gfp)
-{
-   unsigned long dma_mask = 

[PATCH 08/13] iommu/intel-iommu: cleanup intel_{alloc,free}_coherent

2018-03-05 Thread Christoph Hellwig
Use the dma_direct_* helpers and cleanup the code flow.

Signed-off-by: Christoph Hellwig 
---
 drivers/iommu/Kconfig   |  1 +
 drivers/iommu/intel-iommu.c | 62 -
 2 files changed, 17 insertions(+), 46 deletions(-)

diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index dc7c1914645d..df171cb85822 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -143,6 +143,7 @@ config DMAR_TABLE
 config INTEL_IOMMU
bool "Support for Intel IOMMU using DMA Remapping Devices"
depends on PCI_MSI && ACPI && (X86 || IA64_GENERIC)
+   select DMA_DIRECT_OPS
select IOMMU_API
select IOMMU_IOVA
select DMAR_TABLE
diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index fd899b2a12bb..24d1b1b42013 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -31,6 +31,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -3708,61 +3709,30 @@ static void *intel_alloc_coherent(struct device *dev, 
size_t size,
  dma_addr_t *dma_handle, gfp_t flags,
  unsigned long attrs)
 {
-   struct page *page = NULL;
-   int order;
-
-   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_BIT_MASK(32))
-   flags |= GFP_DMA;
-   else
-   flags |= GFP_DMA32;
-   }
+   void *vaddr;
 
-   if (gfpflags_allow_blocking(flags)) {
-   unsigned int count = size >> PAGE_SHIFT;
+   vaddr = dma_direct_alloc(dev, size, dma_handle, flags, attrs);
+   if (iommu_no_mapping(dev) || !vaddr)
+   return vaddr;
 
-   page = dma_alloc_from_contiguous(dev, count, order, flags);
-   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)
-   page = alloc_pages(flags, order);
-   if (!page)
-   return NULL;
-   memset(page_address(page), 0, size);
-
-   *dma_handle = __intel_map_single(dev, page_to_phys(page), size,
-DMA_BIDIRECTIONAL,
-dev->coherent_dma_mask);
-   if (*dma_handle)
-   return page_address(page);
-   if (!dma_release_from_contiguous(dev, page, size >> PAGE_SHIFT))
-   __free_pages(page, order);
+   *dma_handle = __intel_map_single(dev, virt_to_phys(vaddr),
+   PAGE_ALIGN(size), DMA_BIDIRECTIONAL,
+   dev->coherent_dma_mask);
+   if (!*dma_handle)
+   goto out_free_pages;
+   return vaddr;
 
+out_free_pages:
+   dma_direct_free(dev, size, vaddr, *dma_handle, attrs);
return NULL;
 }
 
 static void intel_free_coherent(struct device *dev, size_t size, void *vaddr,
dma_addr_t dma_handle, unsigned long attrs)
 {
-   int order;
-   struct page *page = virt_to_page(vaddr);
-
-   size = PAGE_ALIGN(size);
-   order = get_order(size);
-
-   intel_unmap(dev, dma_handle, size);
-   if (!dma_release_from_contiguous(dev, page, size >> PAGE_SHIFT))
-   __free_pages(page, order);
+   if (!iommu_no_mapping(dev))
+   intel_unmap(dev, dma_handle, PAGE_ALIGN(size));
+   dma_direct_free(dev, size, vaddr, dma_handle, attrs);
 }
 
 static void intel_unmap_sg(struct device *dev, struct scatterlist *sglist,
-- 
2.14.2

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


[PATCH 09/13] x86: remove dma_alloc_coherent_gfp_flags

2018-03-05 Thread Christoph Hellwig
All dma_ops implementations used on x86 now take care of setting their own
required GFP_ masks for the allocation.  And given that the common code
now clears harmful flags itself that means we can stop the flags in all
the iommu implementations as well.

Signed-off-by: Christoph Hellwig 
---
 arch/x86/include/asm/dma-mapping.h | 11 ---
 arch/x86/kernel/pci-calgary_64.c   |  2 --
 arch/x86/kernel/pci-dma.c  |  2 --
 arch/x86/mm/mem_encrypt.c  |  7 ---
 4 files changed, 22 deletions(-)

diff --git a/arch/x86/include/asm/dma-mapping.h 
b/arch/x86/include/asm/dma-mapping.h
index df9816b385eb..89ce4bfd241f 100644
--- a/arch/x86/include/asm/dma-mapping.h
+++ b/arch/x86/include/asm/dma-mapping.h
@@ -36,15 +36,4 @@ int arch_dma_supported(struct device *dev, u64 mask);
 bool arch_dma_alloc_attrs(struct device **dev, gfp_t *gfp);
 #define arch_dma_alloc_attrs arch_dma_alloc_attrs
 
-static inline gfp_t dma_alloc_coherent_gfp_flags(struct device *dev, gfp_t gfp)
-{
-   if (dev->coherent_dma_mask <= DMA_BIT_MASK(24))
-   gfp |= GFP_DMA;
-#ifdef CONFIG_X86_64
-   if (dev->coherent_dma_mask <= DMA_BIT_MASK(32) && !(gfp & GFP_DMA))
-   gfp |= GFP_DMA32;
-#endif
-   return gfp;
-}
-
 #endif
diff --git a/arch/x86/kernel/pci-calgary_64.c b/arch/x86/kernel/pci-calgary_64.c
index 5647853053bd..bbfc8b1e9104 100644
--- a/arch/x86/kernel/pci-calgary_64.c
+++ b/arch/x86/kernel/pci-calgary_64.c
@@ -446,8 +446,6 @@ static void* calgary_alloc_coherent(struct device *dev, 
size_t size,
npages = size >> PAGE_SHIFT;
order = get_order(size);
 
-   flag &= ~(__GFP_DMA | __GFP_HIGHMEM | __GFP_DMA32);
-
/* alloc enough pages (and possibly more) */
ret = (void *)__get_free_pages(flag, order);
if (!ret)
diff --git a/arch/x86/kernel/pci-dma.c b/arch/x86/kernel/pci-dma.c
index db0b88ea8d1b..14437116ffea 100644
--- a/arch/x86/kernel/pci-dma.c
+++ b/arch/x86/kernel/pci-dma.c
@@ -82,8 +82,6 @@ bool arch_dma_alloc_attrs(struct device **dev, gfp_t *gfp)
if (!*dev)
*dev = _dma_fallback_dev;
 
-   *gfp = dma_alloc_coherent_gfp_flags(*dev, *gfp);
-
if (!is_device_dma_capable(*dev))
return false;
return true;
diff --git a/arch/x86/mm/mem_encrypt.c b/arch/x86/mm/mem_encrypt.c
index 75dc8b525c12..66beedc8fe3d 100644
--- a/arch/x86/mm/mem_encrypt.c
+++ b/arch/x86/mm/mem_encrypt.c
@@ -208,13 +208,6 @@ static void *sev_alloc(struct device *dev, size_t size, 
dma_addr_t *dma_handle,
void *vaddr = NULL;
 
order = get_order(size);
-
-   /*
-* Memory will be memset to zero after marking decrypted, so don't
-* bother clearing it before.
-*/
-   gfp &= ~__GFP_ZERO;
-
page = alloc_pages_node(dev_to_node(dev), gfp, order);
if (page) {
dma_addr_t addr;
-- 
2.14.2

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


[PATCH 01/13] x86: remove X86_PPRO_FENCE

2018-03-05 Thread Christoph Hellwig
There were only a few Pentium Pro multiprocessors systems where this
errata applied. They are more than 20 years old now, and we've slowly
dropped places where put the workarounds in and discouraged anyone
from enabling the workaround.

Get rid of it for good.

Signed-off-by: Christoph Hellwig 
---
 arch/x86/Kconfig.cpu| 13 -
 arch/x86/entry/vdso/vdso32/vclock_gettime.c |  2 --
 arch/x86/include/asm/barrier.h  | 30 -
 arch/x86/include/asm/io.h   | 15 ---
 arch/x86/kernel/pci-nommu.c | 19 --
 arch/x86/um/asm/barrier.h   |  4 
 6 files changed, 83 deletions(-)

diff --git a/arch/x86/Kconfig.cpu b/arch/x86/Kconfig.cpu
index 8b8d2297d486..638411f22267 100644
--- a/arch/x86/Kconfig.cpu
+++ b/arch/x86/Kconfig.cpu
@@ -315,19 +315,6 @@ config X86_L1_CACHE_SHIFT
default "4" if MELAN || M486 || MGEODEGX1
default "5" if MWINCHIP3D || MWINCHIPC6 || MCRUSOE || MEFFICEON || 
MCYRIXIII || MK6 || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || 
M586 || MVIAC3_2 || MGEODE_LX
 
-config X86_PPRO_FENCE
-   bool "PentiumPro memory ordering errata workaround"
-   depends on M686 || M586MMX || M586TSC || M586 || M486 || MGEODEGX1
-   ---help---
- Old PentiumPro multiprocessor systems had errata that could cause
- memory operations to violate the x86 ordering standard in rare cases.
- Enabling this option will attempt to work around some (but not all)
- occurrences of this problem, at the cost of much heavier spinlock and
- memory barrier operations.
-
- If unsure, say n here. Even distro kernels should think twice before
- enabling this: there are few systems, and an unlikely bug.
-
 config X86_F00F_BUG
def_bool y
depends on M586MMX || M586TSC || M586 || M486
diff --git a/arch/x86/entry/vdso/vdso32/vclock_gettime.c 
b/arch/x86/entry/vdso/vdso32/vclock_gettime.c
index 7780bbfb06ef..9242b28418d5 100644
--- a/arch/x86/entry/vdso/vdso32/vclock_gettime.c
+++ b/arch/x86/entry/vdso/vdso32/vclock_gettime.c
@@ -5,8 +5,6 @@
 #undef CONFIG_OPTIMIZE_INLINING
 #endif
 
-#undef CONFIG_X86_PPRO_FENCE
-
 #ifdef CONFIG_X86_64
 
 /*
diff --git a/arch/x86/include/asm/barrier.h b/arch/x86/include/asm/barrier.h
index e1259f043ae9..042b5e892ed1 100644
--- a/arch/x86/include/asm/barrier.h
+++ b/arch/x86/include/asm/barrier.h
@@ -52,11 +52,7 @@ static inline unsigned long array_index_mask_nospec(unsigned 
long index,
 #define barrier_nospec() alternative_2("", "mfence", X86_FEATURE_MFENCE_RDTSC, 
\
   "lfence", X86_FEATURE_LFENCE_RDTSC)
 
-#ifdef CONFIG_X86_PPRO_FENCE
-#define dma_rmb()  rmb()
-#else
 #define dma_rmb()  barrier()
-#endif
 #define dma_wmb()  barrier()
 
 #ifdef CONFIG_X86_32
@@ -68,30 +64,6 @@ static inline unsigned long array_index_mask_nospec(unsigned 
long index,
 #define __smp_wmb()barrier()
 #define __smp_store_mb(var, value) do { (void)xchg(, value); } while (0)
 
-#if defined(CONFIG_X86_PPRO_FENCE)
-
-/*
- * For this option x86 doesn't have a strong TSO memory
- * model and we should fall back to full barriers.
- */
-
-#define __smp_store_release(p, v)  \
-do {   \
-   compiletime_assert_atomic_type(*p); \
-   __smp_mb(); \
-   WRITE_ONCE(*p, v);  \
-} while (0)
-
-#define __smp_load_acquire(p)  \
-({ \
-   typeof(*p) ___p1 = READ_ONCE(*p);   \
-   compiletime_assert_atomic_type(*p); \
-   __smp_mb(); \
-   ___p1;  \
-})
-
-#else /* regular x86 TSO memory ordering */
-
 #define __smp_store_release(p, v)  \
 do {   \
compiletime_assert_atomic_type(*p); \
@@ -107,8 +79,6 @@ do { 
\
___p1;  \
 })
 
-#endif
-
 /* Atomic operations are already serializing on x86 */
 #define __smp_mb__before_atomic()  barrier()
 #define __smp_mb__after_atomic()   barrier()
diff --git a/arch/x86/include/asm/io.h b/arch/x86/include/asm/io.h
index 95e948627fd0..f6e5b9375d8c 100644
--- a/arch/x86/include/asm/io.h
+++ b/arch/x86/include/asm/io.h
@@ -232,21 +232,6 @@ extern void set_iounmap_nonlazy(void);
  */
 #define __ISA_IO_base ((char __iomem 

[PATCH 03/13] x86: use dma-direct

2018-03-05 Thread Christoph Hellwig
The generic dma-direct implementation is now functionally equivalent to
the x86 nommu dma_map implementation, so switch over to using it.

Note that the various iommu drivers are switched from x86_dma_supported
to dma_direct_supported to provide identical functionality, although the
checks looks fairly questionable for at least some of them.

Signed-off-by: Christoph Hellwig 
---
 arch/x86/Kconfig   |  1 +
 arch/x86/include/asm/dma-mapping.h |  8 -
 arch/x86/include/asm/iommu.h   |  3 --
 arch/x86/kernel/Makefile   |  2 +-
 arch/x86/kernel/amd_gart_64.c  |  7 ++--
 arch/x86/kernel/pci-calgary_64.c   |  3 +-
 arch/x86/kernel/pci-dma.c  | 66 +-
 arch/x86/kernel/pci-swiotlb.c  |  5 ++-
 arch/x86/pci/sta2x11-fixup.c   |  2 +-
 drivers/iommu/amd_iommu.c  |  7 ++--
 drivers/iommu/intel-iommu.c|  3 +-
 11 files changed, 17 insertions(+), 90 deletions(-)

diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index c1236b187824..7272bb3768d7 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -83,6 +83,7 @@ config X86
select CLOCKSOURCE_VALIDATE_LAST_CYCLE
select CLOCKSOURCE_WATCHDOG
select DCACHE_WORD_ACCESS
+   select DMA_DIRECT_OPS
select EDAC_ATOMIC_SCRUB
select EDAC_SUPPORT
select GENERIC_CLOCKEVENTS
diff --git a/arch/x86/include/asm/dma-mapping.h 
b/arch/x86/include/asm/dma-mapping.h
index 545bf3721bc0..df9816b385eb 100644
--- a/arch/x86/include/asm/dma-mapping.h
+++ b/arch/x86/include/asm/dma-mapping.h
@@ -36,14 +36,6 @@ int arch_dma_supported(struct device *dev, u64 mask);
 bool arch_dma_alloc_attrs(struct device **dev, gfp_t *gfp);
 #define arch_dma_alloc_attrs arch_dma_alloc_attrs
 
-extern void *dma_generic_alloc_coherent(struct device *dev, size_t size,
-   dma_addr_t *dma_addr, gfp_t flag,
-   unsigned long attrs);
-
-extern void dma_generic_free_coherent(struct device *dev, size_t size,
- void *vaddr, dma_addr_t dma_addr,
- unsigned long attrs);
-
 static inline gfp_t dma_alloc_coherent_gfp_flags(struct device *dev, gfp_t gfp)
 {
if (dev->coherent_dma_mask <= DMA_BIT_MASK(24))
diff --git a/arch/x86/include/asm/iommu.h b/arch/x86/include/asm/iommu.h
index 1e5d5d92eb40..baedab8ac538 100644
--- a/arch/x86/include/asm/iommu.h
+++ b/arch/x86/include/asm/iommu.h
@@ -2,13 +2,10 @@
 #ifndef _ASM_X86_IOMMU_H
 #define _ASM_X86_IOMMU_H
 
-extern const struct dma_map_ops nommu_dma_ops;
 extern int force_iommu, no_iommu;
 extern int iommu_detected;
 extern int iommu_pass_through;
 
-int x86_dma_supported(struct device *dev, u64 mask);
-
 /* 10 seconds */
 #define DMAR_OPERATION_TIMEOUT ((cycles_t) tsc_khz*10*1000)
 
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
index 29786c87e864..2e8c8a09ecab 100644
--- a/arch/x86/kernel/Makefile
+++ b/arch/x86/kernel/Makefile
@@ -57,7 +57,7 @@ obj-$(CONFIG_X86_ESPFIX64)+= espfix_64.o
 obj-$(CONFIG_SYSFS)+= ksysfs.o
 obj-y  += bootflag.o e820.o
 obj-y  += pci-dma.o quirks.o topology.o kdebugfs.o
-obj-y  += alternative.o i8253.o pci-nommu.o hw_breakpoint.o
+obj-y  += alternative.o i8253.o hw_breakpoint.o
 obj-y  += tsc.o tsc_msr.o io_delay.o rtc.o
 obj-y  += pci-iommu_table.o
 obj-y  += resource.o
diff --git a/arch/x86/kernel/amd_gart_64.c b/arch/x86/kernel/amd_gart_64.c
index ecd486cb06ab..52e3abcf3e70 100644
--- a/arch/x86/kernel/amd_gart_64.c
+++ b/arch/x86/kernel/amd_gart_64.c
@@ -501,8 +501,7 @@ gart_alloc_coherent(struct device *dev, size_t size, 
dma_addr_t *dma_addr,
}
__free_pages(page, get_order(size));
} else
-   return dma_generic_alloc_coherent(dev, size, dma_addr, flag,
- attrs);
+   return dma_direct_alloc(dev, size, dma_addr, flag, attrs);
 
return NULL;
 }
@@ -513,7 +512,7 @@ gart_free_coherent(struct device *dev, size_t size, void 
*vaddr,
   dma_addr_t dma_addr, unsigned long attrs)
 {
gart_unmap_page(dev, dma_addr, size, DMA_BIDIRECTIONAL, 0);
-   dma_generic_free_coherent(dev, size, vaddr, dma_addr, attrs);
+   dma_direct_free(dev, size, vaddr, dma_addr, attrs);
 }
 
 static int gart_mapping_error(struct device *dev, dma_addr_t dma_addr)
@@ -705,7 +704,7 @@ static const struct dma_map_ops gart_dma_ops = {
.alloc  = gart_alloc_coherent,
.free   = gart_free_coherent,
.mapping_error  = gart_mapping_error,
-   .dma_supported  = x86_dma_supported,
+   .dma_supported  = dma_direct_supported,
 };
 
 static void gart_iommu_shutdown(void)
diff 

[PATCH 06/13] x86/amd_gart: use dma_direct_{alloc,free}

2018-03-05 Thread Christoph Hellwig
This gains support for CMA allocations for the force_iommu case, and
cleans up the code a bit.

Signed-off-by: Christoph Hellwig 
---
 arch/x86/kernel/amd_gart_64.c | 36 ++--
 1 file changed, 14 insertions(+), 22 deletions(-)

diff --git a/arch/x86/kernel/amd_gart_64.c b/arch/x86/kernel/amd_gart_64.c
index 79ac6cbb..f299d8a479bb 100644
--- a/arch/x86/kernel/amd_gart_64.c
+++ b/arch/x86/kernel/amd_gart_64.c
@@ -480,29 +480,21 @@ static void *
 gart_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_addr,
gfp_t flag, unsigned long attrs)
 {
-   dma_addr_t paddr;
-   unsigned long align_mask;
-   struct page *page;
-
-   if (force_iommu && dev->coherent_dma_mask > DMA_BIT_MASK(24)) {
-   flag &= ~(__GFP_DMA | __GFP_HIGHMEM | __GFP_DMA32);
-   page = alloc_pages(flag | __GFP_ZERO, get_order(size));
-   if (!page)
-   return NULL;
-
-   align_mask = (1UL << get_order(size)) - 1;
-   paddr = dma_map_area(dev, page_to_phys(page), size,
-DMA_BIDIRECTIONAL, align_mask);
-
-   flush_gart();
-   if (paddr != bad_dma_addr) {
-   *dma_addr = paddr;
-   return page_address(page);
-   }
-   __free_pages(page, get_order(size));
-   } else
-   return dma_direct_alloc(dev, size, dma_addr, flag, attrs);
+   void *vaddr;
+
+   vaddr = dma_direct_alloc(dev, size, dma_addr, flag, attrs);
+   if (!vaddr ||
+   !force_iommu || dev->coherent_dma_mask <= DMA_BIT_MASK(24))
+   return vaddr;
 
+   *dma_addr = dma_map_area(dev, virt_to_phys(vaddr), size,
+   DMA_BIDIRECTIONAL, (1UL << get_order(size)) - 1);
+   flush_gart();
+   if (unlikely(*dma_addr == bad_dma_addr))
+   goto out_free;
+   return vaddr;
+out_free:
+   dma_direct_free(dev, size, vaddr, *dma_addr, attrs);
return NULL;
 }
 
-- 
2.14.2

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


Re: [PATCH v8 0/5] iommu/arm-smmu: Add runtime pm/sleep support

2018-03-05 Thread Vivek Gautam

Hi Tomasz,


On 3/5/2018 6:55 PM, Tomasz Figa wrote:

Hi Vivek,

On Fri, Mar 2, 2018 at 7:10 PM, Vivek Gautam
 wrote:

This series provides the support for turning on the arm-smmu's
clocks/power domains using runtime pm. This is done using the
recently introduced device links patches, which lets the smmu's
runtime to follow the master's runtime pm, so the smmu remains
powered only when the masters use it.

It also adds support for Qcom's arm-smmu-v2 variant that
has different clocks and power requirements.

Took some reference from the exynos runtime patches [1].

After another round of discussion [3], we now finally seem to be
in agreement to add a flag based on compatible, a flag that would
indicate if a particular implementation of arm-smmu supports
runtime pm or not.
This lets us to use the much-argued pm_runtime_get_sync/put_sync()
calls in map/unmap callbacks so that the clients do not have to
worry about handling any of the arm-smmu's power.
The patch that exported couple of pm_runtime suppliers APIS, viz.
pm_runtime_get_suppliers(), and pm_runtime_put_suppliers() can be
dropped since we don't have a user now for these APIs.
Thanks Rafael for reviewing the changes, but looks like we don't
need to export those APIs for some more time. :)

Previous version of this patch series is @ [5].

Thanks for addressing my comments. There is still a bit of space for
improving the granularity of power management, as far as I understood
how it works on SDM845 correctly, but as a first step, this should at
least let things work.


Sure. I will be sending a patch, based on this series, to add 
'qcom,smmu-500'

that enables *rpm_suported* flag for us.
We can try to take care of some of the things with that.

Reviewed-by: Tomasz Figa 


Thanks for the review.

regards
Vivek


Best regards,
Tomasz


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


RE: [PATCH 1/6] Docs: dt: add fsl-mc iommu-parent device-tree binding

2018-03-05 Thread Nipun Gupta


> -Original Message-
> From: Robin Murphy [mailto:robin.mur...@arm.com]
> Sent: Monday, March 05, 2018 21:07
> To: Nipun Gupta ; will.dea...@arm.com;
> mark.rutl...@arm.com; catalin.mari...@arm.com
> Cc: iommu@lists.linux-foundation.org; robh...@kernel.org; h...@lst.de;
> m.szyprow...@samsung.com; gre...@linuxfoundation.org; j...@8bytes.org;
> Leo Li ; shawn...@kernel.org; linux-
> ker...@vger.kernel.org; devicet...@vger.kernel.org; linux-arm-
> ker...@lists.infradead.org; linuxppc-...@lists.ozlabs.org; Bharat Bhushan
> ; stuyo...@gmail.com; Laurentiu Tudor
> 
> Subject: Re: [PATCH 1/6] Docs: dt: add fsl-mc iommu-parent device-tree binding
> 
> On 05/03/18 15:00, Nipun Gupta wrote:
> >
> >
> >> -Original Message-
> >> From: Robin Murphy [mailto:robin.mur...@arm.com]
> >> Sent: Monday, March 05, 2018 20:23
> >> To: Nipun Gupta ; will.dea...@arm.com;
> >> mark.rutl...@arm.com; catalin.mari...@arm.com
> >> Cc: iommu@lists.linux-foundation.org; robh...@kernel.org; h...@lst.de;
> >> m.szyprow...@samsung.com; gre...@linuxfoundation.org;
> j...@8bytes.org;
> >> Leo Li ; shawn...@kernel.org; linux-
> >> ker...@vger.kernel.org; devicet...@vger.kernel.org; linux-arm-
> >> ker...@lists.infradead.org; linuxppc-...@lists.ozlabs.org; Bharat Bhushan
> >> ; stuyo...@gmail.com; Laurentiu Tudor
> >> 
> >> Subject: Re: [PATCH 1/6] Docs: dt: add fsl-mc iommu-parent device-tree
> binding
> >>
> >> On 05/03/18 14:29, Nipun Gupta wrote:
> >>> The existing IOMMU bindings cannot be used to specify the relationship
> >>> between fsl-mc devices and IOMMUs. This patch adds a binding for
> >>> mapping fsl-mc devices to IOMMUs, using a new iommu-parent property.
> >>
> >> Given that allowing "msi-parent" for #msi-cells > 1 is merely a
> >> backward-compatibility bodge full of hard-coded assumptions, why would
> >> we want to knowingly introduce a similarly unpleasant equivalent for
> >> IOMMUs? What's wrong with "iommu-map"?
> >
> > Hi Robin,
> >
> > With 'msi-parent' the property is fixed up to have msi-map. In this case 
> > there is
> > no fixup required and simple 'iommu-parent' property can be used, with MC
> bus
> > itself providing the stream-id's (in the code execution via FW).
> >
> > We can also use the iommu-map property similar to PCI, which will require u-
> boot
> > fixup. But then it leads to little bit complications of u-boot - kernel
> compatibility.
> 
> What needs fixing up? With a stream-map-mask in place to ignore the
> upper Stream ID bits, you just need:
> 
>   iommu-map = <0  0 0x80>;
> 
> to say that the lower bits of the ICID value map directly to the lower
> bits of the Stream ID value - that's the same fixed property of the
> hardware that you're wanting to assume in iommu-parent.

Makes sense. I was going in a little bit wrong direction. Thanks for correcting.
I will send v2 patchset with iommu-map property.

Regards,
Nipun

> 
> > If you suggest we can re-use the iommu-map property. What is your opinion?
> 
> I think it makes a lot more sense to directly use the property which
> already exists, than to introduce a new one to merely assume one
> hard-coded value of the existing one. Extending msi-parent to msi-map
> was a case of "oops, it turns out we need more flexibility here"; for
> the case of iommu-map I can't imagine any justification for saying
> "oops, we need less flexibility here" (saving 9 whole bytes in the DT
> really is irrelevant).
> 
> Robin.
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH 5/6] dma-mapping: support fsl-mc bus

2018-03-05 Thread Robin Murphy

On 05/03/18 15:08, Christoph Hellwig wrote:

We should not add any new hardocded busses here.  Please mark them in
OF/ACPI.


Unfortunately for us, fsl-mc is conceptually rather like PCI in that 
it's software-discoverable and the only thing described in DT is the bus 
"host", thus we need the same sort of thing as for PCI to map from the 
child devices back to the bus root in order to find the appropriate 
firmware node. Worse than PCI, though, we wouldn't even have the option 
of describing child devices statically in firmware at all, since it's 
actually one of these runtime-configurable "build your own network 
accelerator" hardware pools where userspace gets to create and destroy 
"devices" as it likes.


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


Re: WARN_ON(irqs_disabled()) in dma_free_attrs?

2018-03-05 Thread Christoph Hellwig
On Sat, Mar 03, 2018 at 07:19:06PM +0100, Fredrik Noring wrote:
> Christoph, Alan,
> 
> > If it is allocating / freeing this memory all the time in the hot path
> > it should really use a dma pool (see include/ilinux/dmapool.h).
> > The dma coherent APIs aren't really built for being called in the
> > hot path.
> 
> hcd_buffer_free uses a combination of dma pools and dma coherent APIs:
> 
>   ...
>   for (i = 0; i < HCD_BUFFER_POOLS; i++) {
>   if (size <= pool_max[i]) {
>   dma_pool_free(hcd->pool[i], addr, dma);
>   return;
>   }
>   }
>   dma_free_coherent(hcd->self.sysdev, size, addr, dma);
> 
> Alan, can dma_free_coherent be delayed to a point when IRQs are enabled?

The point is that you should always use a pool, period.
dma_alloc*/dma_free* are fundamentally expensive operations on my
architectures, so if you call them from a fast path you are doing
something wrong.
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH 5/6] dma-mapping: support fsl-mc bus

2018-03-05 Thread Christoph Hellwig
We should not add any new hardocded busses here.  Please mark them in
OF/ACPI.
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


RE: [PATCH 1/6] Docs: dt: add fsl-mc iommu-parent device-tree binding

2018-03-05 Thread Nipun Gupta


> -Original Message-
> From: Robin Murphy [mailto:robin.mur...@arm.com]
> Sent: Monday, March 05, 2018 20:23
> To: Nipun Gupta ; will.dea...@arm.com;
> mark.rutl...@arm.com; catalin.mari...@arm.com
> Cc: iommu@lists.linux-foundation.org; robh...@kernel.org; h...@lst.de;
> m.szyprow...@samsung.com; gre...@linuxfoundation.org; j...@8bytes.org;
> Leo Li ; shawn...@kernel.org; linux-
> ker...@vger.kernel.org; devicet...@vger.kernel.org; linux-arm-
> ker...@lists.infradead.org; linuxppc-...@lists.ozlabs.org; Bharat Bhushan
> ; stuyo...@gmail.com; Laurentiu Tudor
> 
> Subject: Re: [PATCH 1/6] Docs: dt: add fsl-mc iommu-parent device-tree binding
> 
> On 05/03/18 14:29, Nipun Gupta wrote:
> > The existing IOMMU bindings cannot be used to specify the relationship
> > between fsl-mc devices and IOMMUs. This patch adds a binding for
> > mapping fsl-mc devices to IOMMUs, using a new iommu-parent property.
> 
> Given that allowing "msi-parent" for #msi-cells > 1 is merely a
> backward-compatibility bodge full of hard-coded assumptions, why would
> we want to knowingly introduce a similarly unpleasant equivalent for
> IOMMUs? What's wrong with "iommu-map"?

Hi Robin,

With 'msi-parent' the property is fixed up to have msi-map. In this case there 
is
no fixup required and simple 'iommu-parent' property can be used, with MC bus
itself providing the stream-id's (in the code execution via FW).

We can also use the iommu-map property similar to PCI, which will require u-boot
fixup. But then it leads to little bit complications of u-boot - kernel 
compatibility.

If you suggest we can re-use the iommu-map property. What is your opinion?

Thanks,
Nipun

> 
> > Signed-off-by: Nipun Gupta 
> > ---
> >   .../devicetree/bindings/misc/fsl,qoriq-mc.txt  | 31
> ++
> >   1 file changed, 31 insertions(+)
> >
> > diff --git a/Documentation/devicetree/bindings/misc/fsl,qoriq-mc.txt
> b/Documentation/devicetree/bindings/misc/fsl,qoriq-mc.txt
> > index 6611a7c..011c7d6 100644
> > --- a/Documentation/devicetree/bindings/misc/fsl,qoriq-mc.txt
> > +++ b/Documentation/devicetree/bindings/misc/fsl,qoriq-mc.txt
> > @@ -9,6 +9,24 @@ blocks that can be used to create functional hardware
> objects/devices
> >   such as network interfaces, crypto accelerator instances, L2 switches,
> >   etc.
> >
> > +For an overview of the DPAA2 architecture and fsl-mc bus see:
> > +drivers/staging/fsl-mc/README.txt
> > +
> > +As described in the above overview, all DPAA2 objects in a DPRC share the
> > +same hardware "isolation context" and a 10-bit value called an ICID
> > +(isolation context id) is expressed by the hardware to identify
> > +the requester.
> 
> IOW, precisely the case for which "{msi,iommu}-map" exist. Yes, I know
> they're currently documented under bindings/pci, but they're not really
> intended to be absolutely PCI-specific.
> 
> Robin.
> 
> > +The generic 'iommus' property is cannot be used to describe the 
> > relationship
> > +between fsl-mc and IOMMUs, so an iommu-parent property is used to define
> > +the same.
> > +
> > +For generic IOMMU bindings, see
> > +Documentation/devicetree/bindings/iommu/iommu.txt.
> > +
> > +For arm-smmu binding, see:
> > +Documentation/devicetree/bindings/iommu/arm,smmu.txt.
> > +
> >   Required properties:
> >
> >   - compatible
> > @@ -88,14 +106,27 @@ Sub-nodes:
> > Value type: 
> > Definition: Specifies the phandle to the PHY device node 
> > associated
> > with the this dpmac.
> > +Optional properties:
> > +
> > +- iommu-parent: Maps the devices on fsl-mc bus to an IOMMU.
> > +  The property specifies the IOMMU behind which the devices on
> > +  fsl-mc bus are residing.
> >
> >   Example:
> >
> > +smmu: iommu@500 {
> > +   compatible = "arm,mmu-500";
> > +   #iommu-cells = <1>;
> > +   stream-match-mask = <0x7C00>;
> > +   ...
> > +};
> > +
> >   fsl_mc: fsl-mc@80c00 {
> >   compatible = "fsl,qoriq-mc";
> >   reg = <0x0008 0x0c00 0 0x40>,/* MC portal 
> > base */
> > <0x 0x0834 0 0x4>; /* MC control 
> > reg */
> >   msi-parent = <>;
> > +iommu-parent = <>;
> >   #address-cells = <3>;
> >   #size-cells = <1>;
> >
> >
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCHv3] iommu/intel: Ratelimit each dmar fault printing

2018-03-05 Thread Dmitry Safonov via iommu
Hi Joerg,

What do you think about v3?
It looks like, I can solve my softlookups with just a bit more proper
ratelimiting..

On Thu, 2018-02-15 at 19:17 +, Dmitry Safonov wrote:
> There is a ratelimit for printing, but it's incremented each time the
> cpu recives dmar fault interrupt. While one interrupt may signal
> about
> *many* faults.
> So, measuring the impact it turns out that reading/clearing one fault
> takes < 1 usec, and printing info about the fault takes ~170 msec.
> 
> Having in mind that maximum number of fault recording registers per
> remapping hardware unit is 256.. IRQ handler may run for (170*256)
> msec.
> And as fault-serving loop runs without a time limit, during servicing
> new faults may occur..
> 
> Ratelimit each fault printing rather than each irq printing.
> 
> Fixes: commit c43fce4eebae ("iommu/vt-d: Ratelimit fault handler")
> 
> BUG: spinlock lockup suspected on CPU#0, CliShell/9903
>  lock: 0x81a47440, .magic: dead4ead, .owner:
> kworker/u16:2/8915, .owner_cpu: 6
> CPU: 0 PID: 9903 Comm: CliShell
> Call Trace:$\n'
> [..] dump_stack+0x65/0x83$\n'
> [..] spin_dump+0x8f/0x94$\n'
> [..] do_raw_spin_lock+0x123/0x170$\n'
> [..] _raw_spin_lock_irqsave+0x32/0x3a$\n'
> [..] uart_chars_in_buffer+0x20/0x4d$\n'
> [..] tty_chars_in_buffer+0x18/0x1d$\n'
> [..] n_tty_poll+0x1cb/0x1f2$\n'
> [..] tty_poll+0x5e/0x76$\n'
> [..] do_select+0x363/0x629$\n'
> [..] compat_core_sys_select+0x19e/0x239$\n'
> [..] compat_SyS_select+0x98/0xc0$\n'
> [..] sysenter_dispatch+0x7/0x25$\n'
> [..]
> NMI backtrace for cpu 6
> CPU: 6 PID: 8915 Comm: kworker/u16:2
> Workqueue: dmar_fault dmar_fault_work
> Call Trace:$\n'
> [..] wait_for_xmitr+0x26/0x8f$\n'
> [..] serial8250_console_putchar+0x1c/0x2c$\n'
> [..] uart_console_write+0x40/0x4b$\n'
> [..] serial8250_console_write+0xe6/0x13f$\n'
> [..] call_console_drivers.constprop.13+0xce/0x103$\n'
> [..] console_unlock+0x1f8/0x39b$\n'
> [..] vprintk_emit+0x39e/0x3e6$\n'
> [..] printk+0x4d/0x4f$\n'
> [..] dmar_fault+0x1a8/0x1fc$\n'
> [..] dmar_fault_work+0x15/0x17$\n'
> [..] process_one_work+0x1e8/0x3a9$\n'
> [..] worker_thread+0x25d/0x345$\n'
> [..] kthread+0xea/0xf2$\n'
> [..] ret_from_fork+0x58/0x90$\n'
> 
> Cc: Alex Williamson 
> Cc: David Woodhouse 
> Cc: Ingo Molnar 
> Cc: Joerg Roedel 
> Cc: Lu Baolu 
> Cc: iommu@lists.linux-foundation.org
> Signed-off-by: Dmitry Safonov 
> ---
> Maybe it's worth to limit while(1) cycle.
> If IOMMU generates faults with equal speed as irq handler cleans
> them, it may turn into long-irq-disabled region again.
> Not sure if it can happen anyway.
> 
>  drivers/iommu/dmar.c | 8 +++-
>  1 file changed, 3 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c
> index accf58388bdb..6c4ea32ee6a9 100644
> --- a/drivers/iommu/dmar.c
> +++ b/drivers/iommu/dmar.c
> @@ -1618,17 +1618,13 @@ irqreturn_t dmar_fault(int irq, void *dev_id)
>   int reg, fault_index;
>   u32 fault_status;
>   unsigned long flag;
> - bool ratelimited;
>   static DEFINE_RATELIMIT_STATE(rs,
> DEFAULT_RATELIMIT_INTERVAL,
> DEFAULT_RATELIMIT_BURST);
>  
> - /* Disable printing, simply clear the fault when ratelimited
> */
> - ratelimited = !__ratelimit();
> -
>   raw_spin_lock_irqsave(>register_lock, flag);
>   fault_status = readl(iommu->reg + DMAR_FSTS_REG);
> - if (fault_status && !ratelimited)
> + if (fault_status && __ratelimit())
>   pr_err("DRHD: handling fault status reg %x\n",
> fault_status);
>  
>   /* TBD: ignore advanced fault log currently */
> @@ -1638,6 +1634,8 @@ irqreturn_t dmar_fault(int irq, void *dev_id)
>   fault_index = dma_fsts_fault_record_index(fault_status);
>   reg = cap_fault_reg_offset(iommu->cap);
>   while (1) {
> + /* Disable printing, simply clear the fault when
> ratelimited */
> + bool ratelimited = !__ratelimit();
>   u8 fault_reason;
>   u16 source_id;
>   u64 guest_addr;
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH 1/6] Docs: dt: add fsl-mc iommu-parent device-tree binding

2018-03-05 Thread Robin Murphy

On 05/03/18 14:29, Nipun Gupta wrote:

The existing IOMMU bindings cannot be used to specify the relationship
between fsl-mc devices and IOMMUs. This patch adds a binding for
mapping fsl-mc devices to IOMMUs, using a new iommu-parent property.


Given that allowing "msi-parent" for #msi-cells > 1 is merely a 
backward-compatibility bodge full of hard-coded assumptions, why would 
we want to knowingly introduce a similarly unpleasant equivalent for 
IOMMUs? What's wrong with "iommu-map"?



Signed-off-by: Nipun Gupta 
---
  .../devicetree/bindings/misc/fsl,qoriq-mc.txt  | 31 ++
  1 file changed, 31 insertions(+)

diff --git a/Documentation/devicetree/bindings/misc/fsl,qoriq-mc.txt 
b/Documentation/devicetree/bindings/misc/fsl,qoriq-mc.txt
index 6611a7c..011c7d6 100644
--- a/Documentation/devicetree/bindings/misc/fsl,qoriq-mc.txt
+++ b/Documentation/devicetree/bindings/misc/fsl,qoriq-mc.txt
@@ -9,6 +9,24 @@ blocks that can be used to create functional hardware 
objects/devices
  such as network interfaces, crypto accelerator instances, L2 switches,
  etc.
  
+For an overview of the DPAA2 architecture and fsl-mc bus see:

+drivers/staging/fsl-mc/README.txt
+
+As described in the above overview, all DPAA2 objects in a DPRC share the
+same hardware "isolation context" and a 10-bit value called an ICID
+(isolation context id) is expressed by the hardware to identify
+the requester.


IOW, precisely the case for which "{msi,iommu}-map" exist. Yes, I know 
they're currently documented under bindings/pci, but they're not really 
intended to be absolutely PCI-specific.


Robin.


+The generic 'iommus' property is cannot be used to describe the relationship
+between fsl-mc and IOMMUs, so an iommu-parent property is used to define
+the same.
+
+For generic IOMMU bindings, see
+Documentation/devicetree/bindings/iommu/iommu.txt.
+
+For arm-smmu binding, see:
+Documentation/devicetree/bindings/iommu/arm,smmu.txt.
+
  Required properties:
  
  - compatible

@@ -88,14 +106,27 @@ Sub-nodes:
Value type: 
Definition: Specifies the phandle to the PHY device node 
associated
with the this dpmac.
+Optional properties:
+
+- iommu-parent: Maps the devices on fsl-mc bus to an IOMMU.
+  The property specifies the IOMMU behind which the devices on
+  fsl-mc bus are residing.
  
  Example:
  
+smmu: iommu@500 {

+   compatible = "arm,mmu-500";
+   #iommu-cells = <1>;
+   stream-match-mask = <0x7C00>;
+   ...
+};
+
  fsl_mc: fsl-mc@80c00 {
  compatible = "fsl,qoriq-mc";
  reg = <0x0008 0x0c00 0 0x40>,/* MC portal base */
<0x 0x0834 0 0x4>; /* MC control reg */
  msi-parent = <>;
+iommu-parent = <>;
  #address-cells = <3>;
  #size-cells = <1>;
  


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


[bug report] iommu/arm-smmu: Make use of the iommu_register interface

2018-03-05 Thread Dan Carpenter
Hello Joerg Roedel,

This is a semi-automatic email about new static checker warnings.

The patch 9648cbc9625b: "iommu/arm-smmu: Make use of the 
iommu_register interface" from Feb 1, 2017, leads to the following 
Smatch complaint:

./drivers/iommu/arm-smmu-v3.c:1957 arm_smmu_remove_device()
warn: variable dereferenced before check 'master' (see line 1956)

./drivers/iommu/arm-smmu-v3.c
  1955  master = fwspec->iommu_priv;
  1956  smmu = master->smmu;
   
Pach adds unchecked dereference

  1957  if (master && master->ste.assigned)
^^
The old code assumes "master" can be NULL.

  1958  arm_smmu_detach_dev(dev);
  1959  iommu_group_remove_device(dev);

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


Re: [RESEND PATCH v6 13/14] iommu/rockchip: Add runtime PM support

2018-03-05 Thread Tomasz Figa
On Mon, Mar 5, 2018 at 11:13 PM, Robin Murphy  wrote:
> On 05/03/18 13:49, Tomasz Figa wrote:
> [...]
>>>
>>> @@ -518,7 +520,12 @@ static irqreturn_t rk_iommu_irq(int irq, void
>>> *dev_id)
>>>  u32 int_status;
>>>  dma_addr_t iova;
>>>  irqreturn_t ret = IRQ_NONE;
>>> -   int i;
>>> +   int i, err, need_runtime_put;
>>
>>
>> nit: need_runtime_put could be a bool.
>>
>>> +
>>> +   err = pm_runtime_get_if_in_use(iommu->dev);
>>> +   if (err <= 0 && err != -EINVAL)
>>> +   return ret;
>>> +   need_runtime_put = err > 0;
>>
>>
>> Generally something must be really wrong if we end up with err == 0
>> here, because the IOMMU must be powered on to signal an interrupt. The
>> only case this could happen would be if the IRQ signal was shared with
>> some device from another power domain. Is it possible on Rockchip
>> SoCs? If not, perhaps we should have a WARN_ON() here for such case.
>
>
> In general, there's almost certainly some time window between the interrupt
> level being latched at the GIC and the IRQ actually being taken by its
> target CPU, in which potentially the power could be removed and/or the
> clocks gated - especially if there are higher-priority IRQs pending at the
> same time and the racing PM call is on some other CPU. Sure, it's probably
> unlikely, but I wouldn't necessarily consider it completely erroneous.

Clocks are not a problem here, since the handler re-enables them and
clk_enable() is IRQ-safe. However, runtime PM might need sleeping, so
we can't just get_sync() from the handler. I guess, we should just
bail out in such case, since the power off would probably clear any
internal interrupt state anyway.

Also, the interrupt would be basically a page fault, during which the
master device would be stalled, so it's rather unlikely that we see
its driver putting the runtime PM, which would only happen after the
master device resumes and competes (or something times out). So
probably WARN_ON() isn't such bad idea still.
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH 5/6] dma-mapping: support fsl-mc bus

2018-03-05 Thread Nipun Gupta
Signed-off-by: Nipun Gupta 
---
 drivers/base/dma-mapping.c | 7 +++
 1 file changed, 7 insertions(+)

diff --git a/drivers/base/dma-mapping.c b/drivers/base/dma-mapping.c
index 3b11835..2279c4d 100644
--- a/drivers/base/dma-mapping.c
+++ b/drivers/base/dma-mapping.c
@@ -334,6 +334,7 @@ void dma_common_free_remap(void *cpu_addr, size_t size, 
unsigned long vm_flags)
  * Common configuration to enable DMA API use for a device
  */
 #include 
+#include 
 
 int dma_configure(struct device *dev)
 {
@@ -349,6 +350,12 @@ int dma_configure(struct device *dev)
dma_dev = dma_dev->parent;
}
 
+   if (dev_is_fsl_mc(dev)) {
+   dma_dev = dev;
+   while (dev_is_fsl_mc(dma_dev))
+   dma_dev = dma_dev->parent;
+   }
+
if (dma_dev->of_node) {
ret = of_dma_configure(dev, dma_dev->of_node);
} else if (has_acpi_companion(dma_dev)) {
-- 
1.9.1

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


[PATCH 6/6] dts: fsl-ls208x: updated DT with SMMU support for fsl-mc

2018-03-05 Thread Nipun Gupta
Signed-off-by: Nipun Gupta 
---
 arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi | 6 +-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi 
b/arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi
index f3a40af..1f15492 100644
--- a/arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi
+++ b/arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi
@@ -135,6 +135,7 @@
#address-cells = <2>;
#size-cells = <2>;
ranges;
+   dma-ranges = <0x0 0x0 0x0 0x0 0x1 0x>;
 
clockgen: clocking@130 {
compatible = "fsl,ls2080a-clockgen";
@@ -357,6 +358,8 @@
reg = <0x0008 0x0c00 0 0x40>,/* MC portal 
base */
  <0x 0x0834 0 0x4>; /* MC control 
reg */
msi-parent = <>;
+   iommu-parent = <>;
+   dma-coherent;
#address-cells = <3>;
#size-cells = <1>;
 
@@ -460,6 +463,8 @@
compatible = "arm,mmu-500";
reg = <0 0x500 0 0x80>;
#global-interrupts = <12>;
+   stream-match-mask = <0x7C00>;
+   dma-coherent;
interrupts = <0 13 4>, /* global secure fault */
 <0 14 4>, /* combined secure interrupt */
 <0 15 4>, /* global non-secure fault */
@@ -502,7 +507,6 @@
 <0 204 4>, <0 205 4>,
 <0 206 4>, <0 207 4>,
 <0 208 4>, <0 209 4>;
-   mmu-masters = <_mc 0x300 0>;
};
 
dspi: dspi@210 {
-- 
1.9.1

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


[PATCH 4/6] bus: fsl-mc: remove dma ops setup from driver

2018-03-05 Thread Nipun Gupta
The dma setup for fsl-mc devices is being done from device_add()
function. So, no need to call in mc bus driver.

Signed-off-by: Nipun Gupta 
---
 drivers/bus/fsl-mc/fsl-mc-bus.c | 5 +
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/drivers/bus/fsl-mc/fsl-mc-bus.c b/drivers/bus/fsl-mc/fsl-mc-bus.c
index 1b333c4..c9a239a 100644
--- a/drivers/bus/fsl-mc/fsl-mc-bus.c
+++ b/drivers/bus/fsl-mc/fsl-mc-bus.c
@@ -616,6 +616,7 @@ int fsl_mc_device_add(struct fsl_mc_obj_desc *obj_desc,
mc_dev->icid = parent_mc_dev->icid;
mc_dev->dma_mask = FSL_MC_DEFAULT_DMA_MASK;
mc_dev->dev.dma_mask = _dev->dma_mask;
+   mc_dev->dev.coherent_dma_mask = mc_dev->dma_mask;
dev_set_msi_domain(_dev->dev,
   dev_get_msi_domain(_mc_dev->dev));
}
@@ -633,10 +634,6 @@ int fsl_mc_device_add(struct fsl_mc_obj_desc *obj_desc,
goto error_cleanup_dev;
}
 
-   /* Objects are coherent, unless 'no shareability' flag set. */
-   if (!(obj_desc->flags & FSL_MC_OBJ_FLAG_NO_MEM_SHAREABILITY))
-   arch_setup_dma_ops(_dev->dev, 0, 0, NULL, true);
-
/*
 * The device-specific probe callback will get invoked by device_add()
 */
-- 
1.9.1

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


[PATCH 3/6] iommu: arm-smmu: Add support for the fsl-mc bus

2018-03-05 Thread Nipun Gupta
Implement bus specific support for the fsl-mc bus including
registering arm_smmu_ops and bus specific device add operations.

Signed-off-by: Nipun Gupta 
---
 drivers/iommu/arm-smmu.c |  7 +++
 drivers/iommu/iommu.c| 21 +
 include/linux/fsl/mc.h   |  8 
 include/linux/iommu.h|  2 ++
 4 files changed, 38 insertions(+)

diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index 69e7c60..e1d5090 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -52,6 +52,7 @@
 #include 
 
 #include 
+#include 
 
 #include "io-pgtable.h"
 #include "arm-smmu-regs.h"
@@ -1459,6 +1460,8 @@ static struct iommu_group *arm_smmu_device_group(struct 
device *dev)
 
if (dev_is_pci(dev))
group = pci_device_group(dev);
+   else if (dev_is_fsl_mc(dev))
+   group = fsl_mc_device_group(dev);
else
group = generic_device_group(dev);
 
@@ -2037,6 +2040,10 @@ static void arm_smmu_bus_init(void)
bus_set_iommu(_bus_type, _smmu_ops);
}
 #endif
+#ifdef CONFIG_FSL_MC_BUS
+   if (!iommu_present(_mc_bus_type))
+   bus_set_iommu(_mc_bus_type, _smmu_ops);
+#endif
 }
 
 static int arm_smmu_device_probe(struct platform_device *pdev)
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 69fef99..fbeebb2 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -32,6 +32,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 
 static struct kset *iommu_group_kset;
@@ -987,6 +988,26 @@ struct iommu_group *pci_device_group(struct device *dev)
return iommu_group_alloc();
 }
 
+/* Get the IOMMU group for device on fsl-mc bus */
+struct iommu_group *fsl_mc_device_group(struct device *dev)
+{
+   struct device *cont_dev = fsl_mc_cont_dev(dev);
+   struct iommu_group *group;
+
+   /* Container device is responsible for creating the iommu group */
+   if (fsl_mc_is_cont_dev(dev)) {
+   group = iommu_group_alloc();
+   if (IS_ERR(group))
+   return NULL;
+   } else {
+   get_device(cont_dev);
+   group = iommu_group_get(cont_dev);
+   put_device(cont_dev);
+   }
+
+   return group;
+}
+
 /**
  * iommu_group_get_for_dev - Find or create the IOMMU group for a device
  * @dev: target device
diff --git a/include/linux/fsl/mc.h b/include/linux/fsl/mc.h
index 765ba41..ae9382b 100644
--- a/include/linux/fsl/mc.h
+++ b/include/linux/fsl/mc.h
@@ -351,6 +351,14 @@ struct fsl_mc_io {
 #define dev_is_fsl_mc(_dev) (0)
 #endif
 
+/* Macro to check if a device is a container device */
+#define fsl_mc_is_cont_dev(_dev) (to_fsl_mc_device(_dev)->flags & \
+   FSL_MC_IS_DPRC)
+
+/* Macro to get the container device of a MC device */
+#define fsl_mc_cont_dev(_dev) (fsl_mc_is_cont_dev(_dev) ? \
+   (_dev) : (_dev)->parent)
+
 /*
  * module_fsl_mc_driver() - Helper macro for drivers that don't do
  * anything special in module init/exit.  This eliminates a lot of
diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index 41b8c57..00a460b 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -389,6 +389,8 @@ static inline size_t iommu_map_sg(struct iommu_domain 
*domain,
 extern struct iommu_group *pci_device_group(struct device *dev);
 /* Generic device grouping function */
 extern struct iommu_group *generic_device_group(struct device *dev);
+/* FSL-MC device grouping function */
+struct iommu_group *fsl_mc_device_group(struct device *dev);
 
 /**
  * struct iommu_fwspec - per-device IOMMU instance data
-- 
1.9.1

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


[PATCH 2/6] iommu: support iommu configuration for fsl-mc devices

2018-03-05 Thread Nipun Gupta
Signed-off-by: Nipun Gupta 
---
 drivers/iommu/of_iommu.c | 23 +++
 1 file changed, 23 insertions(+)

diff --git a/drivers/iommu/of_iommu.c b/drivers/iommu/of_iommu.c
index 5c36a8b..cc2fb9c 100644
--- a/drivers/iommu/of_iommu.c
+++ b/drivers/iommu/of_iommu.c
@@ -24,6 +24,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #define NO_IOMMU   1
 
@@ -160,6 +161,26 @@ static int of_pci_iommu_init(struct pci_dev *pdev, u16 
alias, void *data)
return err;
 }
 
+static int
+of_fsl_mc_iommu_init(struct fsl_mc_device *mc_dev,
+ struct device_node *master_np)
+{
+   struct of_phandle_args iommu_spec;
+   int err;
+
+   iommu_spec.np = of_parse_phandle(master_np, "iommu-parent", 0);
+   if (!iommu_spec.np)
+   return NO_IOMMU;
+
+   iommu_spec.args[0] = mc_dev->icid;
+   iommu_spec.args_count = 1;
+
+   err = of_iommu_xlate(_dev->dev, _spec);
+   of_node_put(iommu_spec.np);
+
+   return err;
+}
+
 const struct iommu_ops *of_iommu_configure(struct device *dev,
   struct device_node *master_np)
 {
@@ -191,6 +212,8 @@ const struct iommu_ops *of_iommu_configure(struct device 
*dev,
 
err = pci_for_each_dma_alias(to_pci_dev(dev),
 of_pci_iommu_init, );
+   } else if (dev_is_fsl_mc(dev)) {
+   err = of_fsl_mc_iommu_init(to_fsl_mc_device(dev), master_np);
} else {
struct of_phandle_args iommu_spec;
int idx = 0;
-- 
1.9.1

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


[PATCH 1/6] Docs: dt: add fsl-mc iommu-parent device-tree binding

2018-03-05 Thread Nipun Gupta
The existing IOMMU bindings cannot be used to specify the relationship
between fsl-mc devices and IOMMUs. This patch adds a binding for
mapping fsl-mc devices to IOMMUs, using a new iommu-parent property.

Signed-off-by: Nipun Gupta 
---
 .../devicetree/bindings/misc/fsl,qoriq-mc.txt  | 31 ++
 1 file changed, 31 insertions(+)

diff --git a/Documentation/devicetree/bindings/misc/fsl,qoriq-mc.txt 
b/Documentation/devicetree/bindings/misc/fsl,qoriq-mc.txt
index 6611a7c..011c7d6 100644
--- a/Documentation/devicetree/bindings/misc/fsl,qoriq-mc.txt
+++ b/Documentation/devicetree/bindings/misc/fsl,qoriq-mc.txt
@@ -9,6 +9,24 @@ blocks that can be used to create functional hardware 
objects/devices
 such as network interfaces, crypto accelerator instances, L2 switches,
 etc.
 
+For an overview of the DPAA2 architecture and fsl-mc bus see:
+drivers/staging/fsl-mc/README.txt
+
+As described in the above overview, all DPAA2 objects in a DPRC share the
+same hardware "isolation context" and a 10-bit value called an ICID
+(isolation context id) is expressed by the hardware to identify
+the requester.
+
+The generic 'iommus' property is cannot be used to describe the relationship
+between fsl-mc and IOMMUs, so an iommu-parent property is used to define
+the same.
+
+For generic IOMMU bindings, see
+Documentation/devicetree/bindings/iommu/iommu.txt.
+
+For arm-smmu binding, see:
+Documentation/devicetree/bindings/iommu/arm,smmu.txt.
+
 Required properties:
 
 - compatible
@@ -88,14 +106,27 @@ Sub-nodes:
   Value type: 
   Definition: Specifies the phandle to the PHY device node 
associated
   with the this dpmac.
+Optional properties:
+
+- iommu-parent: Maps the devices on fsl-mc bus to an IOMMU.
+  The property specifies the IOMMU behind which the devices on
+  fsl-mc bus are residing.
 
 Example:
 
+smmu: iommu@500 {
+   compatible = "arm,mmu-500";
+   #iommu-cells = <1>;
+   stream-match-mask = <0x7C00>;
+   ...
+};
+
 fsl_mc: fsl-mc@80c00 {
 compatible = "fsl,qoriq-mc";
 reg = <0x0008 0x0c00 0 0x40>,/* MC portal base */
   <0x 0x0834 0 0x4>; /* MC control reg */
 msi-parent = <>;
+iommu-parent = <>;
 #address-cells = <3>;
 #size-cells = <1>;
 
-- 
1.9.1

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


[PATCH 0/6] Support for fsl-mc bus and its devices in SMMU

2018-03-05 Thread Nipun Gupta
This patchset defines IOMMU DT binding for fsl-mc bus and adds
support in SMMU for fsl-mc bus.

These patches
  - Define the new property 'iommu-parent' for fsl-mc bus (patch 1)
  - Integrates the fsl-mc bus with the SMMU using this
IOMMU binding (patch 2,3)
  - Adds the dma-mapping support for fsl-mc bus (patch 4,5)
  - Updates the fsl-mc device node with iommu/dma related changes

This patchset is based on staging-testing tree where fsl-mc bus is out
from staging

This patchset is dependent on patch 
https://patchwork.kernel.org/patch/10207507/;
otherwise DPAA2 Ethernet driver functionality will break.

Nipun Gupta (6):
  Docs: dt: add fsl-mc iommu-parent device-tree binding
  iommu: support iommu configuration for fsl-mc devices
  iommu: arm-smmu: Add support for the fsl-mc bus
  bus: fsl-mc: remove dma ops setup from driver
  dma-mapping: support fsl-mc bus
  dts: fsl-ls208x: updated DT with SMMU support for fsl-mc

 .../devicetree/bindings/misc/fsl,qoriq-mc.txt  | 31 ++
 arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi |  6 -
 drivers/base/dma-mapping.c |  7 +
 drivers/bus/fsl-mc/fsl-mc-bus.c|  5 +---
 drivers/iommu/arm-smmu.c   |  7 +
 drivers/iommu/iommu.c  | 21 +++
 drivers/iommu/of_iommu.c   | 23 
 include/linux/fsl/mc.h |  8 ++
 include/linux/iommu.h  |  2 ++
 9 files changed, 105 insertions(+), 5 deletions(-)

-- 
1.9.1

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


Re: [RESEND PATCH v6 13/14] iommu/rockchip: Add runtime PM support

2018-03-05 Thread Robin Murphy

On 05/03/18 13:49, Tomasz Figa wrote:
[...]

@@ -518,7 +520,12 @@ static irqreturn_t rk_iommu_irq(int irq, void *dev_id)
 u32 int_status;
 dma_addr_t iova;
 irqreturn_t ret = IRQ_NONE;
-   int i;
+   int i, err, need_runtime_put;


nit: need_runtime_put could be a bool.


+
+   err = pm_runtime_get_if_in_use(iommu->dev);
+   if (err <= 0 && err != -EINVAL)
+   return ret;
+   need_runtime_put = err > 0;


Generally something must be really wrong if we end up with err == 0
here, because the IOMMU must be powered on to signal an interrupt. The
only case this could happen would be if the IRQ signal was shared with
some device from another power domain. Is it possible on Rockchip
SoCs? If not, perhaps we should have a WARN_ON() here for such case.


In general, there's almost certainly some time window between the 
interrupt level being latched at the GIC and the IRQ actually being 
taken by its target CPU, in which potentially the power could be removed 
and/or the clocks gated - especially if there are higher-priority IRQs 
pending at the same time and the racing PM call is on some other CPU. 
Sure, it's probably unlikely, but I wouldn't necessarily consider it 
completely erroneous.


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


Re: [RESEND PATCH v6 13/14] iommu/rockchip: Add runtime PM support

2018-03-05 Thread Tomasz Figa
Hi Jeffy,

On Thu, Mar 1, 2018 at 7:18 PM, Jeffy Chen  wrote:
> When the power domain is powered off, the IOMMU cannot be accessed and
> register programming must be deferred until the power domain becomes
> enabled.
>
> Add runtime PM support, and use runtime PM device link from IOMMU to
> master to startup and shutdown IOMMU.
>
> Signed-off-by: Jeffy Chen 
> ---
>
> Changes in v6: None
> Changes in v5:
> Avoid race about pm_runtime_get_if_in_use() and pm_runtime_enabled().
>
> Changes in v4: None
> Changes in v3:
> Only call startup() and shutdown() when iommu attached.
> Remove pm_mutex.
> Check runtime PM disabled.
> Check pm_runtime in rk_iommu_irq().
>
> Changes in v2: None
>
>  drivers/iommu/rockchip-iommu.c | 181 
> +++--
>  1 file changed, 140 insertions(+), 41 deletions(-)
>
> diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c
> index 2448a0528e39..0e0a42f41818 100644
> --- a/drivers/iommu/rockchip-iommu.c
> +++ b/drivers/iommu/rockchip-iommu.c
> @@ -22,6 +22,7 @@
>  #include 
>  #include 
>  #include 
> +#include 
>  #include 
>  #include 
>
> @@ -106,6 +107,7 @@ struct rk_iommu {
>  };
>
>  struct rk_iommudata {
> +   struct device_link *link; /* runtime PM link from IOMMU to master */

Kerneldoc comment for the struct could be added instead.

> struct rk_iommu *iommu;
>  };
>
> @@ -518,7 +520,12 @@ static irqreturn_t rk_iommu_irq(int irq, void *dev_id)
> u32 int_status;
> dma_addr_t iova;
> irqreturn_t ret = IRQ_NONE;
> -   int i;
> +   int i, err, need_runtime_put;

nit: need_runtime_put could be a bool.

> +
> +   err = pm_runtime_get_if_in_use(iommu->dev);
> +   if (err <= 0 && err != -EINVAL)
> +   return ret;
> +   need_runtime_put = err > 0;

Generally something must be really wrong if we end up with err == 0
here, because the IOMMU must be powered on to signal an interrupt. The
only case this could happen would be if the IRQ signal was shared with
some device from another power domain. Is it possible on Rockchip
SoCs? If not, perhaps we should have a WARN_ON() here for such case.

>
> WARN_ON(clk_bulk_enable(iommu->num_clocks, iommu->clocks));
>
> @@ -570,6 +577,9 @@ static irqreturn_t rk_iommu_irq(int irq, void *dev_id)
>
> clk_bulk_disable(iommu->num_clocks, iommu->clocks);
>
> +   if (need_runtime_put)
> +   pm_runtime_put(iommu->dev);
> +
> return ret;
>  }
>
> @@ -611,10 +621,20 @@ static void rk_iommu_zap_iova(struct rk_iommu_domain 
> *rk_domain,
> spin_lock_irqsave(_domain->iommus_lock, flags);
> list_for_each(pos, _domain->iommus) {
> struct rk_iommu *iommu;
> +   int ret;
> +
> iommu = list_entry(pos, struct rk_iommu, node);
> -   WARN_ON(clk_bulk_enable(iommu->num_clocks, iommu->clocks));
> -   rk_iommu_zap_lines(iommu, iova, size);
> -   clk_bulk_disable(iommu->num_clocks, iommu->clocks);
> +
> +   /* Only zap TLBs of IOMMUs that are powered on. */
> +   ret = pm_runtime_get_if_in_use(iommu->dev);
> +   if (ret > 0 || ret == -EINVAL) {
> +   WARN_ON(clk_bulk_enable(iommu->num_clocks,
> +   iommu->clocks));
> +   rk_iommu_zap_lines(iommu, iova, size);
> +   clk_bulk_disable(iommu->num_clocks, iommu->clocks);
> +   }
> +   if (ret > 0)
> +   pm_runtime_put(iommu->dev);
> }
> spin_unlock_irqrestore(_domain->iommus_lock, flags);
>  }
> @@ -817,22 +837,30 @@ static struct rk_iommu *rk_iommu_from_dev(struct device 
> *dev)
> return data ? data->iommu : NULL;
>  }
>
> -static int rk_iommu_attach_device(struct iommu_domain *domain,
> - struct device *dev)
> +/* Must be called with iommu powered on and attached */
> +static void rk_iommu_shutdown(struct rk_iommu *iommu)
>  {
> -   struct rk_iommu *iommu;
> +   int i;
> +
> +   /* Ignore error while disabling, just keep going */
> +   WARN_ON(clk_bulk_enable(iommu->num_clocks, iommu->clocks));
> +   rk_iommu_enable_stall(iommu);
> +   rk_iommu_disable_paging(iommu);
> +   for (i = 0; i < iommu->num_mmu; i++) {
> +   rk_iommu_write(iommu->bases[i], RK_MMU_INT_MASK, 0);
> +   rk_iommu_write(iommu->bases[i], RK_MMU_DTE_ADDR, 0);
> +   }
> +   rk_iommu_disable_stall(iommu);
> +   clk_bulk_disable(iommu->num_clocks, iommu->clocks);
> +}
> +
> +/* Must be called with iommu powered on and attached */
> +static int rk_iommu_startup(struct rk_iommu *iommu)
> +{
> +   struct iommu_domain *domain = iommu->domain;
> struct rk_iommu_domain *rk_domain = to_rk_domain(domain);
> -   unsigned long flags;
> int ret, 

Re: [RESEND PATCH v6 03/14] iommu/rockchip: Request irqs in rk_iommu_probe()

2018-03-05 Thread Tomasz Figa
Hi Jeffy,

On Thu, Mar 1, 2018 at 7:18 PM, Jeffy Chen  wrote:
> Move request_irq to the end of rk_iommu_probe().
>
> Suggested-by: Robin Murphy 
> Signed-off-by: Jeffy Chen 
> ---
>
> Changes in v6: None
> Changes in v5: None
> Changes in v4: None
> Changes in v3:
> Loop platform_get_irq() as Robin suggested.
>
> Changes in v2: None
>
>  drivers/iommu/rockchip-iommu.c | 38 +-
>  1 file changed, 9 insertions(+), 29 deletions(-)
>

Reviewed-by: Tomasz Figa 

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


Re: [PATCH v8 0/5] iommu/arm-smmu: Add runtime pm/sleep support

2018-03-05 Thread Tomasz Figa
Hi Vivek,

On Fri, Mar 2, 2018 at 7:10 PM, Vivek Gautam
 wrote:
> This series provides the support for turning on the arm-smmu's
> clocks/power domains using runtime pm. This is done using the
> recently introduced device links patches, which lets the smmu's
> runtime to follow the master's runtime pm, so the smmu remains
> powered only when the masters use it.
>
> It also adds support for Qcom's arm-smmu-v2 variant that
> has different clocks and power requirements.
>
> Took some reference from the exynos runtime patches [1].
>
> After another round of discussion [3], we now finally seem to be
> in agreement to add a flag based on compatible, a flag that would
> indicate if a particular implementation of arm-smmu supports
> runtime pm or not.
> This lets us to use the much-argued pm_runtime_get_sync/put_sync()
> calls in map/unmap callbacks so that the clients do not have to
> worry about handling any of the arm-smmu's power.
> The patch that exported couple of pm_runtime suppliers APIS, viz.
> pm_runtime_get_suppliers(), and pm_runtime_put_suppliers() can be
> dropped since we don't have a user now for these APIs.
> Thanks Rafael for reviewing the changes, but looks like we don't
> need to export those APIs for some more time. :)
>
> Previous version of this patch series is @ [5].

Thanks for addressing my comments. There is still a bit of space for
improving the granularity of power management, as far as I understood
how it works on SDM845 correctly, but as a first step, this should at
least let things work.

Reviewed-by: Tomasz Figa 

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


Re: [PATCH 35/37] iommu/arm-smmu-v3: Add support for PRI

2018-03-05 Thread Jean-Philippe Brucker
On 05/03/18 12:29, Dongdong Liu wrote:
>>
>> +static int arm_smmu_enable_pri(struct arm_smmu_master_data *master)
>> +{
>> +int ret, pos;
>> +struct pci_dev *pdev;
>> +/*
>> + * TODO: find a good inflight PPR number. We should divide the PRI queue
>> + * by the number of PRI-capable devices, but it's impossible to know
>> + * about current and future (hotplugged) devices. So we're at risk of
>> + * dropping PPRs (and leaking pending requests in the FQ).
>> + */
>> +size_t max_inflight_pprs = 16;
>> +struct arm_smmu_device *smmu = master->smmu;
>> +
>> +if (!(smmu->features & ARM_SMMU_FEAT_PRI) || !dev_is_pci(master->dev))
>> +return -ENOSYS;
>> +
>> +pdev = to_pci_dev(master->dev);
>> +
>  From here
>> +pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI);
>> +if (!pos)
>> +return -ENOSYS;
> to here, seems this code is not needed as it is already done in
> pci_reset_pri().

Indeed, thanks. It would allow to differentiate a device that doesn't
support PRI from a reset error, but since we ignore the return value at
the moment I'll remove it.

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


Re: [PATCH 35/37] iommu/arm-smmu-v3: Add support for PRI

2018-03-05 Thread Dongdong Liu


+static int arm_smmu_enable_pri(struct arm_smmu_master_data *master)
+{
+   int ret, pos;
+   struct pci_dev *pdev;
+   /*
+* TODO: find a good inflight PPR number. We should divide the PRI queue
+* by the number of PRI-capable devices, but it's impossible to know
+* about current and future (hotplugged) devices. So we're at risk of
+* dropping PPRs (and leaking pending requests in the FQ).
+*/
+   size_t max_inflight_pprs = 16;
+   struct arm_smmu_device *smmu = master->smmu;
+
+   if (!(smmu->features & ARM_SMMU_FEAT_PRI) || !dev_is_pci(master->dev))
+   return -ENOSYS;
+
+   pdev = to_pci_dev(master->dev);
+

From here

+   pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI);
+   if (!pos)
+   return -ENOSYS;

to here, seems this code is not needed as it is already done in
pci_reset_pri().

Thanks,
Dongdong

+
+   ret = pci_reset_pri(pdev);
+   if (ret)
+   return ret;
+
+   ret = pci_enable_pri(pdev, max_inflight_pprs);
+   if (ret) {
+   dev_err(master->dev, "cannot enable PRI: %d\n", ret);
+   return ret;
+   }
+
+   master->can_fault = true;
+   master->ste.prg_resp_needs_ssid = pci_prg_resp_requires_prefix(pdev);
+
+   dev_dbg(master->dev, "enabled PRI");
+
+   return 0;
+}
+
 static void arm_smmu_disable_ats(struct arm_smmu_master_data *master)
 {
struct pci_dev *pdev;
@@ -2548,6 +2592,22 @@ static void arm_smmu_disable_ats(struct 
arm_smmu_master_data *master)
pci_disable_ats(pdev);
 }

+static void arm_smmu_disable_pri(struct arm_smmu_master_data *master)
+{
+   struct pci_dev *pdev;
+
+   if (!dev_is_pci(master->dev))
+   return;
+
+   pdev = to_pci_dev(master->dev);
+
+   if (!pdev->pri_enabled)
+   return;
+
+   pci_disable_pri(pdev);
+   master->can_fault = false;
+}
+
 static int arm_smmu_insert_master(struct arm_smmu_device *smmu,
  struct arm_smmu_master_data *master)
 {
@@ -2668,12 +2728,13 @@ static int arm_smmu_add_device(struct device *dev)
master->ste.can_stall = true;
}

-   arm_smmu_enable_ats(master);
+   if (!arm_smmu_enable_ats(master))
+   arm_smmu_enable_pri(master);

group = iommu_group_get_for_dev(dev);
if (IS_ERR(group)) {
ret = PTR_ERR(group);
-   goto err_disable_ats;
+   goto err_disable_pri;
}

iommu_group_put(group);
@@ -2682,7 +2743,8 @@ static int arm_smmu_add_device(struct device *dev)

return 0;

-err_disable_ats:
+err_disable_pri:
+   arm_smmu_disable_pri(master);
arm_smmu_disable_ats(master);

return ret;
@@ -2702,6 +2764,8 @@ static void arm_smmu_remove_device(struct device *dev)
if (master && master->ste.assigned)
arm_smmu_detach_dev(dev);
arm_smmu_remove_master(smmu, master);
+
+   arm_smmu_disable_pri(master);
arm_smmu_disable_ats(master);

iommu_group_remove_device(dev);



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


Re: Using dma-ranges with iommu to limit range of iova

2018-03-05 Thread Robin Murphy

Hi Vivek,

On 05/03/18 09:06, Vivek Gautam wrote:

Hi all,

I have a question regarding usage of 'dma-ranges', can someone point me 
in the right direction?
On qcom soc, few of the master devices with iommu attached to them, have 
limitations in using the iova address range. They can allow the iova to 
be only in a certain range, e.g. video codec firmware can only access 
iova only in a first few MBs as the video's arm core reset starts at 0x0.
To do that, I earlier, had the understanding that we can modify the 
iommu_domain's geometry aperture. But that looks kind of a hacky way to 
get the domain for the device and modify the aperture.
I was trying to explore if we can use the dma-ranges property. But the 
iommu bindings documentation doesn't really talks much about usage of 
dma-ranges.
Can someone help me with with the answer to - can we use 'dma-ranges' to 
limit a device's iova address access? If yes, then how?


Yes, if the device has physical restrictions on what it can address, 
then "dma-ranges" is the correct way to describe that. That should be 
pretty much orthogonal to the IOMMU binding and combine in the obvious 
way, e.g.:


...
soc {
#address-cells = <1>;
#size-cells = <1>;
compatible = "simple-bus";
ranges;

...

iommu@f000 {
compatible = "iommu";
reg = <0xf000 0x1000>;
#iommu-cells = <0>;
};

...

subsystem {
#address-cells = <1>;
#size-cells = <1>;
compatible = "simple-bus";
ranges;
/* Devices can only drive address bits 0:23 */
dma-ranges = <0 0 0x100>;

device {
iommus = <>;
};
};
};
...

In terms of Linux, for the straightforward platform device case 
of_dma_configure() initialises the subsystem devices' DMA masks based on 
the size covered by "dma-ranges", and the DMA API code respects the 
device's DMA mask when allocating IOVAs. The only problem is the bit in 
the middle where the device driver's dma_set_mask() call can just trash 
of_dma_configure()'s initial mask, because there's no way to 
differentiate an explicitly-specified mask from a default one. It's also 
even uglier for PCI devices since the existing "pass the host bridge's 
node as the device's" bodge happens to work for the "dma-coherent" 
property but is a bit broken in general and doesn't work at all for 
"dma-ranges".


Fixing all of this (not to mention the DT/ACPI interaction aspect) has 
been hovering around #3 on my to-do list for the past couple of years 
now, but things keep sneaking in above it :(


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


Using dma-ranges with iommu to limit range of iova

2018-03-05 Thread Vivek Gautam

Hi all,

I have a question regarding usage of 'dma-ranges', can someone point me 
in the right direction?
On qcom soc, few of the master devices with iommu attached to them, have 
limitations in using the iova address range. They can allow the iova to 
be only in a certain range, e.g. video codec firmware can only access 
iova only in a first few MBs as the video's arm core reset starts at 0x0.
To do that, I earlier, had the understanding that we can modify the 
iommu_domain's geometry aperture. But that looks kind of a hacky way to 
get the domain for the device and modify the aperture.
I was trying to explore if we can use the dma-ranges property. But the 
iommu bindings documentation doesn't really talks much about usage of 
dma-ranges.
Can someone help me with with the answer to - can we use 'dma-ranges' to 
limit a device's iova address access? If yes, then how?


TIF

Regards
Vivek

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