Re: RFC on Kdump and PCIe on ARM64

2018-03-01 Thread Baoquan He
On 03/01/18 at 01:05pm, Bjorn Helgaas wrote:
> [+cc Joerg, David, iommu list]
> 
> On Thu, Mar 01, 2018 at 12:44:26PM -0500, Sinan Kaya wrote:
> > Hi,
> > 
> > We are seeing IOMMU faults when booting the kdump kernel on ARM64.
> > 
> > [7.220162] arm-smmu-v3 arm-smmu-v3.0.auto: event 0x02 received:
> > [7.226123] arm-smmu-v3 arm-smmu-v3.0.auto:0x0102
> > [7.232023] arm-smmu-v3 arm-smmu-v3.0.auto:0x
> > [7.237925] arm-smmu-v3 arm-smmu-v3.0.auto:0x
> > [7.243827] arm-smmu-v3 arm-smmu-v3.0.auto:0x
> > 
> > This is Nate's interpretation of the fault:
> > 
> > "The PCI device is sending transactions just after the SMMU was
> > reset/reinitialized which is problematic because the device has not
> > yet been added to the SMMU and thus should not be doing *any* DMA.
> > DMA from the PCI devices should be quiesced prior to starting the
> > crashdump kernel or you risk overwriting portions of memory you
> > meant to preserve. In this case the SMMU was actually doing you a
> > favor by blocking these errant DMA operations!!"

This seems an known issue which existed on x86 arch with intel vt-d
or amd-vi iommu deployed. Both of them have been fixed on x86. The root
cause is that kexec/kdump jumping is a warm reboot, it skips
bios/firmware. That left behind on-flight DMA which is started in 1st
kernel, and on-going during kdump kernel bootup. Then iommu devices
init will cause the on-flight DMA being stray and access those memory
region violently until pci devices initialization.

On x86, for intel vt-d iommu, patches and discussion can be found here:
https://lists.onap.org/pipermail/iommu/2015-May/012948.html

Finally, Joerg made a formal fix to make it.

On amd-iommu, I made a patchset with Joerg's help.

http://linux.kernel.narkive.com/Przi0Xaf/patch-v10-00-12-fix-the-on-flight-dma-issue-on-system-with-amd-iommu

On arm64, not sure how different the smmu is, you might need to do the
similar thing. Personal opinion, just for reference.

Thanks
Baoquan

> > 
> > I think this makes sense especially for the IOMMU enabled case on
> > the host where an IOVA can overlap with the region of memory kdump
> > reserved for itself.
> > 
> > Apparently, there has been similar concerns in the past.
> > 
> > https://www.fujitsu.com/jp/documents/products/software/os/linux/catalog/LinuxConJapan2013-Indoh.pdf
> > 
> > and was not addressed globally due to IOMMU+PCI driver ordering
> > issues and bugs in HW due to hot reset.
> > 
> > https://lkml.org/lkml/2012/8/3/160
> > 
> > Hot reset as mentioned is destructive and may not be the best
> > implementation choice.  However, most of the modern endpoints
> > support PCIE function level reset.
> > 
> > One other solution is for SMMUv3 driver to reserve the kdump used
> > IOVA addresses.
> > 
> > Another solution is for the SMMUv3 driver to disable PCIe devices
> > behind the SMMU if it see SMMU is already enabled.
> 
> What problem are you trying to solve?  If the IOMMU is blocking DMA
> after the kdump kernel starts up, that sounds like the desired
> behavior.
> 
> ___
> kexec mailing list
> ke...@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/kexec
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: RFC on Kdump and PCIe on ARM64

2018-03-01 Thread Bjorn Helgaas
On Thu, Mar 01, 2018 at 02:19:09PM -0500, Sinan Kaya wrote:
> On 3/1/2018 2:05 PM, Bjorn Helgaas wrote:
> > On Thu, Mar 01, 2018 at 12:44:26PM -0500, Sinan Kaya wrote:
> >> Hi,
> >>
> >> We are seeing IOMMU faults when booting the kdump kernel on ARM64.
> >>
> >> [7.220162] arm-smmu-v3 arm-smmu-v3.0.auto: event 0x02 received:
> >> [7.226123] arm-smmu-v3 arm-smmu-v3.0.auto:
> >> 0x0102
> >> [7.232023] arm-smmu-v3 arm-smmu-v3.0.auto:
> >> 0x
> >> [7.237925] arm-smmu-v3 arm-smmu-v3.0.auto:
> >> 0x
> >> [7.243827] arm-smmu-v3 arm-smmu-v3.0.auto:
> >> 0x
> >>
> >> This is Nate's interpretation of the fault:
> >>
> >> "The PCI device is sending transactions just after the SMMU was
> >> reset/reinitialized which is problematic because the device has not
> >> yet been added to the SMMU and thus should not be doing *any* DMA.
> >> DMA from the PCI devices should be quiesced prior to starting the
> >> crashdump kernel or you risk overwriting portions of memory you
> >> meant to preserve. In this case the SMMU was actually doing you a
> >> favor by blocking these errant DMA operations!!"
> >>
> >> I think this makes sense especially for the IOMMU enabled case on
> >> the host where an IOVA can overlap with the region of memory kdump
> >> reserved for itself.
> >>
> >> Apparently, there has been similar concerns in the past.
> >>
> >> https://www.fujitsu.com/jp/documents/products/software/os/linux/catalog/LinuxConJapan2013-Indoh.pdf
> >>
> >> and was not addressed globally due to IOMMU+PCI driver ordering
> >> issues and bugs in HW due to hot reset.
> >>
> >> https://lkml.org/lkml/2012/8/3/160
> >>
> >> Hot reset as mentioned is destructive and may not be the best
> >> implementation choice.  However, most of the modern endpoints
> >> support PCIE function level reset.
> >>
> >> One other solution is for SMMUv3 driver to reserve the kdump used
> >> IOVA addresses.
> >>
> >> Another solution is for the SMMUv3 driver to disable PCIe devices
> >> behind the SMMU if it see SMMU is already enabled.
> > 
> > What problem are you trying to solve?  If the IOMMU is blocking DMA
> > after the kdump kernel starts up, that sounds like the desired
> > behavior.
> > 
> 
> Three issues:
> 1. I'm seeing a flood of SMMUv3 faults due to adapter using
> addresses from the previous kernel. This might be OK. 

Yep.  That's cosmetic and we could suppress the messages if they were
a problem.

Isn't part of the point of an IOMMU protection against malicious
devices and drivers?  If so, we should be able to withstand an
arbitrary number of faults.

> 2. When the SMMUv3 driver sees that it is enabled, it resets itself
> and configures it one more time. 
> 
> [7.018304] arm-smmu-v3 arm-smmu-v3.0.auto: ias 44-bit, oas 44-bit 
> (features 0x1fef)
> [7.026379] arm-smmu-v3 arm-smmu-v3.0.auto: SMMU currently enabled! 
> Resetting...
> 
> From the moment IOMMU is disabled to the point where IOMMU get
> enabled again, there is a potential for the PCIE device to corrupt
> the kdump kernel memory as the bus master and memory enable bits are
> left enabled.

Do you really have to reset the IOMMU?  Can you just give it new page
tables that start out with all IOVAs from all devices being invalid,
then add valid mappings as drivers need them (presumably after the
driver has done whatever it needs to so the device stops using the old
DMA addresses)?

> [0.00] crashkernel reserved: 0x7fe0 - 0xffe0 
> (2048 MB)
> 
> This region happens to overlap with the IOVA addresses that SMMUv3
> driver on the main kernel is allocating.
> 
> IOVA addresses start from 0x and get decremented on each
> allocation.
> 
> 3. The last one is adapter gets into fuzzy state due to not coming
> out of clean state in the second time init and being rejected by
> SMMUv3 multiple times.
> 
> [   16.093441] pci :01:00.0: aer_status: 0x0004, aer_mask: 0x
> [   16.099356] pci :01:00.0: Malformed TLP
> [   16.103522] pci :01:00.0: aer_layer=Transaction Layer, 
> aer_agent=Receiver ID
> [   16.110900] pci :01:00.0: aer_uncor_severity: 0x00062011
> [   16.116543] pci :01:00.0:   TLP Header: 0a00a000 8100 01010100 
> 

I'm not clear on this.  I don't remember what an IOMMU fault looks
like to an Endpoint.  Are you saying that if an Endpoint sees too many
of those faults, it gets into this "fuzzy state" (whatever that is :))?
Is this a hardware defect?  Do we care (this is a kdump kernel, after
all)?  If we do care, can we fix the device by resetting it?

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


Re: RFC on Kdump and PCIe on ARM64

2018-03-01 Thread Sinan Kaya
On 3/1/2018 2:05 PM, Bjorn Helgaas wrote:
> [+cc Joerg, David, iommu list]
> 
> On Thu, Mar 01, 2018 at 12:44:26PM -0500, Sinan Kaya wrote:
>> Hi,
>>
>> We are seeing IOMMU faults when booting the kdump kernel on ARM64.
>>
>> [7.220162] arm-smmu-v3 arm-smmu-v3.0.auto: event 0x02 received:
>> [7.226123] arm-smmu-v3 arm-smmu-v3.0.auto:0x0102
>> [7.232023] arm-smmu-v3 arm-smmu-v3.0.auto:0x
>> [7.237925] arm-smmu-v3 arm-smmu-v3.0.auto:0x
>> [7.243827] arm-smmu-v3 arm-smmu-v3.0.auto:0x
>>
>> This is Nate's interpretation of the fault:
>>
>> "The PCI device is sending transactions just after the SMMU was
>> reset/reinitialized which is problematic because the device has not
>> yet been added to the SMMU and thus should not be doing *any* DMA.
>> DMA from the PCI devices should be quiesced prior to starting the
>> crashdump kernel or you risk overwriting portions of memory you
>> meant to preserve. In this case the SMMU was actually doing you a
>> favor by blocking these errant DMA operations!!"
>>
>> I think this makes sense especially for the IOMMU enabled case on
>> the host where an IOVA can overlap with the region of memory kdump
>> reserved for itself.
>>
>> Apparently, there has been similar concerns in the past.
>>
>> https://www.fujitsu.com/jp/documents/products/software/os/linux/catalog/LinuxConJapan2013-Indoh.pdf
>>
>> and was not addressed globally due to IOMMU+PCI driver ordering
>> issues and bugs in HW due to hot reset.
>>
>> https://lkml.org/lkml/2012/8/3/160
>>
>> Hot reset as mentioned is destructive and may not be the best
>> implementation choice.  However, most of the modern endpoints
>> support PCIE function level reset.
>>
>> One other solution is for SMMUv3 driver to reserve the kdump used
>> IOVA addresses.
>>
>> Another solution is for the SMMUv3 driver to disable PCIe devices
>> behind the SMMU if it see SMMU is already enabled.
> 
> What problem are you trying to solve?  If the IOMMU is blocking DMA
> after the kdump kernel starts up, that sounds like the desired
> behavior.
> 

Three issues:
1. I'm seeing a flood of SMMUv3 faults due to adapter using addresses from the
previous kernel. This might be OK. 
2. When the SMMUv3 driver sees that it is enabled, it resets itself and
configures it one more time. 

[7.018304] arm-smmu-v3 arm-smmu-v3.0.auto: ias 44-bit, oas 44-bit (features 
0x1fef)
[7.026379] arm-smmu-v3 arm-smmu-v3.0.auto: SMMU currently enabled! 
Resetting...

>From the moment IOMMU is disabled to the point where IOMMU get enabled again,
there is a potential for the PCIE device to corrupt the kdump kernel memory as
the bus master and memory enable bits are left enabled.

[0.00] crashkernel reserved: 0x7fe0 - 0xffe0 
(2048 MB)

This region happens to overlap with the IOVA addresses that SMMUv3 driver on 
the main
kernel is allocating.

IOVA addresses start from 0x and get decremented on each allocation.

3. The last one is adapter gets into fuzzy state due to not coming out of clean 
state
in the second time init and being rejected by SMMUv3 multiple times.

[   16.093441] pci :01:00.0: aer_status: 0x0004, aer_mask: 0x
[   16.099356] pci :01:00.0: Malformed TLP
[   16.103522] pci :01:00.0: aer_layer=Transaction Layer, 
aer_agent=Receiver ID
[   16.110900] pci :01:00.0: aer_uncor_severity: 0x00062011
[   16.116543] pci :01:00.0:   TLP Header: 0a00a000 8100 01010100 




-- 
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: RFC on Kdump and PCIe on ARM64

2018-03-01 Thread Bjorn Helgaas
[+cc Joerg, David, iommu list]

On Thu, Mar 01, 2018 at 12:44:26PM -0500, Sinan Kaya wrote:
> Hi,
> 
> We are seeing IOMMU faults when booting the kdump kernel on ARM64.
> 
> [7.220162] arm-smmu-v3 arm-smmu-v3.0.auto: event 0x02 received:
> [7.226123] arm-smmu-v3 arm-smmu-v3.0.auto:0x0102
> [7.232023] arm-smmu-v3 arm-smmu-v3.0.auto:0x
> [7.237925] arm-smmu-v3 arm-smmu-v3.0.auto:0x
> [7.243827] arm-smmu-v3 arm-smmu-v3.0.auto:0x
> 
> This is Nate's interpretation of the fault:
> 
> "The PCI device is sending transactions just after the SMMU was
> reset/reinitialized which is problematic because the device has not
> yet been added to the SMMU and thus should not be doing *any* DMA.
> DMA from the PCI devices should be quiesced prior to starting the
> crashdump kernel or you risk overwriting portions of memory you
> meant to preserve. In this case the SMMU was actually doing you a
> favor by blocking these errant DMA operations!!"
> 
> I think this makes sense especially for the IOMMU enabled case on
> the host where an IOVA can overlap with the region of memory kdump
> reserved for itself.
> 
> Apparently, there has been similar concerns in the past.
> 
> https://www.fujitsu.com/jp/documents/products/software/os/linux/catalog/LinuxConJapan2013-Indoh.pdf
> 
> and was not addressed globally due to IOMMU+PCI driver ordering
> issues and bugs in HW due to hot reset.
> 
> https://lkml.org/lkml/2012/8/3/160
> 
> Hot reset as mentioned is destructive and may not be the best
> implementation choice.  However, most of the modern endpoints
> support PCIE function level reset.
> 
> One other solution is for SMMUv3 driver to reserve the kdump used
> IOVA addresses.
> 
> Another solution is for the SMMUv3 driver to disable PCIe devices
> behind the SMMU if it see SMMU is already enabled.

What problem are you trying to solve?  If the IOMMU is blocking DMA
after the kdump kernel starts up, that sounds like the desired
behavior.
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH] iommu/omap: Increase group ref in .device_group()

2018-03-01 Thread Jeffy Chen
Increase group refcounting in omap_iommu_device_group().

Signed-off-by: Jeffy Chen 
---

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

diff --git a/drivers/iommu/omap-iommu.c b/drivers/iommu/omap-iommu.c
index e135ab830ebf..c33b7b104e72 100644
--- a/drivers/iommu/omap-iommu.c
+++ b/drivers/iommu/omap-iommu.c
@@ -1536,7 +1536,7 @@ static struct iommu_group *omap_iommu_device_group(struct 
device *dev)
struct iommu_group *group = ERR_PTR(-EINVAL);
 
if (arch_data->iommu_dev)
-   group = arch_data->iommu_dev->group;
+   group = iommu_group_ref_get(arch_data->iommu_dev->group);
 
return group;
 }
-- 
2.11.0


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


Re: [RESEND PATCH v6 14/14] iommu/rockchip: Support sharing IOMMU between masters

2018-03-01 Thread JeffyChen

Hi Robin,

On 03/01/2018 07:03 PM, Robin Murphy wrote:


+static struct iommu_group *rk_iommu_device_group(struct device *dev)
+{
+struct rk_iommu *iommu;
+
+iommu = rk_iommu_from_dev(dev);
+
+return iommu->group;


Oops, seems I overlooked this in my previous review - it should really be:

 return iommu_group_get(iommu->group);

or the refcounting will be unbalanced on those future systems where it
really will be called more than once.


hmmm, right, it should be return iommu_group_ref_get(iommu->group);

i was following omap iommu:
static struct iommu_group *omap_iommu_device_group(struct device *dev)
{
struct omap_iommu_arch_data *arch_data = dev->archdata.iommu;
struct iommu_group *group = ERR_PTR(-EINVAL);

if (arch_data->iommu_dev)
group = arch_data->iommu_dev->group;

return group;
}

will fix it too in the version.


Robin.



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


Re: [RESEND PATCH v6 14/14] iommu/rockchip: Support sharing IOMMU between masters

2018-03-01 Thread Robin Murphy

On 01/03/18 10:18, Jeffy Chen wrote:

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 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 0e0a42f41818..f4ce7706fc34 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;
  };
  
  struct rk_iommudata {

@@ -1083,6 +1084,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;


Oops, seems I overlooked this in my previous review - it should really be:

return iommu_group_get(iommu->group);

or the refcounting will be unbalanced on those future systems where it 
really will be called more than once.


Robin.


+}
+
  static int rk_iommu_of_xlate(struct device *dev,
 struct of_phandle_args *args)
  {
@@ -1114,7 +1124,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,
  };
@@ -1183,9 +1193,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);
@@ -1209,6 +1225,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;


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


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

2018-03-01 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 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


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

2018-03-01 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 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 0e0a42f41818..f4ce7706fc34 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;
 };
 
 struct rk_iommudata {
@@ -1083,6 +1084,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;
+}
+
 static int rk_iommu_of_xlate(struct device *dev,
 struct of_phandle_args *args)
 {
@@ -1114,7 +1124,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,
 };
@@ -1183,9 +1193,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);
@@ -1209,6 +1225,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


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

2018-03-01 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 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 */
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;
+
+   err = pm_runtime_get_if_in_use(iommu->dev);
+   if (err <= 0 && err != -EINVAL)
+   return ret;
+   need_runtime_put = err > 0;
 
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 (ret)
return ret;
@@ -845,8 +873,6 @@ static int rk_iommu_attach_device(struct iommu_domain 
*domain,
if (ret)
goto out_disable_stall;
 
-   iommu->domain = domain;
-
for (i = 0; i < iommu->num_mmu; i++) {
rk_iommu_write(iommu->bases[i], RK_MMU_DTE_ADDR,
   rk_domain->dt_dma);
@@ -855,14 +881,6 @@ static int rk_iommu_attach_device(struct 

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

2018-03-01 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 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 = rk_iommu_from_dev(dev);
-  

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

2018-03-01 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 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


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

2018-03-01 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 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))
return 0;
 

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

2018-03-01 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 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;
+
+   for (i = 0; 

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

2018-03-01 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 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 = 

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

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

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

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


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

2018-03-01 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 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


[RESEND PATCH v6 00/14] iommu/rockchip: Use OF_IOMMU

2018-03-01 Thread Jeffy Chen

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

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.

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 | 600 +++--
 8 files changed, 374 insertions(+), 289 deletions(-)

-- 
2.11.0


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


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

2018-03-01 Thread Jeffy Chen
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(-)

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


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

2018-03-01 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 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 v6 03/14] iommu/rockchip: Request irqs in rk_iommu_probe()

2018-03-01 Thread Jeffy Chen
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(-)

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 v6 06/14] iommu/rockchip: Fix TLB flush of secondary IOMMUs

2018-03-01 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 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 v6 04/14] iommu/rockchip: Fix error handling in attach

2018-03-01 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 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 v6 05/14] iommu/rockchip: Use iopoll helpers to wait for hardware

2018-03-01 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 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))
return 0;
 

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

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

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

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


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

2018-03-01 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 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 v6 00/14] iommu/rockchip: Use OF_IOMMU

2018-03-01 Thread Jeffy Chen

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

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.

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 | 600 +++--
 8 files changed, 374 insertions(+), 289 deletions(-)

-- 
2.11.0


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


Re: [PATCH 03/37] iommu/sva: Manage process address spaces

2018-03-01 Thread Christian König

Am 01.03.2018 um 07:52 schrieb Lu Baolu:

Hi Jean,

On 02/13/2018 02:33 AM, Jean-Philippe Brucker wrote:

[SNIP]
+   pasid = idr_alloc_cyclic(_pasid_idr, io_mm, dev_param->min_pasid,
+dev_param->max_pasid + 1, GFP_ATOMIC);

Can the pasid management code be moved into a common library?
PASID is not stick to SVA. An IOMMU model device could be designed
to use PASID for second level translation (classical DMA translation)
as well.


Yeah, we have the same problem on amdgpu.

We assign PASIDs to clients even when IOMMU isn't present in the system 
just because we need it for debugging.


E.g. when the hardware detects that some shader program is doing 
something nasty we get the PASID in the interrupt and could for example 
use it to inform the client about the fault.


Regards,
Christian.



Best regards,
Lu Baolu


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