* [PATCH v4 01/13] iommu/rockchip: Prohibit unbind and remove
2018-01-18 11:52 ` Jeffy Chen
(?)
@ 2018-01-18 11:52 ` Jeffy Chen
-1 siblings, 0 replies; 101+ messages in thread
From: Jeffy Chen @ 2018-01-18 11:52 UTC (permalink / raw)
To: linux-kernel-u79uwXL29TY76Z2rM5mHXA
Cc: Jeffy Chen, jcliang-F7+t8E8rja9g9hUCZPvPmw,
linux-rockchip-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Heiko Stuebner
Removal of IOMMUs cannot be done reliably.
This is similar to exynos iommu driver.
Signed-off-by: Jeffy Chen <jeffy.chen-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
Reviewed-by: Tomasz Figa <tfiga-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
---
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);
- iommu_device_unregister(&iommu->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(&rk_iommu_domain_driver);
return ret;
}
-static void __exit rk_iommu_exit(void)
-{
- platform_driver_unregister(&rk_iommu_driver);
- platform_driver_unregister(&rk_iommu_domain_driver);
-}
-
subsys_initcall(rk_iommu_init);
-module_exit(rk_iommu_exit);
MODULE_DESCRIPTION("IOMMU API for Rockchip");
MODULE_AUTHOR("Simon Xue <xxm-TNX95d0MmH7DzftRWevZcw@public.gmane.org> and Daniel Kurtz <djkurtz-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>");
--
2.11.0
^ permalink raw reply related [flat|nested] 101+ messages in thread* [PATCH v4 01/13] iommu/rockchip: Prohibit unbind and remove
@ 2018-01-18 11:52 ` Jeffy Chen
0 siblings, 0 replies; 101+ messages in thread
From: Jeffy Chen @ 2018-01-18 11:52 UTC (permalink / raw)
To: linux-kernel
Cc: jcliang, robin.murphy, xxm, tfiga, Jeffy Chen, Heiko Stuebner,
linux-rockchip, iommu, Joerg Roedel, linux-arm-kernel
Removal of IOMMUs cannot be done reliably.
This is similar to exynos iommu driver.
Signed-off-by: Jeffy Chen <jeffy.chen@rock-chips.com>
Reviewed-by: Tomasz Figa <tfiga@chromium.org>
---
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);
- iommu_device_unregister(&iommu->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(&rk_iommu_domain_driver);
return ret;
}
-static void __exit rk_iommu_exit(void)
-{
- platform_driver_unregister(&rk_iommu_driver);
- platform_driver_unregister(&rk_iommu_domain_driver);
-}
-
subsys_initcall(rk_iommu_init);
-module_exit(rk_iommu_exit);
MODULE_DESCRIPTION("IOMMU API for Rockchip");
MODULE_AUTHOR("Simon Xue <xxm@rock-chips.com> and Daniel Kurtz <djkurtz@chromium.org>");
--
2.11.0
^ permalink raw reply related [flat|nested] 101+ messages in thread* [PATCH v4 01/13] iommu/rockchip: Prohibit unbind and remove
@ 2018-01-18 11:52 ` Jeffy Chen
0 siblings, 0 replies; 101+ messages in thread
From: Jeffy Chen @ 2018-01-18 11:52 UTC (permalink / raw)
To: linux-arm-kernel
Removal of IOMMUs cannot be done reliably.
This is similar to exynos iommu driver.
Signed-off-by: Jeffy Chen <jeffy.chen@rock-chips.com>
Reviewed-by: Tomasz Figa <tfiga@chromium.org>
---
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);
- iommu_device_unregister(&iommu->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(&rk_iommu_domain_driver);
return ret;
}
-static void __exit rk_iommu_exit(void)
-{
- platform_driver_unregister(&rk_iommu_driver);
- platform_driver_unregister(&rk_iommu_domain_driver);
-}
-
subsys_initcall(rk_iommu_init);
-module_exit(rk_iommu_exit);
MODULE_DESCRIPTION("IOMMU API for Rockchip");
MODULE_AUTHOR("Simon Xue <xxm@rock-chips.com> and Daniel Kurtz <djkurtz@chromium.org>");
--
2.11.0
^ permalink raw reply related [flat|nested] 101+ messages in thread
* [PATCH v4 02/13] iommu/rockchip: Fix error handling in probe
2018-01-18 11:52 ` Jeffy Chen
(?)
@ 2018-01-18 11:52 ` Jeffy Chen
-1 siblings, 0 replies; 101+ messages in thread
From: Jeffy Chen @ 2018-01-18 11:52 UTC (permalink / raw)
To: linux-kernel-u79uwXL29TY76Z2rM5mHXA
Cc: Jeffy Chen, jcliang-F7+t8E8rja9g9hUCZPvPmw,
linux-rockchip-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Heiko Stuebner
Add missing iommu_device_sysfs_remove in error path.
Signed-off-by: Jeffy Chen <jeffy.chen-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
Reviewed-by: Tomasz Figa <tfiga-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
---
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, &rk_iommu_ops);
err = iommu_device_register(&iommu->iommu);
+ if (err) {
+ iommu_device_sysfs_remove(&iommu->iommu);
+ return err;
+ }
- return err;
+ return 0;
}
static const struct of_device_id rk_iommu_dt_ids[] = {
--
2.11.0
^ permalink raw reply related [flat|nested] 101+ messages in thread* [PATCH v4 02/13] iommu/rockchip: Fix error handling in probe
@ 2018-01-18 11:52 ` Jeffy Chen
0 siblings, 0 replies; 101+ messages in thread
From: Jeffy Chen @ 2018-01-18 11:52 UTC (permalink / raw)
To: linux-kernel
Cc: jcliang, robin.murphy, xxm, tfiga, Jeffy Chen, Heiko Stuebner,
linux-rockchip, iommu, Joerg Roedel, linux-arm-kernel
Add missing iommu_device_sysfs_remove in error path.
Signed-off-by: Jeffy Chen <jeffy.chen@rock-chips.com>
Reviewed-by: Tomasz Figa <tfiga@chromium.org>
---
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, &rk_iommu_ops);
err = iommu_device_register(&iommu->iommu);
+ if (err) {
+ iommu_device_sysfs_remove(&iommu->iommu);
+ return err;
+ }
- return err;
+ return 0;
}
static const struct of_device_id rk_iommu_dt_ids[] = {
--
2.11.0
^ permalink raw reply related [flat|nested] 101+ messages in thread* [PATCH v4 02/13] iommu/rockchip: Fix error handling in probe
@ 2018-01-18 11:52 ` Jeffy Chen
0 siblings, 0 replies; 101+ messages in thread
From: Jeffy Chen @ 2018-01-18 11:52 UTC (permalink / raw)
To: linux-arm-kernel
Add missing iommu_device_sysfs_remove in error path.
Signed-off-by: Jeffy Chen <jeffy.chen@rock-chips.com>
Reviewed-by: Tomasz Figa <tfiga@chromium.org>
---
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, &rk_iommu_ops);
err = iommu_device_register(&iommu->iommu);
+ if (err) {
+ iommu_device_sysfs_remove(&iommu->iommu);
+ return err;
+ }
- return err;
+ return 0;
}
static const struct of_device_id rk_iommu_dt_ids[] = {
--
2.11.0
^ permalink raw reply related [flat|nested] 101+ messages in thread
* [PATCH v4 04/13] iommu/rockchip: Fix error handling in attach
2018-01-18 11:52 ` Jeffy Chen
(?)
@ 2018-01-18 11:52 ` Jeffy Chen
-1 siblings, 0 replies; 101+ messages in thread
From: Jeffy Chen @ 2018-01-18 11:52 UTC (permalink / raw)
To: linux-kernel-u79uwXL29TY76Z2rM5mHXA
Cc: Jeffy Chen, jcliang-F7+t8E8rja9g9hUCZPvPmw,
linux-rockchip-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Heiko Stuebner
From: Tomasz Figa <tfiga-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
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 <tfiga-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
Signed-off-by: Jeffy Chen <jeffy.chen-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
---
Changes in v4: None
Changes in v3: None
Changes in v2:
Move irq request to probe(in patch[0])
drivers/iommu/rockchip-iommu.c | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c
index b743d82e6fe1..37065a7127c9 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 err_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 err_disable_stall;
spin_lock_irqsave(&rk_domain->iommus_lock, flags);
list_add_tail(&iommu->node, &rk_domain->iommus);
@@ -848,6 +848,11 @@ static int rk_iommu_attach_device(struct iommu_domain *domain,
rk_iommu_disable_stall(iommu);
return 0;
+
+err_disable_stall:
+ rk_iommu_disable_stall(iommu);
+
+ return ret;
}
static void rk_iommu_detach_device(struct iommu_domain *domain,
--
2.11.0
^ permalink raw reply related [flat|nested] 101+ messages in thread
* [PATCH v4 04/13] iommu/rockchip: Fix error handling in attach
@ 2018-01-18 11:52 ` Jeffy Chen
0 siblings, 0 replies; 101+ messages in thread
From: Jeffy Chen @ 2018-01-18 11:52 UTC (permalink / raw)
To: linux-kernel
Cc: jcliang, robin.murphy, xxm, tfiga, Jeffy Chen, Heiko Stuebner,
linux-rockchip, iommu, Joerg Roedel, linux-arm-kernel
From: Tomasz Figa <tfiga@chromium.org>
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 <tfiga@chromium.org>
Signed-off-by: Jeffy Chen <jeffy.chen@rock-chips.com>
---
Changes in v4: None
Changes in v3: None
Changes in v2:
Move irq request to probe(in patch[0])
drivers/iommu/rockchip-iommu.c | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c
index b743d82e6fe1..37065a7127c9 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 err_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 err_disable_stall;
spin_lock_irqsave(&rk_domain->iommus_lock, flags);
list_add_tail(&iommu->node, &rk_domain->iommus);
@@ -848,6 +848,11 @@ static int rk_iommu_attach_device(struct iommu_domain *domain,
rk_iommu_disable_stall(iommu);
return 0;
+
+err_disable_stall:
+ rk_iommu_disable_stall(iommu);
+
+ return ret;
}
static void rk_iommu_detach_device(struct iommu_domain *domain,
--
2.11.0
^ permalink raw reply related [flat|nested] 101+ messages in thread
* [PATCH v4 04/13] iommu/rockchip: Fix error handling in attach
@ 2018-01-18 11:52 ` Jeffy Chen
0 siblings, 0 replies; 101+ messages in thread
From: Jeffy Chen @ 2018-01-18 11:52 UTC (permalink / raw)
To: linux-arm-kernel
From: Tomasz Figa <tfiga@chromium.org>
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 <tfiga@chromium.org>
Signed-off-by: Jeffy Chen <jeffy.chen@rock-chips.com>
---
Changes in v4: None
Changes in v3: None
Changes in v2:
Move irq request to probe(in patch[0])
drivers/iommu/rockchip-iommu.c | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c
index b743d82e6fe1..37065a7127c9 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 err_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 err_disable_stall;
spin_lock_irqsave(&rk_domain->iommus_lock, flags);
list_add_tail(&iommu->node, &rk_domain->iommus);
@@ -848,6 +848,11 @@ static int rk_iommu_attach_device(struct iommu_domain *domain,
rk_iommu_disable_stall(iommu);
return 0;
+
+err_disable_stall:
+ rk_iommu_disable_stall(iommu);
+
+ return ret;
}
static void rk_iommu_detach_device(struct iommu_domain *domain,
--
2.11.0
^ permalink raw reply related [flat|nested] 101+ messages in thread
[parent not found: <20180118115251.5542-5-jeffy.chen-TNX95d0MmH7DzftRWevZcw@public.gmane.org>]
* Re: [PATCH v4 04/13] iommu/rockchip: Fix error handling in attach
2018-01-18 11:52 ` Jeffy Chen
(?)
@ 2018-01-18 13:23 ` Robin Murphy
-1 siblings, 0 replies; 101+ messages in thread
From: Robin Murphy @ 2018-01-18 13:23 UTC (permalink / raw)
To: Jeffy Chen, linux-kernel-u79uwXL29TY76Z2rM5mHXA
Cc: Heiko Stuebner, jcliang-F7+t8E8rja9g9hUCZPvPmw,
linux-rockchip-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
On 18/01/18 11:52, Jeffy Chen wrote:
> From: Tomasz Figa <tfiga-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
>
> 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 <tfiga-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
> Signed-off-by: Jeffy Chen <jeffy.chen-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
> ---
>
> Changes in v4: None
> Changes in v3: None
> Changes in v2:
> Move irq request to probe(in patch[0])
>
> drivers/iommu/rockchip-iommu.c | 9 +++++++--
> 1 file changed, 7 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c
> index b743d82e6fe1..37065a7127c9 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 err_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 err_disable_stall;
>
> spin_lock_irqsave(&rk_domain->iommus_lock, flags);
> list_add_tail(&iommu->node, &rk_domain->iommus);
> @@ -848,6 +848,11 @@ static int rk_iommu_attach_device(struct iommu_domain *domain,
> rk_iommu_disable_stall(iommu);
>
> return 0;
Nit: if you like, it looks reasonable to name the label
"out_disable_stall" and remove these lines above here, to save the
duplication between the error and success paths (since ret will already
be 0 on the latter).
Either way,
Reviewed-by: Robin Murphy <robin.murphy-5wv7dgnIgG8@public.gmane.org>
> +
> +err_disable_stall:
> + rk_iommu_disable_stall(iommu);
> +
> + return ret;
> }
>
> static void rk_iommu_detach_device(struct iommu_domain *domain,
>
^ permalink raw reply [flat|nested] 101+ messages in thread
* Re: [PATCH v4 04/13] iommu/rockchip: Fix error handling in attach
@ 2018-01-18 13:23 ` Robin Murphy
0 siblings, 0 replies; 101+ messages in thread
From: Robin Murphy @ 2018-01-18 13:23 UTC (permalink / raw)
To: Jeffy Chen, linux-kernel
Cc: jcliang, xxm, tfiga, Heiko Stuebner, linux-rockchip, iommu,
Joerg Roedel, linux-arm-kernel
On 18/01/18 11:52, Jeffy Chen wrote:
> From: Tomasz Figa <tfiga@chromium.org>
>
> 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 <tfiga@chromium.org>
> Signed-off-by: Jeffy Chen <jeffy.chen@rock-chips.com>
> ---
>
> Changes in v4: None
> Changes in v3: None
> Changes in v2:
> Move irq request to probe(in patch[0])
>
> drivers/iommu/rockchip-iommu.c | 9 +++++++--
> 1 file changed, 7 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c
> index b743d82e6fe1..37065a7127c9 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 err_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 err_disable_stall;
>
> spin_lock_irqsave(&rk_domain->iommus_lock, flags);
> list_add_tail(&iommu->node, &rk_domain->iommus);
> @@ -848,6 +848,11 @@ static int rk_iommu_attach_device(struct iommu_domain *domain,
> rk_iommu_disable_stall(iommu);
>
> return 0;
Nit: if you like, it looks reasonable to name the label
"out_disable_stall" and remove these lines above here, to save the
duplication between the error and success paths (since ret will already
be 0 on the latter).
Either way,
Reviewed-by: Robin Murphy <robin.murphy@arm.com>
> +
> +err_disable_stall:
> + rk_iommu_disable_stall(iommu);
> +
> + return ret;
> }
>
> static void rk_iommu_detach_device(struct iommu_domain *domain,
>
^ permalink raw reply [flat|nested] 101+ messages in thread
* [PATCH v4 04/13] iommu/rockchip: Fix error handling in attach
@ 2018-01-18 13:23 ` Robin Murphy
0 siblings, 0 replies; 101+ messages in thread
From: Robin Murphy @ 2018-01-18 13:23 UTC (permalink / raw)
To: linux-arm-kernel
On 18/01/18 11:52, Jeffy Chen wrote:
> From: Tomasz Figa <tfiga@chromium.org>
>
> 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 <tfiga@chromium.org>
> Signed-off-by: Jeffy Chen <jeffy.chen@rock-chips.com>
> ---
>
> Changes in v4: None
> Changes in v3: None
> Changes in v2:
> Move irq request to probe(in patch[0])
>
> drivers/iommu/rockchip-iommu.c | 9 +++++++--
> 1 file changed, 7 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c
> index b743d82e6fe1..37065a7127c9 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 err_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 err_disable_stall;
>
> spin_lock_irqsave(&rk_domain->iommus_lock, flags);
> list_add_tail(&iommu->node, &rk_domain->iommus);
> @@ -848,6 +848,11 @@ static int rk_iommu_attach_device(struct iommu_domain *domain,
> rk_iommu_disable_stall(iommu);
>
> return 0;
Nit: if you like, it looks reasonable to name the label
"out_disable_stall" and remove these lines above here, to save the
duplication between the error and success paths (since ret will already
be 0 on the latter).
Either way,
Reviewed-by: Robin Murphy <robin.murphy@arm.com>
> +
> +err_disable_stall:
> + rk_iommu_disable_stall(iommu);
> +
> + return ret;
> }
>
> static void rk_iommu_detach_device(struct iommu_domain *domain,
>
^ permalink raw reply [flat|nested] 101+ messages in thread
* Re: [PATCH v4 04/13] iommu/rockchip: Fix error handling in attach
2018-01-18 13:23 ` Robin Murphy
@ 2018-01-18 14:22 ` JeffyChen
-1 siblings, 0 replies; 101+ messages in thread
From: JeffyChen @ 2018-01-18 14:22 UTC (permalink / raw)
To: Robin Murphy, linux-kernel
Cc: jcliang, xxm, tfiga, Heiko Stuebner, linux-rockchip, iommu,
Joerg Roedel, linux-arm-kernel
Hi Robin,
On 01/18/2018 09:23 PM, Robin Murphy wrote:
>>
>> @@ -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 err_disable_stall;
>> spin_lock_irqsave(&rk_domain->iommus_lock, flags);
>> list_add_tail(&iommu->node, &rk_domain->iommus);
>> @@ -848,6 +848,11 @@ static int rk_iommu_attach_device(struct
>> iommu_domain *domain,
>> rk_iommu_disable_stall(iommu);
>> return 0;
>
> Nit: if you like, it looks reasonable to name the label
> "out_disable_stall" and remove these lines above here, to save the
> duplication between the error and success paths (since ret will already
> be 0 on the latter).
>
right, i think so, will do it in the next version.
> Either way,
>
> Reviewed-by: Robin Murphy <robin.murphy@arm.com>
^ permalink raw reply [flat|nested] 101+ messages in thread
* [PATCH v4 04/13] iommu/rockchip: Fix error handling in attach
@ 2018-01-18 14:22 ` JeffyChen
0 siblings, 0 replies; 101+ messages in thread
From: JeffyChen @ 2018-01-18 14:22 UTC (permalink / raw)
To: linux-arm-kernel
Hi Robin,
On 01/18/2018 09:23 PM, Robin Murphy wrote:
>>
>> @@ -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 err_disable_stall;
>> spin_lock_irqsave(&rk_domain->iommus_lock, flags);
>> list_add_tail(&iommu->node, &rk_domain->iommus);
>> @@ -848,6 +848,11 @@ static int rk_iommu_attach_device(struct
>> iommu_domain *domain,
>> rk_iommu_disable_stall(iommu);
>> return 0;
>
> Nit: if you like, it looks reasonable to name the label
> "out_disable_stall" and remove these lines above here, to save the
> duplication between the error and success paths (since ret will already
> be 0 on the latter).
>
right, i think so, will do it in the next version.
> Either way,
>
> Reviewed-by: Robin Murphy <robin.murphy@arm.com>
^ permalink raw reply [flat|nested] 101+ messages in thread
* [PATCH v4 06/13] iommu/rockchip: Fix TLB flush of secondary IOMMUs
2018-01-18 11:52 ` Jeffy Chen
(?)
@ 2018-01-18 11:52 ` Jeffy Chen
-1 siblings, 0 replies; 101+ messages in thread
From: Jeffy Chen @ 2018-01-18 11:52 UTC (permalink / raw)
To: linux-kernel-u79uwXL29TY76Z2rM5mHXA
Cc: Jeffy Chen, jcliang-F7+t8E8rja9g9hUCZPvPmw,
linux-rockchip-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Heiko Stuebner
From: Tomasz Figa <tfiga-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
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 <tfiga-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
Signed-off-by: Jeffy Chen <jeffy.chen-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
---
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 4a1c710408af..1914ac52042c 100644
--- a/drivers/iommu/rockchip-iommu.c
+++ b/drivers/iommu/rockchip-iommu.c
@@ -272,19 +272,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
^ permalink raw reply related [flat|nested] 101+ messages in thread* [PATCH v4 06/13] iommu/rockchip: Fix TLB flush of secondary IOMMUs
@ 2018-01-18 11:52 ` Jeffy Chen
0 siblings, 0 replies; 101+ messages in thread
From: Jeffy Chen @ 2018-01-18 11:52 UTC (permalink / raw)
To: linux-kernel
Cc: jcliang, robin.murphy, xxm, tfiga, Jeffy Chen, Heiko Stuebner,
linux-rockchip, iommu, Joerg Roedel, linux-arm-kernel
From: Tomasz Figa <tfiga@chromium.org>
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 <tfiga@chromium.org>
Signed-off-by: Jeffy Chen <jeffy.chen@rock-chips.com>
---
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 4a1c710408af..1914ac52042c 100644
--- a/drivers/iommu/rockchip-iommu.c
+++ b/drivers/iommu/rockchip-iommu.c
@@ -272,19 +272,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
^ permalink raw reply related [flat|nested] 101+ messages in thread* [PATCH v4 06/13] iommu/rockchip: Fix TLB flush of secondary IOMMUs
@ 2018-01-18 11:52 ` Jeffy Chen
0 siblings, 0 replies; 101+ messages in thread
From: Jeffy Chen @ 2018-01-18 11:52 UTC (permalink / raw)
To: linux-arm-kernel
From: Tomasz Figa <tfiga@chromium.org>
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 <tfiga@chromium.org>
Signed-off-by: Jeffy Chen <jeffy.chen@rock-chips.com>
---
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 4a1c710408af..1914ac52042c 100644
--- a/drivers/iommu/rockchip-iommu.c
+++ b/drivers/iommu/rockchip-iommu.c
@@ -272,19 +272,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
^ permalink raw reply related [flat|nested] 101+ messages in thread
* [PATCH v4 08/13] iommu/rockchip: Control clocks needed to access the IOMMU
2018-01-18 11:52 ` Jeffy Chen
(?)
@ 2018-01-18 11:52 ` Jeffy Chen
-1 siblings, 0 replies; 101+ messages in thread
From: Jeffy Chen @ 2018-01-18 11:52 UTC (permalink / raw)
To: linux-kernel-u79uwXL29TY76Z2rM5mHXA
Cc: Mark Rutland, devicetree-u79uwXL29TY76Z2rM5mHXA, Jeffy Chen,
jcliang-F7+t8E8rja9g9hUCZPvPmw,
linux-rockchip-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA, Rob Herring,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Heiko Stuebner
From: Tomasz Figa <tfiga-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
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 <jeffy.chen-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
Signed-off-by: Tomasz Figa <tfiga-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
---
Changes in v4: None
Changes in v3: None
Changes in v2: None
.../devicetree/bindings/iommu/rockchip,iommu.txt | 8 ++
drivers/iommu/rockchip-iommu.c | 114 +++++++++++++++++++--
2 files changed, 116 insertions(+), 6 deletions(-)
diff --git a/Documentation/devicetree/bindings/iommu/rockchip,iommu.txt b/Documentation/devicetree/bindings/iommu/rockchip,iommu.txt
index 2098f7732264..33dd853359fa 100644
--- a/Documentation/devicetree/bindings/iommu/rockchip,iommu.txt
+++ b/Documentation/devicetree/bindings/iommu/rockchip,iommu.txt
@@ -14,6 +14,13 @@ Required properties:
"single-master" device, and needs no additional information
to associate with its master device. See:
Documentation/devicetree/bindings/iommu/iommu.txt
+Optional properties:
+- clocks : A list of master clocks requires for the IOMMU to be accessible
+ by the host CPU. The number of clocks depends on the master
+ block and might as well be zero. See [1] for generic clock
+ bindings description.
+
+[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
Optional properties:
- rockchip,disable-mmu-reset : Don't use the mmu reset operation.
@@ -27,5 +34,6 @@ Example:
reg = <0xff940300 0x100>;
interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "vopl_mmu";
+ clocks = <&cru ACLK_VOP1>, <&cru DCLK_VOP1>, <&cru HCLK_VOP1>;
#iommu-cells = <0>;
};
diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c
index 1914ac52042c..9b85a3050449 100644
--- a/drivers/iommu/rockchip-iommu.c
+++ b/drivers/iommu/rockchip-iommu.c
@@ -4,6 +4,7 @@
* published by the Free Software Foundation.
*/
+#include <linux/clk.h>
#include <linux/compiler.h>
#include <linux/delay.h>
#include <linux/device.h>
@@ -89,6 +90,8 @@ struct rk_iommu {
struct device *dev;
void __iomem **bases;
int num_mmu;
+ struct clk **clocks;
+ int num_clocks;
bool reset_disabled;
struct iommu_device iommu;
struct list_head node; /* entry in rk_iommu_domain.iommus */
@@ -443,6 +446,83 @@ static int rk_iommu_force_reset(struct rk_iommu *iommu)
return 0;
}
+static void rk_iommu_put_clocks(struct rk_iommu *iommu)
+{
+ int i;
+
+ for (i = 0; i < iommu->num_clocks; ++i) {
+ clk_unprepare(iommu->clocks[i]);
+ clk_put(iommu->clocks[i]);
+ }
+}
+
+static int rk_iommu_get_clocks(struct rk_iommu *iommu)
+{
+ struct device_node *np = iommu->dev->of_node;
+ int ret;
+ int i;
+
+ ret = of_count_phandle_with_args(np, "clocks", "#clock-cells");
+ if (ret == -ENOENT)
+ return 0;
+ else if (ret < 0)
+ return ret;
+
+ iommu->num_clocks = ret;
+ iommu->clocks = devm_kcalloc(iommu->dev, iommu->num_clocks,
+ sizeof(*iommu->clocks), GFP_KERNEL);
+ if (!iommu->clocks)
+ return -ENOMEM;
+
+ for (i = 0; i < iommu->num_clocks; ++i) {
+ iommu->clocks[i] = of_clk_get(np, i);
+ if (IS_ERR(iommu->clocks[i])) {
+ iommu->num_clocks = i;
+ goto err_clk_put;
+ }
+ ret = clk_prepare(iommu->clocks[i]);
+ if (ret) {
+ clk_put(iommu->clocks[i]);
+ iommu->num_clocks = i;
+ goto err_clk_put;
+ }
+ }
+
+ return 0;
+
+err_clk_put:
+ rk_iommu_put_clocks(iommu);
+
+ return ret;
+}
+
+static int rk_iommu_enable_clocks(struct rk_iommu *iommu)
+{
+ int i, ret;
+
+ for (i = 0; i < iommu->num_clocks; ++i) {
+ ret = clk_enable(iommu->clocks[i]);
+ if (ret)
+ goto err_disable;
+ }
+
+ return 0;
+
+err_disable:
+ for (--i; i >= 0; --i)
+ clk_disable(iommu->clocks[i]);
+
+ return ret;
+}
+
+static void rk_iommu_disable_clocks(struct rk_iommu *iommu)
+{
+ int i;
+
+ for (i = 0; i < iommu->num_clocks; ++i)
+ clk_disable(iommu->clocks[i]);
+}
+
static void log_iova(struct rk_iommu *iommu, int index, dma_addr_t iova)
{
void __iomem *base = iommu->bases[index];
@@ -499,6 +579,8 @@ static irqreturn_t rk_iommu_irq(int irq, void *dev_id)
irqreturn_t ret = IRQ_NONE;
int i;
+ WARN_ON(rk_iommu_enable_clocks(iommu));
+
for (i = 0; i < iommu->num_mmu; i++) {
int_status = rk_iommu_read(iommu->bases[i], RK_MMU_INT_STATUS);
if (int_status == 0)
@@ -545,6 +627,8 @@ static irqreturn_t rk_iommu_irq(int irq, void *dev_id)
rk_iommu_write(iommu->bases[i], RK_MMU_INT_CLEAR, int_status);
}
+ rk_iommu_disable_clocks(iommu);
+
return ret;
}
@@ -587,7 +671,9 @@ static void rk_iommu_zap_iova(struct rk_iommu_domain *rk_domain,
list_for_each(pos, &rk_domain->iommus) {
struct rk_iommu *iommu;
iommu = list_entry(pos, struct rk_iommu, node);
+ rk_iommu_enable_clocks(iommu);
rk_iommu_zap_lines(iommu, iova, size);
+ rk_iommu_disable_clocks(iommu);
}
spin_unlock_irqrestore(&rk_domain->iommus_lock, flags);
}
@@ -816,10 +902,14 @@ static int rk_iommu_attach_device(struct iommu_domain *domain,
if (!iommu)
return 0;
- ret = rk_iommu_enable_stall(iommu);
+ ret = rk_iommu_enable_clocks(iommu);
if (ret)
return ret;
+ ret = rk_iommu_enable_stall(iommu);
+ if (ret)
+ goto err_disable_clocks;
+
ret = rk_iommu_force_reset(iommu);
if (ret)
goto err_disable_stall;
@@ -844,11 +934,14 @@ static int rk_iommu_attach_device(struct iommu_domain *domain,
dev_dbg(dev, "Attached to iommu domain\n");
rk_iommu_disable_stall(iommu);
+ rk_iommu_disable_clocks(iommu);
return 0;
err_disable_stall:
rk_iommu_disable_stall(iommu);
+err_disable_clocks:
+ rk_iommu_disable_clocks(iommu);
return ret;
}
@@ -871,6 +964,7 @@ static void rk_iommu_detach_device(struct iommu_domain *domain,
spin_unlock_irqrestore(&rk_domain->iommus_lock, flags);
/* Ignore error while disabling, just keep going */
+ WARN_ON(rk_iommu_enable_clocks(iommu));
rk_iommu_enable_stall(iommu);
rk_iommu_disable_paging(iommu);
for (i = 0; i < iommu->num_mmu; i++) {
@@ -878,6 +972,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);
+ rk_iommu_disable_clocks(iommu);
iommu->domain = NULL;
@@ -1167,21 +1262,28 @@ static int rk_iommu_probe(struct platform_device *pdev)
return err;
}
+ err = rk_iommu_get_clocks(iommu);
+ if (err)
+ return err;
+
iommu->reset_disabled = device_property_read_bool(dev,
"rockchip,disable-mmu-reset");
err = iommu_device_sysfs_add(&iommu->iommu, dev, NULL, dev_name(dev));
if (err)
- return err;
+ goto err_put_clocks;
iommu_device_set_ops(&iommu->iommu, &rk_iommu_ops);
err = iommu_device_register(&iommu->iommu);
- if (err) {
- iommu_device_sysfs_remove(&iommu->iommu);
- return err;
- }
+ if (err)
+ goto err_remove_sysfs;
return 0;
+err_remove_sysfs:
+ iommu_device_sysfs_remove(&iommu->iommu);
+err_put_clocks:
+ rk_iommu_put_clocks(iommu);
+ return err;
}
static const struct of_device_id rk_iommu_dt_ids[] = {
--
2.11.0
^ permalink raw reply related [flat|nested] 101+ messages in thread* [PATCH v4 08/13] iommu/rockchip: Control clocks needed to access the IOMMU
@ 2018-01-18 11:52 ` Jeffy Chen
0 siblings, 0 replies; 101+ messages in thread
From: Jeffy Chen @ 2018-01-18 11:52 UTC (permalink / raw)
To: linux-kernel
Cc: jcliang, robin.murphy, xxm, tfiga, Jeffy Chen, devicetree,
Heiko Stuebner, linux-rockchip, iommu, Rob Herring, Mark Rutland,
Joerg Roedel, linux-arm-kernel
From: Tomasz Figa <tfiga@chromium.org>
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 <jeffy.chen@rock-chips.com>
Signed-off-by: Tomasz Figa <tfiga@chromium.org>
---
Changes in v4: None
Changes in v3: None
Changes in v2: None
.../devicetree/bindings/iommu/rockchip,iommu.txt | 8 ++
drivers/iommu/rockchip-iommu.c | 114 +++++++++++++++++++--
2 files changed, 116 insertions(+), 6 deletions(-)
diff --git a/Documentation/devicetree/bindings/iommu/rockchip,iommu.txt b/Documentation/devicetree/bindings/iommu/rockchip,iommu.txt
index 2098f7732264..33dd853359fa 100644
--- a/Documentation/devicetree/bindings/iommu/rockchip,iommu.txt
+++ b/Documentation/devicetree/bindings/iommu/rockchip,iommu.txt
@@ -14,6 +14,13 @@ Required properties:
"single-master" device, and needs no additional information
to associate with its master device. See:
Documentation/devicetree/bindings/iommu/iommu.txt
+Optional properties:
+- clocks : A list of master clocks requires for the IOMMU to be accessible
+ by the host CPU. The number of clocks depends on the master
+ block and might as well be zero. See [1] for generic clock
+ bindings description.
+
+[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
Optional properties:
- rockchip,disable-mmu-reset : Don't use the mmu reset operation.
@@ -27,5 +34,6 @@ Example:
reg = <0xff940300 0x100>;
interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "vopl_mmu";
+ clocks = <&cru ACLK_VOP1>, <&cru DCLK_VOP1>, <&cru HCLK_VOP1>;
#iommu-cells = <0>;
};
diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c
index 1914ac52042c..9b85a3050449 100644
--- a/drivers/iommu/rockchip-iommu.c
+++ b/drivers/iommu/rockchip-iommu.c
@@ -4,6 +4,7 @@
* published by the Free Software Foundation.
*/
+#include <linux/clk.h>
#include <linux/compiler.h>
#include <linux/delay.h>
#include <linux/device.h>
@@ -89,6 +90,8 @@ struct rk_iommu {
struct device *dev;
void __iomem **bases;
int num_mmu;
+ struct clk **clocks;
+ int num_clocks;
bool reset_disabled;
struct iommu_device iommu;
struct list_head node; /* entry in rk_iommu_domain.iommus */
@@ -443,6 +446,83 @@ static int rk_iommu_force_reset(struct rk_iommu *iommu)
return 0;
}
+static void rk_iommu_put_clocks(struct rk_iommu *iommu)
+{
+ int i;
+
+ for (i = 0; i < iommu->num_clocks; ++i) {
+ clk_unprepare(iommu->clocks[i]);
+ clk_put(iommu->clocks[i]);
+ }
+}
+
+static int rk_iommu_get_clocks(struct rk_iommu *iommu)
+{
+ struct device_node *np = iommu->dev->of_node;
+ int ret;
+ int i;
+
+ ret = of_count_phandle_with_args(np, "clocks", "#clock-cells");
+ if (ret == -ENOENT)
+ return 0;
+ else if (ret < 0)
+ return ret;
+
+ iommu->num_clocks = ret;
+ iommu->clocks = devm_kcalloc(iommu->dev, iommu->num_clocks,
+ sizeof(*iommu->clocks), GFP_KERNEL);
+ if (!iommu->clocks)
+ return -ENOMEM;
+
+ for (i = 0; i < iommu->num_clocks; ++i) {
+ iommu->clocks[i] = of_clk_get(np, i);
+ if (IS_ERR(iommu->clocks[i])) {
+ iommu->num_clocks = i;
+ goto err_clk_put;
+ }
+ ret = clk_prepare(iommu->clocks[i]);
+ if (ret) {
+ clk_put(iommu->clocks[i]);
+ iommu->num_clocks = i;
+ goto err_clk_put;
+ }
+ }
+
+ return 0;
+
+err_clk_put:
+ rk_iommu_put_clocks(iommu);
+
+ return ret;
+}
+
+static int rk_iommu_enable_clocks(struct rk_iommu *iommu)
+{
+ int i, ret;
+
+ for (i = 0; i < iommu->num_clocks; ++i) {
+ ret = clk_enable(iommu->clocks[i]);
+ if (ret)
+ goto err_disable;
+ }
+
+ return 0;
+
+err_disable:
+ for (--i; i >= 0; --i)
+ clk_disable(iommu->clocks[i]);
+
+ return ret;
+}
+
+static void rk_iommu_disable_clocks(struct rk_iommu *iommu)
+{
+ int i;
+
+ for (i = 0; i < iommu->num_clocks; ++i)
+ clk_disable(iommu->clocks[i]);
+}
+
static void log_iova(struct rk_iommu *iommu, int index, dma_addr_t iova)
{
void __iomem *base = iommu->bases[index];
@@ -499,6 +579,8 @@ static irqreturn_t rk_iommu_irq(int irq, void *dev_id)
irqreturn_t ret = IRQ_NONE;
int i;
+ WARN_ON(rk_iommu_enable_clocks(iommu));
+
for (i = 0; i < iommu->num_mmu; i++) {
int_status = rk_iommu_read(iommu->bases[i], RK_MMU_INT_STATUS);
if (int_status == 0)
@@ -545,6 +627,8 @@ static irqreturn_t rk_iommu_irq(int irq, void *dev_id)
rk_iommu_write(iommu->bases[i], RK_MMU_INT_CLEAR, int_status);
}
+ rk_iommu_disable_clocks(iommu);
+
return ret;
}
@@ -587,7 +671,9 @@ static void rk_iommu_zap_iova(struct rk_iommu_domain *rk_domain,
list_for_each(pos, &rk_domain->iommus) {
struct rk_iommu *iommu;
iommu = list_entry(pos, struct rk_iommu, node);
+ rk_iommu_enable_clocks(iommu);
rk_iommu_zap_lines(iommu, iova, size);
+ rk_iommu_disable_clocks(iommu);
}
spin_unlock_irqrestore(&rk_domain->iommus_lock, flags);
}
@@ -816,10 +902,14 @@ static int rk_iommu_attach_device(struct iommu_domain *domain,
if (!iommu)
return 0;
- ret = rk_iommu_enable_stall(iommu);
+ ret = rk_iommu_enable_clocks(iommu);
if (ret)
return ret;
+ ret = rk_iommu_enable_stall(iommu);
+ if (ret)
+ goto err_disable_clocks;
+
ret = rk_iommu_force_reset(iommu);
if (ret)
goto err_disable_stall;
@@ -844,11 +934,14 @@ static int rk_iommu_attach_device(struct iommu_domain *domain,
dev_dbg(dev, "Attached to iommu domain\n");
rk_iommu_disable_stall(iommu);
+ rk_iommu_disable_clocks(iommu);
return 0;
err_disable_stall:
rk_iommu_disable_stall(iommu);
+err_disable_clocks:
+ rk_iommu_disable_clocks(iommu);
return ret;
}
@@ -871,6 +964,7 @@ static void rk_iommu_detach_device(struct iommu_domain *domain,
spin_unlock_irqrestore(&rk_domain->iommus_lock, flags);
/* Ignore error while disabling, just keep going */
+ WARN_ON(rk_iommu_enable_clocks(iommu));
rk_iommu_enable_stall(iommu);
rk_iommu_disable_paging(iommu);
for (i = 0; i < iommu->num_mmu; i++) {
@@ -878,6 +972,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);
+ rk_iommu_disable_clocks(iommu);
iommu->domain = NULL;
@@ -1167,21 +1262,28 @@ static int rk_iommu_probe(struct platform_device *pdev)
return err;
}
+ err = rk_iommu_get_clocks(iommu);
+ if (err)
+ return err;
+
iommu->reset_disabled = device_property_read_bool(dev,
"rockchip,disable-mmu-reset");
err = iommu_device_sysfs_add(&iommu->iommu, dev, NULL, dev_name(dev));
if (err)
- return err;
+ goto err_put_clocks;
iommu_device_set_ops(&iommu->iommu, &rk_iommu_ops);
err = iommu_device_register(&iommu->iommu);
- if (err) {
- iommu_device_sysfs_remove(&iommu->iommu);
- return err;
- }
+ if (err)
+ goto err_remove_sysfs;
return 0;
+err_remove_sysfs:
+ iommu_device_sysfs_remove(&iommu->iommu);
+err_put_clocks:
+ rk_iommu_put_clocks(iommu);
+ return err;
}
static const struct of_device_id rk_iommu_dt_ids[] = {
--
2.11.0
^ permalink raw reply related [flat|nested] 101+ messages in thread* [PATCH v4 08/13] iommu/rockchip: Control clocks needed to access the IOMMU
@ 2018-01-18 11:52 ` Jeffy Chen
0 siblings, 0 replies; 101+ messages in thread
From: Jeffy Chen @ 2018-01-18 11:52 UTC (permalink / raw)
To: linux-arm-kernel
From: Tomasz Figa <tfiga@chromium.org>
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 <jeffy.chen@rock-chips.com>
Signed-off-by: Tomasz Figa <tfiga@chromium.org>
---
Changes in v4: None
Changes in v3: None
Changes in v2: None
.../devicetree/bindings/iommu/rockchip,iommu.txt | 8 ++
drivers/iommu/rockchip-iommu.c | 114 +++++++++++++++++++--
2 files changed, 116 insertions(+), 6 deletions(-)
diff --git a/Documentation/devicetree/bindings/iommu/rockchip,iommu.txt b/Documentation/devicetree/bindings/iommu/rockchip,iommu.txt
index 2098f7732264..33dd853359fa 100644
--- a/Documentation/devicetree/bindings/iommu/rockchip,iommu.txt
+++ b/Documentation/devicetree/bindings/iommu/rockchip,iommu.txt
@@ -14,6 +14,13 @@ Required properties:
"single-master" device, and needs no additional information
to associate with its master device. See:
Documentation/devicetree/bindings/iommu/iommu.txt
+Optional properties:
+- clocks : A list of master clocks requires for the IOMMU to be accessible
+ by the host CPU. The number of clocks depends on the master
+ block and might as well be zero. See [1] for generic clock
+ bindings description.
+
+[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
Optional properties:
- rockchip,disable-mmu-reset : Don't use the mmu reset operation.
@@ -27,5 +34,6 @@ Example:
reg = <0xff940300 0x100>;
interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "vopl_mmu";
+ clocks = <&cru ACLK_VOP1>, <&cru DCLK_VOP1>, <&cru HCLK_VOP1>;
#iommu-cells = <0>;
};
diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c
index 1914ac52042c..9b85a3050449 100644
--- a/drivers/iommu/rockchip-iommu.c
+++ b/drivers/iommu/rockchip-iommu.c
@@ -4,6 +4,7 @@
* published by the Free Software Foundation.
*/
+#include <linux/clk.h>
#include <linux/compiler.h>
#include <linux/delay.h>
#include <linux/device.h>
@@ -89,6 +90,8 @@ struct rk_iommu {
struct device *dev;
void __iomem **bases;
int num_mmu;
+ struct clk **clocks;
+ int num_clocks;
bool reset_disabled;
struct iommu_device iommu;
struct list_head node; /* entry in rk_iommu_domain.iommus */
@@ -443,6 +446,83 @@ static int rk_iommu_force_reset(struct rk_iommu *iommu)
return 0;
}
+static void rk_iommu_put_clocks(struct rk_iommu *iommu)
+{
+ int i;
+
+ for (i = 0; i < iommu->num_clocks; ++i) {
+ clk_unprepare(iommu->clocks[i]);
+ clk_put(iommu->clocks[i]);
+ }
+}
+
+static int rk_iommu_get_clocks(struct rk_iommu *iommu)
+{
+ struct device_node *np = iommu->dev->of_node;
+ int ret;
+ int i;
+
+ ret = of_count_phandle_with_args(np, "clocks", "#clock-cells");
+ if (ret == -ENOENT)
+ return 0;
+ else if (ret < 0)
+ return ret;
+
+ iommu->num_clocks = ret;
+ iommu->clocks = devm_kcalloc(iommu->dev, iommu->num_clocks,
+ sizeof(*iommu->clocks), GFP_KERNEL);
+ if (!iommu->clocks)
+ return -ENOMEM;
+
+ for (i = 0; i < iommu->num_clocks; ++i) {
+ iommu->clocks[i] = of_clk_get(np, i);
+ if (IS_ERR(iommu->clocks[i])) {
+ iommu->num_clocks = i;
+ goto err_clk_put;
+ }
+ ret = clk_prepare(iommu->clocks[i]);
+ if (ret) {
+ clk_put(iommu->clocks[i]);
+ iommu->num_clocks = i;
+ goto err_clk_put;
+ }
+ }
+
+ return 0;
+
+err_clk_put:
+ rk_iommu_put_clocks(iommu);
+
+ return ret;
+}
+
+static int rk_iommu_enable_clocks(struct rk_iommu *iommu)
+{
+ int i, ret;
+
+ for (i = 0; i < iommu->num_clocks; ++i) {
+ ret = clk_enable(iommu->clocks[i]);
+ if (ret)
+ goto err_disable;
+ }
+
+ return 0;
+
+err_disable:
+ for (--i; i >= 0; --i)
+ clk_disable(iommu->clocks[i]);
+
+ return ret;
+}
+
+static void rk_iommu_disable_clocks(struct rk_iommu *iommu)
+{
+ int i;
+
+ for (i = 0; i < iommu->num_clocks; ++i)
+ clk_disable(iommu->clocks[i]);
+}
+
static void log_iova(struct rk_iommu *iommu, int index, dma_addr_t iova)
{
void __iomem *base = iommu->bases[index];
@@ -499,6 +579,8 @@ static irqreturn_t rk_iommu_irq(int irq, void *dev_id)
irqreturn_t ret = IRQ_NONE;
int i;
+ WARN_ON(rk_iommu_enable_clocks(iommu));
+
for (i = 0; i < iommu->num_mmu; i++) {
int_status = rk_iommu_read(iommu->bases[i], RK_MMU_INT_STATUS);
if (int_status == 0)
@@ -545,6 +627,8 @@ static irqreturn_t rk_iommu_irq(int irq, void *dev_id)
rk_iommu_write(iommu->bases[i], RK_MMU_INT_CLEAR, int_status);
}
+ rk_iommu_disable_clocks(iommu);
+
return ret;
}
@@ -587,7 +671,9 @@ static void rk_iommu_zap_iova(struct rk_iommu_domain *rk_domain,
list_for_each(pos, &rk_domain->iommus) {
struct rk_iommu *iommu;
iommu = list_entry(pos, struct rk_iommu, node);
+ rk_iommu_enable_clocks(iommu);
rk_iommu_zap_lines(iommu, iova, size);
+ rk_iommu_disable_clocks(iommu);
}
spin_unlock_irqrestore(&rk_domain->iommus_lock, flags);
}
@@ -816,10 +902,14 @@ static int rk_iommu_attach_device(struct iommu_domain *domain,
if (!iommu)
return 0;
- ret = rk_iommu_enable_stall(iommu);
+ ret = rk_iommu_enable_clocks(iommu);
if (ret)
return ret;
+ ret = rk_iommu_enable_stall(iommu);
+ if (ret)
+ goto err_disable_clocks;
+
ret = rk_iommu_force_reset(iommu);
if (ret)
goto err_disable_stall;
@@ -844,11 +934,14 @@ static int rk_iommu_attach_device(struct iommu_domain *domain,
dev_dbg(dev, "Attached to iommu domain\n");
rk_iommu_disable_stall(iommu);
+ rk_iommu_disable_clocks(iommu);
return 0;
err_disable_stall:
rk_iommu_disable_stall(iommu);
+err_disable_clocks:
+ rk_iommu_disable_clocks(iommu);
return ret;
}
@@ -871,6 +964,7 @@ static void rk_iommu_detach_device(struct iommu_domain *domain,
spin_unlock_irqrestore(&rk_domain->iommus_lock, flags);
/* Ignore error while disabling, just keep going */
+ WARN_ON(rk_iommu_enable_clocks(iommu));
rk_iommu_enable_stall(iommu);
rk_iommu_disable_paging(iommu);
for (i = 0; i < iommu->num_mmu; i++) {
@@ -878,6 +972,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);
+ rk_iommu_disable_clocks(iommu);
iommu->domain = NULL;
@@ -1167,21 +1262,28 @@ static int rk_iommu_probe(struct platform_device *pdev)
return err;
}
+ err = rk_iommu_get_clocks(iommu);
+ if (err)
+ return err;
+
iommu->reset_disabled = device_property_read_bool(dev,
"rockchip,disable-mmu-reset");
err = iommu_device_sysfs_add(&iommu->iommu, dev, NULL, dev_name(dev));
if (err)
- return err;
+ goto err_put_clocks;
iommu_device_set_ops(&iommu->iommu, &rk_iommu_ops);
err = iommu_device_register(&iommu->iommu);
- if (err) {
- iommu_device_sysfs_remove(&iommu->iommu);
- return err;
- }
+ if (err)
+ goto err_remove_sysfs;
return 0;
+err_remove_sysfs:
+ iommu_device_sysfs_remove(&iommu->iommu);
+err_put_clocks:
+ rk_iommu_put_clocks(iommu);
+ return err;
}
static const struct of_device_id rk_iommu_dt_ids[] = {
--
2.11.0
^ permalink raw reply related [flat|nested] 101+ messages in thread[parent not found: <20180118115251.5542-9-jeffy.chen-TNX95d0MmH7DzftRWevZcw@public.gmane.org>]
* Re: [PATCH v4 08/13] iommu/rockchip: Control clocks needed to access the IOMMU
2018-01-18 11:52 ` Jeffy Chen
(?)
@ 2018-01-18 12:27 ` Robin Murphy
-1 siblings, 0 replies; 101+ messages in thread
From: Robin Murphy @ 2018-01-18 12:27 UTC (permalink / raw)
To: Jeffy Chen, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
tfiga-F7+t8E8rja9g9hUCZPvPmw
Cc: jcliang-F7+t8E8rja9g9hUCZPvPmw, xxm-TNX95d0MmH7DzftRWevZcw,
devicetree-u79uwXL29TY76Z2rM5mHXA, Heiko Stuebner,
linux-rockchip-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA, Rob Herring,
Mark Rutland, Joerg Roedel,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
On 18/01/18 11:52, Jeffy Chen wrote:
> From: Tomasz Figa <tfiga-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
>
> 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.
Is it worth using the clk_bulk_*() APIs for this? At a glance, most of
the code being added here appears to duplicate what those functions
already do (but I'm no clk API expert, for sure).
Robin.
> Signed-off-by: Jeffy Chen <jeffy.chen-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
> Signed-off-by: Tomasz Figa <tfiga-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
> ---
>
> Changes in v4: None
> Changes in v3: None
> Changes in v2: None
>
> .../devicetree/bindings/iommu/rockchip,iommu.txt | 8 ++
> drivers/iommu/rockchip-iommu.c | 114 +++++++++++++++++++--
> 2 files changed, 116 insertions(+), 6 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/iommu/rockchip,iommu.txt b/Documentation/devicetree/bindings/iommu/rockchip,iommu.txt
> index 2098f7732264..33dd853359fa 100644
> --- a/Documentation/devicetree/bindings/iommu/rockchip,iommu.txt
> +++ b/Documentation/devicetree/bindings/iommu/rockchip,iommu.txt
> @@ -14,6 +14,13 @@ Required properties:
> "single-master" device, and needs no additional information
> to associate with its master device. See:
> Documentation/devicetree/bindings/iommu/iommu.txt
> +Optional properties:
> +- clocks : A list of master clocks requires for the IOMMU to be accessible
> + by the host CPU. The number of clocks depends on the master
> + block and might as well be zero. See [1] for generic clock
> + bindings description.
> +
> +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
>
> Optional properties:
> - rockchip,disable-mmu-reset : Don't use the mmu reset operation.
> @@ -27,5 +34,6 @@ Example:
> reg = <0xff940300 0x100>;
> interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>;
> interrupt-names = "vopl_mmu";
> + clocks = <&cru ACLK_VOP1>, <&cru DCLK_VOP1>, <&cru HCLK_VOP1>;
> #iommu-cells = <0>;
> };
> diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c
> index 1914ac52042c..9b85a3050449 100644
> --- a/drivers/iommu/rockchip-iommu.c
> +++ b/drivers/iommu/rockchip-iommu.c
> @@ -4,6 +4,7 @@
> * published by the Free Software Foundation.
> */
>
> +#include <linux/clk.h>
> #include <linux/compiler.h>
> #include <linux/delay.h>
> #include <linux/device.h>
> @@ -89,6 +90,8 @@ struct rk_iommu {
> struct device *dev;
> void __iomem **bases;
> int num_mmu;
> + struct clk **clocks;
> + int num_clocks;
> bool reset_disabled;
> struct iommu_device iommu;
> struct list_head node; /* entry in rk_iommu_domain.iommus */
> @@ -443,6 +446,83 @@ static int rk_iommu_force_reset(struct rk_iommu *iommu)
> return 0;
> }
>
> +static void rk_iommu_put_clocks(struct rk_iommu *iommu)
> +{
> + int i;
> +
> + for (i = 0; i < iommu->num_clocks; ++i) {
> + clk_unprepare(iommu->clocks[i]);
> + clk_put(iommu->clocks[i]);
> + }
> +}
> +
> +static int rk_iommu_get_clocks(struct rk_iommu *iommu)
> +{
> + struct device_node *np = iommu->dev->of_node;
> + int ret;
> + int i;
> +
> + ret = of_count_phandle_with_args(np, "clocks", "#clock-cells");
> + if (ret == -ENOENT)
> + return 0;
> + else if (ret < 0)
> + return ret;
> +
> + iommu->num_clocks = ret;
> + iommu->clocks = devm_kcalloc(iommu->dev, iommu->num_clocks,
> + sizeof(*iommu->clocks), GFP_KERNEL);
> + if (!iommu->clocks)
> + return -ENOMEM;
> +
> + for (i = 0; i < iommu->num_clocks; ++i) {
> + iommu->clocks[i] = of_clk_get(np, i);
> + if (IS_ERR(iommu->clocks[i])) {
> + iommu->num_clocks = i;
> + goto err_clk_put;
> + }
> + ret = clk_prepare(iommu->clocks[i]);
> + if (ret) {
> + clk_put(iommu->clocks[i]);
> + iommu->num_clocks = i;
> + goto err_clk_put;
> + }
> + }
> +
> + return 0;
> +
> +err_clk_put:
> + rk_iommu_put_clocks(iommu);
> +
> + return ret;
> +}
> +
> +static int rk_iommu_enable_clocks(struct rk_iommu *iommu)
> +{
> + int i, ret;
> +
> + for (i = 0; i < iommu->num_clocks; ++i) {
> + ret = clk_enable(iommu->clocks[i]);
> + if (ret)
> + goto err_disable;
> + }
> +
> + return 0;
> +
> +err_disable:
> + for (--i; i >= 0; --i)
> + clk_disable(iommu->clocks[i]);
> +
> + return ret;
> +}
> +
> +static void rk_iommu_disable_clocks(struct rk_iommu *iommu)
> +{
> + int i;
> +
> + for (i = 0; i < iommu->num_clocks; ++i)
> + clk_disable(iommu->clocks[i]);
> +}
> +
> static void log_iova(struct rk_iommu *iommu, int index, dma_addr_t iova)
> {
> void __iomem *base = iommu->bases[index];
> @@ -499,6 +579,8 @@ static irqreturn_t rk_iommu_irq(int irq, void *dev_id)
> irqreturn_t ret = IRQ_NONE;
> int i;
>
> + WARN_ON(rk_iommu_enable_clocks(iommu));
> +
> for (i = 0; i < iommu->num_mmu; i++) {
> int_status = rk_iommu_read(iommu->bases[i], RK_MMU_INT_STATUS);
> if (int_status == 0)
> @@ -545,6 +627,8 @@ static irqreturn_t rk_iommu_irq(int irq, void *dev_id)
> rk_iommu_write(iommu->bases[i], RK_MMU_INT_CLEAR, int_status);
> }
>
> + rk_iommu_disable_clocks(iommu);
> +
> return ret;
> }
>
> @@ -587,7 +671,9 @@ static void rk_iommu_zap_iova(struct rk_iommu_domain *rk_domain,
> list_for_each(pos, &rk_domain->iommus) {
> struct rk_iommu *iommu;
> iommu = list_entry(pos, struct rk_iommu, node);
> + rk_iommu_enable_clocks(iommu);
> rk_iommu_zap_lines(iommu, iova, size);
> + rk_iommu_disable_clocks(iommu);
> }
> spin_unlock_irqrestore(&rk_domain->iommus_lock, flags);
> }
> @@ -816,10 +902,14 @@ static int rk_iommu_attach_device(struct iommu_domain *domain,
> if (!iommu)
> return 0;
>
> - ret = rk_iommu_enable_stall(iommu);
> + ret = rk_iommu_enable_clocks(iommu);
> if (ret)
> return ret;
>
> + ret = rk_iommu_enable_stall(iommu);
> + if (ret)
> + goto err_disable_clocks;
> +
> ret = rk_iommu_force_reset(iommu);
> if (ret)
> goto err_disable_stall;
> @@ -844,11 +934,14 @@ static int rk_iommu_attach_device(struct iommu_domain *domain,
> dev_dbg(dev, "Attached to iommu domain\n");
>
> rk_iommu_disable_stall(iommu);
> + rk_iommu_disable_clocks(iommu);
>
> return 0;
>
> err_disable_stall:
> rk_iommu_disable_stall(iommu);
> +err_disable_clocks:
> + rk_iommu_disable_clocks(iommu);
>
> return ret;
> }
> @@ -871,6 +964,7 @@ static void rk_iommu_detach_device(struct iommu_domain *domain,
> spin_unlock_irqrestore(&rk_domain->iommus_lock, flags);
>
> /* Ignore error while disabling, just keep going */
> + WARN_ON(rk_iommu_enable_clocks(iommu));
> rk_iommu_enable_stall(iommu);
> rk_iommu_disable_paging(iommu);
> for (i = 0; i < iommu->num_mmu; i++) {
> @@ -878,6 +972,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);
> + rk_iommu_disable_clocks(iommu);
>
> iommu->domain = NULL;
>
> @@ -1167,21 +1262,28 @@ static int rk_iommu_probe(struct platform_device *pdev)
> return err;
> }
>
> + err = rk_iommu_get_clocks(iommu);
> + if (err)
> + return err;
> +
> iommu->reset_disabled = device_property_read_bool(dev,
> "rockchip,disable-mmu-reset");
>
> err = iommu_device_sysfs_add(&iommu->iommu, dev, NULL, dev_name(dev));
> if (err)
> - return err;
> + goto err_put_clocks;
>
> iommu_device_set_ops(&iommu->iommu, &rk_iommu_ops);
> err = iommu_device_register(&iommu->iommu);
> - if (err) {
> - iommu_device_sysfs_remove(&iommu->iommu);
> - return err;
> - }
> + if (err)
> + goto err_remove_sysfs;
>
> return 0;
> +err_remove_sysfs:
> + iommu_device_sysfs_remove(&iommu->iommu);
> +err_put_clocks:
> + rk_iommu_put_clocks(iommu);
> + return err;
> }
>
> static const struct of_device_id rk_iommu_dt_ids[] = {
>
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 101+ messages in thread* Re: [PATCH v4 08/13] iommu/rockchip: Control clocks needed to access the IOMMU
@ 2018-01-18 12:27 ` Robin Murphy
0 siblings, 0 replies; 101+ messages in thread
From: Robin Murphy @ 2018-01-18 12:27 UTC (permalink / raw)
To: Jeffy Chen, linux-kernel, tfiga
Cc: jcliang, xxm, devicetree, Heiko Stuebner, linux-rockchip, iommu,
Rob Herring, Mark Rutland, Joerg Roedel, linux-arm-kernel
On 18/01/18 11:52, Jeffy Chen wrote:
> From: Tomasz Figa <tfiga@chromium.org>
>
> 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.
Is it worth using the clk_bulk_*() APIs for this? At a glance, most of
the code being added here appears to duplicate what those functions
already do (but I'm no clk API expert, for sure).
Robin.
> Signed-off-by: Jeffy Chen <jeffy.chen@rock-chips.com>
> Signed-off-by: Tomasz Figa <tfiga@chromium.org>
> ---
>
> Changes in v4: None
> Changes in v3: None
> Changes in v2: None
>
> .../devicetree/bindings/iommu/rockchip,iommu.txt | 8 ++
> drivers/iommu/rockchip-iommu.c | 114 +++++++++++++++++++--
> 2 files changed, 116 insertions(+), 6 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/iommu/rockchip,iommu.txt b/Documentation/devicetree/bindings/iommu/rockchip,iommu.txt
> index 2098f7732264..33dd853359fa 100644
> --- a/Documentation/devicetree/bindings/iommu/rockchip,iommu.txt
> +++ b/Documentation/devicetree/bindings/iommu/rockchip,iommu.txt
> @@ -14,6 +14,13 @@ Required properties:
> "single-master" device, and needs no additional information
> to associate with its master device. See:
> Documentation/devicetree/bindings/iommu/iommu.txt
> +Optional properties:
> +- clocks : A list of master clocks requires for the IOMMU to be accessible
> + by the host CPU. The number of clocks depends on the master
> + block and might as well be zero. See [1] for generic clock
> + bindings description.
> +
> +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
>
> Optional properties:
> - rockchip,disable-mmu-reset : Don't use the mmu reset operation.
> @@ -27,5 +34,6 @@ Example:
> reg = <0xff940300 0x100>;
> interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>;
> interrupt-names = "vopl_mmu";
> + clocks = <&cru ACLK_VOP1>, <&cru DCLK_VOP1>, <&cru HCLK_VOP1>;
> #iommu-cells = <0>;
> };
> diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c
> index 1914ac52042c..9b85a3050449 100644
> --- a/drivers/iommu/rockchip-iommu.c
> +++ b/drivers/iommu/rockchip-iommu.c
> @@ -4,6 +4,7 @@
> * published by the Free Software Foundation.
> */
>
> +#include <linux/clk.h>
> #include <linux/compiler.h>
> #include <linux/delay.h>
> #include <linux/device.h>
> @@ -89,6 +90,8 @@ struct rk_iommu {
> struct device *dev;
> void __iomem **bases;
> int num_mmu;
> + struct clk **clocks;
> + int num_clocks;
> bool reset_disabled;
> struct iommu_device iommu;
> struct list_head node; /* entry in rk_iommu_domain.iommus */
> @@ -443,6 +446,83 @@ static int rk_iommu_force_reset(struct rk_iommu *iommu)
> return 0;
> }
>
> +static void rk_iommu_put_clocks(struct rk_iommu *iommu)
> +{
> + int i;
> +
> + for (i = 0; i < iommu->num_clocks; ++i) {
> + clk_unprepare(iommu->clocks[i]);
> + clk_put(iommu->clocks[i]);
> + }
> +}
> +
> +static int rk_iommu_get_clocks(struct rk_iommu *iommu)
> +{
> + struct device_node *np = iommu->dev->of_node;
> + int ret;
> + int i;
> +
> + ret = of_count_phandle_with_args(np, "clocks", "#clock-cells");
> + if (ret == -ENOENT)
> + return 0;
> + else if (ret < 0)
> + return ret;
> +
> + iommu->num_clocks = ret;
> + iommu->clocks = devm_kcalloc(iommu->dev, iommu->num_clocks,
> + sizeof(*iommu->clocks), GFP_KERNEL);
> + if (!iommu->clocks)
> + return -ENOMEM;
> +
> + for (i = 0; i < iommu->num_clocks; ++i) {
> + iommu->clocks[i] = of_clk_get(np, i);
> + if (IS_ERR(iommu->clocks[i])) {
> + iommu->num_clocks = i;
> + goto err_clk_put;
> + }
> + ret = clk_prepare(iommu->clocks[i]);
> + if (ret) {
> + clk_put(iommu->clocks[i]);
> + iommu->num_clocks = i;
> + goto err_clk_put;
> + }
> + }
> +
> + return 0;
> +
> +err_clk_put:
> + rk_iommu_put_clocks(iommu);
> +
> + return ret;
> +}
> +
> +static int rk_iommu_enable_clocks(struct rk_iommu *iommu)
> +{
> + int i, ret;
> +
> + for (i = 0; i < iommu->num_clocks; ++i) {
> + ret = clk_enable(iommu->clocks[i]);
> + if (ret)
> + goto err_disable;
> + }
> +
> + return 0;
> +
> +err_disable:
> + for (--i; i >= 0; --i)
> + clk_disable(iommu->clocks[i]);
> +
> + return ret;
> +}
> +
> +static void rk_iommu_disable_clocks(struct rk_iommu *iommu)
> +{
> + int i;
> +
> + for (i = 0; i < iommu->num_clocks; ++i)
> + clk_disable(iommu->clocks[i]);
> +}
> +
> static void log_iova(struct rk_iommu *iommu, int index, dma_addr_t iova)
> {
> void __iomem *base = iommu->bases[index];
> @@ -499,6 +579,8 @@ static irqreturn_t rk_iommu_irq(int irq, void *dev_id)
> irqreturn_t ret = IRQ_NONE;
> int i;
>
> + WARN_ON(rk_iommu_enable_clocks(iommu));
> +
> for (i = 0; i < iommu->num_mmu; i++) {
> int_status = rk_iommu_read(iommu->bases[i], RK_MMU_INT_STATUS);
> if (int_status == 0)
> @@ -545,6 +627,8 @@ static irqreturn_t rk_iommu_irq(int irq, void *dev_id)
> rk_iommu_write(iommu->bases[i], RK_MMU_INT_CLEAR, int_status);
> }
>
> + rk_iommu_disable_clocks(iommu);
> +
> return ret;
> }
>
> @@ -587,7 +671,9 @@ static void rk_iommu_zap_iova(struct rk_iommu_domain *rk_domain,
> list_for_each(pos, &rk_domain->iommus) {
> struct rk_iommu *iommu;
> iommu = list_entry(pos, struct rk_iommu, node);
> + rk_iommu_enable_clocks(iommu);
> rk_iommu_zap_lines(iommu, iova, size);
> + rk_iommu_disable_clocks(iommu);
> }
> spin_unlock_irqrestore(&rk_domain->iommus_lock, flags);
> }
> @@ -816,10 +902,14 @@ static int rk_iommu_attach_device(struct iommu_domain *domain,
> if (!iommu)
> return 0;
>
> - ret = rk_iommu_enable_stall(iommu);
> + ret = rk_iommu_enable_clocks(iommu);
> if (ret)
> return ret;
>
> + ret = rk_iommu_enable_stall(iommu);
> + if (ret)
> + goto err_disable_clocks;
> +
> ret = rk_iommu_force_reset(iommu);
> if (ret)
> goto err_disable_stall;
> @@ -844,11 +934,14 @@ static int rk_iommu_attach_device(struct iommu_domain *domain,
> dev_dbg(dev, "Attached to iommu domain\n");
>
> rk_iommu_disable_stall(iommu);
> + rk_iommu_disable_clocks(iommu);
>
> return 0;
>
> err_disable_stall:
> rk_iommu_disable_stall(iommu);
> +err_disable_clocks:
> + rk_iommu_disable_clocks(iommu);
>
> return ret;
> }
> @@ -871,6 +964,7 @@ static void rk_iommu_detach_device(struct iommu_domain *domain,
> spin_unlock_irqrestore(&rk_domain->iommus_lock, flags);
>
> /* Ignore error while disabling, just keep going */
> + WARN_ON(rk_iommu_enable_clocks(iommu));
> rk_iommu_enable_stall(iommu);
> rk_iommu_disable_paging(iommu);
> for (i = 0; i < iommu->num_mmu; i++) {
> @@ -878,6 +972,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);
> + rk_iommu_disable_clocks(iommu);
>
> iommu->domain = NULL;
>
> @@ -1167,21 +1262,28 @@ static int rk_iommu_probe(struct platform_device *pdev)
> return err;
> }
>
> + err = rk_iommu_get_clocks(iommu);
> + if (err)
> + return err;
> +
> iommu->reset_disabled = device_property_read_bool(dev,
> "rockchip,disable-mmu-reset");
>
> err = iommu_device_sysfs_add(&iommu->iommu, dev, NULL, dev_name(dev));
> if (err)
> - return err;
> + goto err_put_clocks;
>
> iommu_device_set_ops(&iommu->iommu, &rk_iommu_ops);
> err = iommu_device_register(&iommu->iommu);
> - if (err) {
> - iommu_device_sysfs_remove(&iommu->iommu);
> - return err;
> - }
> + if (err)
> + goto err_remove_sysfs;
>
> return 0;
> +err_remove_sysfs:
> + iommu_device_sysfs_remove(&iommu->iommu);
> +err_put_clocks:
> + rk_iommu_put_clocks(iommu);
> + return err;
> }
>
> static const struct of_device_id rk_iommu_dt_ids[] = {
>
^ permalink raw reply [flat|nested] 101+ messages in thread* [PATCH v4 08/13] iommu/rockchip: Control clocks needed to access the IOMMU
@ 2018-01-18 12:27 ` Robin Murphy
0 siblings, 0 replies; 101+ messages in thread
From: Robin Murphy @ 2018-01-18 12:27 UTC (permalink / raw)
To: linux-arm-kernel
On 18/01/18 11:52, Jeffy Chen wrote:
> From: Tomasz Figa <tfiga@chromium.org>
>
> 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.
Is it worth using the clk_bulk_*() APIs for this? At a glance, most of
the code being added here appears to duplicate what those functions
already do (but I'm no clk API expert, for sure).
Robin.
> Signed-off-by: Jeffy Chen <jeffy.chen@rock-chips.com>
> Signed-off-by: Tomasz Figa <tfiga@chromium.org>
> ---
>
> Changes in v4: None
> Changes in v3: None
> Changes in v2: None
>
> .../devicetree/bindings/iommu/rockchip,iommu.txt | 8 ++
> drivers/iommu/rockchip-iommu.c | 114 +++++++++++++++++++--
> 2 files changed, 116 insertions(+), 6 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/iommu/rockchip,iommu.txt b/Documentation/devicetree/bindings/iommu/rockchip,iommu.txt
> index 2098f7732264..33dd853359fa 100644
> --- a/Documentation/devicetree/bindings/iommu/rockchip,iommu.txt
> +++ b/Documentation/devicetree/bindings/iommu/rockchip,iommu.txt
> @@ -14,6 +14,13 @@ Required properties:
> "single-master" device, and needs no additional information
> to associate with its master device. See:
> Documentation/devicetree/bindings/iommu/iommu.txt
> +Optional properties:
> +- clocks : A list of master clocks requires for the IOMMU to be accessible
> + by the host CPU. The number of clocks depends on the master
> + block and might as well be zero. See [1] for generic clock
> + bindings description.
> +
> +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
>
> Optional properties:
> - rockchip,disable-mmu-reset : Don't use the mmu reset operation.
> @@ -27,5 +34,6 @@ Example:
> reg = <0xff940300 0x100>;
> interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>;
> interrupt-names = "vopl_mmu";
> + clocks = <&cru ACLK_VOP1>, <&cru DCLK_VOP1>, <&cru HCLK_VOP1>;
> #iommu-cells = <0>;
> };
> diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c
> index 1914ac52042c..9b85a3050449 100644
> --- a/drivers/iommu/rockchip-iommu.c
> +++ b/drivers/iommu/rockchip-iommu.c
> @@ -4,6 +4,7 @@
> * published by the Free Software Foundation.
> */
>
> +#include <linux/clk.h>
> #include <linux/compiler.h>
> #include <linux/delay.h>
> #include <linux/device.h>
> @@ -89,6 +90,8 @@ struct rk_iommu {
> struct device *dev;
> void __iomem **bases;
> int num_mmu;
> + struct clk **clocks;
> + int num_clocks;
> bool reset_disabled;
> struct iommu_device iommu;
> struct list_head node; /* entry in rk_iommu_domain.iommus */
> @@ -443,6 +446,83 @@ static int rk_iommu_force_reset(struct rk_iommu *iommu)
> return 0;
> }
>
> +static void rk_iommu_put_clocks(struct rk_iommu *iommu)
> +{
> + int i;
> +
> + for (i = 0; i < iommu->num_clocks; ++i) {
> + clk_unprepare(iommu->clocks[i]);
> + clk_put(iommu->clocks[i]);
> + }
> +}
> +
> +static int rk_iommu_get_clocks(struct rk_iommu *iommu)
> +{
> + struct device_node *np = iommu->dev->of_node;
> + int ret;
> + int i;
> +
> + ret = of_count_phandle_with_args(np, "clocks", "#clock-cells");
> + if (ret == -ENOENT)
> + return 0;
> + else if (ret < 0)
> + return ret;
> +
> + iommu->num_clocks = ret;
> + iommu->clocks = devm_kcalloc(iommu->dev, iommu->num_clocks,
> + sizeof(*iommu->clocks), GFP_KERNEL);
> + if (!iommu->clocks)
> + return -ENOMEM;
> +
> + for (i = 0; i < iommu->num_clocks; ++i) {
> + iommu->clocks[i] = of_clk_get(np, i);
> + if (IS_ERR(iommu->clocks[i])) {
> + iommu->num_clocks = i;
> + goto err_clk_put;
> + }
> + ret = clk_prepare(iommu->clocks[i]);
> + if (ret) {
> + clk_put(iommu->clocks[i]);
> + iommu->num_clocks = i;
> + goto err_clk_put;
> + }
> + }
> +
> + return 0;
> +
> +err_clk_put:
> + rk_iommu_put_clocks(iommu);
> +
> + return ret;
> +}
> +
> +static int rk_iommu_enable_clocks(struct rk_iommu *iommu)
> +{
> + int i, ret;
> +
> + for (i = 0; i < iommu->num_clocks; ++i) {
> + ret = clk_enable(iommu->clocks[i]);
> + if (ret)
> + goto err_disable;
> + }
> +
> + return 0;
> +
> +err_disable:
> + for (--i; i >= 0; --i)
> + clk_disable(iommu->clocks[i]);
> +
> + return ret;
> +}
> +
> +static void rk_iommu_disable_clocks(struct rk_iommu *iommu)
> +{
> + int i;
> +
> + for (i = 0; i < iommu->num_clocks; ++i)
> + clk_disable(iommu->clocks[i]);
> +}
> +
> static void log_iova(struct rk_iommu *iommu, int index, dma_addr_t iova)
> {
> void __iomem *base = iommu->bases[index];
> @@ -499,6 +579,8 @@ static irqreturn_t rk_iommu_irq(int irq, void *dev_id)
> irqreturn_t ret = IRQ_NONE;
> int i;
>
> + WARN_ON(rk_iommu_enable_clocks(iommu));
> +
> for (i = 0; i < iommu->num_mmu; i++) {
> int_status = rk_iommu_read(iommu->bases[i], RK_MMU_INT_STATUS);
> if (int_status == 0)
> @@ -545,6 +627,8 @@ static irqreturn_t rk_iommu_irq(int irq, void *dev_id)
> rk_iommu_write(iommu->bases[i], RK_MMU_INT_CLEAR, int_status);
> }
>
> + rk_iommu_disable_clocks(iommu);
> +
> return ret;
> }
>
> @@ -587,7 +671,9 @@ static void rk_iommu_zap_iova(struct rk_iommu_domain *rk_domain,
> list_for_each(pos, &rk_domain->iommus) {
> struct rk_iommu *iommu;
> iommu = list_entry(pos, struct rk_iommu, node);
> + rk_iommu_enable_clocks(iommu);
> rk_iommu_zap_lines(iommu, iova, size);
> + rk_iommu_disable_clocks(iommu);
> }
> spin_unlock_irqrestore(&rk_domain->iommus_lock, flags);
> }
> @@ -816,10 +902,14 @@ static int rk_iommu_attach_device(struct iommu_domain *domain,
> if (!iommu)
> return 0;
>
> - ret = rk_iommu_enable_stall(iommu);
> + ret = rk_iommu_enable_clocks(iommu);
> if (ret)
> return ret;
>
> + ret = rk_iommu_enable_stall(iommu);
> + if (ret)
> + goto err_disable_clocks;
> +
> ret = rk_iommu_force_reset(iommu);
> if (ret)
> goto err_disable_stall;
> @@ -844,11 +934,14 @@ static int rk_iommu_attach_device(struct iommu_domain *domain,
> dev_dbg(dev, "Attached to iommu domain\n");
>
> rk_iommu_disable_stall(iommu);
> + rk_iommu_disable_clocks(iommu);
>
> return 0;
>
> err_disable_stall:
> rk_iommu_disable_stall(iommu);
> +err_disable_clocks:
> + rk_iommu_disable_clocks(iommu);
>
> return ret;
> }
> @@ -871,6 +964,7 @@ static void rk_iommu_detach_device(struct iommu_domain *domain,
> spin_unlock_irqrestore(&rk_domain->iommus_lock, flags);
>
> /* Ignore error while disabling, just keep going */
> + WARN_ON(rk_iommu_enable_clocks(iommu));
> rk_iommu_enable_stall(iommu);
> rk_iommu_disable_paging(iommu);
> for (i = 0; i < iommu->num_mmu; i++) {
> @@ -878,6 +972,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);
> + rk_iommu_disable_clocks(iommu);
>
> iommu->domain = NULL;
>
> @@ -1167,21 +1262,28 @@ static int rk_iommu_probe(struct platform_device *pdev)
> return err;
> }
>
> + err = rk_iommu_get_clocks(iommu);
> + if (err)
> + return err;
> +
> iommu->reset_disabled = device_property_read_bool(dev,
> "rockchip,disable-mmu-reset");
>
> err = iommu_device_sysfs_add(&iommu->iommu, dev, NULL, dev_name(dev));
> if (err)
> - return err;
> + goto err_put_clocks;
>
> iommu_device_set_ops(&iommu->iommu, &rk_iommu_ops);
> err = iommu_device_register(&iommu->iommu);
> - if (err) {
> - iommu_device_sysfs_remove(&iommu->iommu);
> - return err;
> - }
> + if (err)
> + goto err_remove_sysfs;
>
> return 0;
> +err_remove_sysfs:
> + iommu_device_sysfs_remove(&iommu->iommu);
> +err_put_clocks:
> + rk_iommu_put_clocks(iommu);
> + return err;
> }
>
> static const struct of_device_id rk_iommu_dt_ids[] = {
>
^ permalink raw reply [flat|nested] 101+ messages in thread* Re: [PATCH v4 08/13] iommu/rockchip: Control clocks needed to access the IOMMU
2018-01-18 12:27 ` Robin Murphy
@ 2018-01-18 14:25 ` JeffyChen
-1 siblings, 0 replies; 101+ messages in thread
From: JeffyChen @ 2018-01-18 14:25 UTC (permalink / raw)
To: Robin Murphy, linux-kernel, tfiga
Cc: jcliang, xxm, devicetree, Heiko Stuebner, linux-rockchip, iommu,
Rob Herring, Mark Rutland, Joerg Roedel, linux-arm-kernel
Hi Robin,
On 01/18/2018 08:27 PM, Robin Murphy wrote:
>>
>
> Is it worth using the clk_bulk_*() APIs for this? At a glance, most of
> the code being added here appears to duplicate what those functions
> already do (but I'm no clk API expert, for sure).
right, i think it's doable, the clk_bulk APIs are very helpful. i think
we didn't use that is because this patch were wrote for the chromeos 4.4
kernel, which doesn't have clk_bulk yet:)
will do it in the next version, thanks.
>
> Robin.
^ permalink raw reply [flat|nested] 101+ messages in thread
* [PATCH v4 08/13] iommu/rockchip: Control clocks needed to access the IOMMU
@ 2018-01-18 14:25 ` JeffyChen
0 siblings, 0 replies; 101+ messages in thread
From: JeffyChen @ 2018-01-18 14:25 UTC (permalink / raw)
To: linux-arm-kernel
Hi Robin,
On 01/18/2018 08:27 PM, Robin Murphy wrote:
>>
>
> Is it worth using the clk_bulk_*() APIs for this? At a glance, most of
> the code being added here appears to duplicate what those functions
> already do (but I'm no clk API expert, for sure).
right, i think it's doable, the clk_bulk APIs are very helpful. i think
we didn't use that is because this patch were wrote for the chromeos 4.4
kernel, which doesn't have clk_bulk yet:)
will do it in the next version, thanks.
>
> Robin.
^ permalink raw reply [flat|nested] 101+ messages in thread
[parent not found: <5A60AE41.2050101-TNX95d0MmH7DzftRWevZcw@public.gmane.org>]
* Re: [PATCH v4 08/13] iommu/rockchip: Control clocks needed to access the IOMMU
2018-01-18 14:25 ` JeffyChen
(?)
@ 2018-01-22 1:18 ` Randy Li
-1 siblings, 0 replies; 101+ messages in thread
From: Randy Li @ 2018-01-22 1:18 UTC (permalink / raw)
To: JeffyChen, Robin Murphy, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
tfiga-F7+t8E8rja9g9hUCZPvPmw
Cc: Mark Rutland, devicetree-u79uwXL29TY76Z2rM5mHXA,
xxm-TNX95d0MmH7DzftRWevZcw, Joerg Roedel,
jcliang-F7+t8E8rja9g9hUCZPvPmw,
linux-rockchip-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA, Rob Herring,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Heiko Stuebner
On 01/18/2018 10:25 PM, JeffyChen wrote:
> Hi Robin,
>
> On 01/18/2018 08:27 PM, Robin Murphy wrote:
>>>
>>
>> Is it worth using the clk_bulk_*() APIs for this? At a glance, most of
>> the code being added here appears to duplicate what those functions
>> already do (but I'm no clk API expert, for sure).
> right, i think it's doable, the clk_bulk APIs are very helpful. i think
> we didn't use that is because this patch were wrote for the chromeos 4.4
> kernel, which doesn't have clk_bulk yet:)
>
> will do it in the next version, thanks.
Also the power domain driver could manage the clocks as well, I would
suggest to use pm_runtime_*.
>>
>> Robin.
>
>
>
> _______________________________________________
> Linux-rockchip mailing list
> Linux-rockchip-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org
> http://lists.infradead.org/mailman/listinfo/linux-rockchip
>
--
Randy Li
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 101+ messages in thread
* Re: [PATCH v4 08/13] iommu/rockchip: Control clocks needed to access the IOMMU
@ 2018-01-22 1:18 ` Randy Li
0 siblings, 0 replies; 101+ messages in thread
From: Randy Li @ 2018-01-22 1:18 UTC (permalink / raw)
To: JeffyChen, Robin Murphy, linux-kernel, tfiga
Cc: Mark Rutland, devicetree, xxm, Joerg Roedel, jcliang,
linux-rockchip, iommu, Rob Herring, linux-arm-kernel,
Heiko Stuebner
On 01/18/2018 10:25 PM, JeffyChen wrote:
> Hi Robin,
>
> On 01/18/2018 08:27 PM, Robin Murphy wrote:
>>>
>>
>> Is it worth using the clk_bulk_*() APIs for this? At a glance, most of
>> the code being added here appears to duplicate what those functions
>> already do (but I'm no clk API expert, for sure).
> right, i think it's doable, the clk_bulk APIs are very helpful. i think
> we didn't use that is because this patch were wrote for the chromeos 4.4
> kernel, which doesn't have clk_bulk yet:)
>
> will do it in the next version, thanks.
Also the power domain driver could manage the clocks as well, I would
suggest to use pm_runtime_*.
>>
>> Robin.
>
>
>
> _______________________________________________
> Linux-rockchip mailing list
> Linux-rockchip@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-rockchip
>
--
Randy Li
^ permalink raw reply [flat|nested] 101+ messages in thread
* [PATCH v4 08/13] iommu/rockchip: Control clocks needed to access the IOMMU
@ 2018-01-22 1:18 ` Randy Li
0 siblings, 0 replies; 101+ messages in thread
From: Randy Li @ 2018-01-22 1:18 UTC (permalink / raw)
To: linux-arm-kernel
On 01/18/2018 10:25 PM, JeffyChen wrote:
> Hi Robin,
>
> On 01/18/2018 08:27 PM, Robin Murphy wrote:
>>>
>>
>> Is it worth using the clk_bulk_*() APIs for this? At a glance, most of
>> the code being added here appears to duplicate what those functions
>> already do (but I'm no clk API expert, for sure).
> right, i think it's doable, the clk_bulk APIs are very helpful. i think
> we didn't use that is because this patch were wrote for the chromeos 4.4
> kernel, which doesn't have clk_bulk yet:)
>
> will do it in the next version, thanks.
Also the power domain driver could manage the clocks as well, I would
suggest to use pm_runtime_*.
>>
>> Robin.
>
>
>
> _______________________________________________
> Linux-rockchip mailing list
> Linux-rockchip at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-rockchip
>
--
Randy Li
^ permalink raw reply [flat|nested] 101+ messages in thread
[parent not found: <1f4b3c0d-1414-0012-a072-f4a11f432c21-TNX95d0MmH7DzftRWevZcw@public.gmane.org>]
* Re: [PATCH v4 08/13] iommu/rockchip: Control clocks needed to access the IOMMU
2018-01-22 1:18 ` Randy Li
(?)
@ 2018-01-22 2:15 ` JeffyChen
-1 siblings, 0 replies; 101+ messages in thread
From: JeffyChen @ 2018-01-22 2:15 UTC (permalink / raw)
To: Randy Li, Robin Murphy, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
tfiga-F7+t8E8rja9g9hUCZPvPmw
Cc: Mark Rutland, devicetree-u79uwXL29TY76Z2rM5mHXA,
xxm-TNX95d0MmH7DzftRWevZcw, Joerg Roedel,
jcliang-F7+t8E8rja9g9hUCZPvPmw,
linux-rockchip-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA, Rob Herring,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Heiko Stuebner
Hi Randy,
On 01/22/2018 09:18 AM, Randy Li wrote:
>>
> Also the power domain driver could manage the clocks as well, I would
> suggest to use pm_runtime_*.
actually the clocks required by pm domain may not be the same as what we
want to control here, there might be some clocks only be needed when
accessing mmu registers.
but i'm not very sure about that, will confirm it with Simon Xue.
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 101+ messages in thread
* Re: [PATCH v4 08/13] iommu/rockchip: Control clocks needed to access the IOMMU
@ 2018-01-22 2:15 ` JeffyChen
0 siblings, 0 replies; 101+ messages in thread
From: JeffyChen @ 2018-01-22 2:15 UTC (permalink / raw)
To: Randy Li, Robin Murphy, linux-kernel, tfiga
Cc: Mark Rutland, devicetree, xxm, Joerg Roedel, jcliang,
linux-rockchip, iommu, Rob Herring, linux-arm-kernel,
Heiko Stuebner
Hi Randy,
On 01/22/2018 09:18 AM, Randy Li wrote:
>>
> Also the power domain driver could manage the clocks as well, I would
> suggest to use pm_runtime_*.
actually the clocks required by pm domain may not be the same as what we
want to control here, there might be some clocks only be needed when
accessing mmu registers.
but i'm not very sure about that, will confirm it with Simon Xue.
^ permalink raw reply [flat|nested] 101+ messages in thread
* [PATCH v4 08/13] iommu/rockchip: Control clocks needed to access the IOMMU
@ 2018-01-22 2:15 ` JeffyChen
0 siblings, 0 replies; 101+ messages in thread
From: JeffyChen @ 2018-01-22 2:15 UTC (permalink / raw)
To: linux-arm-kernel
Hi Randy,
On 01/22/2018 09:18 AM, Randy Li wrote:
>>
> Also the power domain driver could manage the clocks as well, I would
> suggest to use pm_runtime_*.
actually the clocks required by pm domain may not be the same as what we
want to control here, there might be some clocks only be needed when
accessing mmu registers.
but i'm not very sure about that, will confirm it with Simon Xue.
^ permalink raw reply [flat|nested] 101+ messages in thread
[parent not found: <5A654925.9020203-TNX95d0MmH7DzftRWevZcw@public.gmane.org>]
* Re: [PATCH v4 08/13] iommu/rockchip: Control clocks needed to access the IOMMU
2018-01-22 2:15 ` JeffyChen
(?)
@ 2018-01-22 4:09 ` JeffyChen
-1 siblings, 0 replies; 101+ messages in thread
From: JeffyChen @ 2018-01-22 4:09 UTC (permalink / raw)
To: Randy Li, Robin Murphy, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
tfiga-F7+t8E8rja9g9hUCZPvPmw
Cc: Mark Rutland, devicetree-u79uwXL29TY76Z2rM5mHXA,
jcliang-F7+t8E8rja9g9hUCZPvPmw,
linux-rockchip-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA, Rob Herring,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Heiko Stuebner
Hi Randy,
On 01/22/2018 10:15 AM, JeffyChen wrote:
> Hi Randy,
>
> On 01/22/2018 09:18 AM, Randy Li wrote:
>>>
>> Also the power domain driver could manage the clocks as well, I would
>> suggest to use pm_runtime_*.
>
> actually the clocks required by pm domain may not be the same as what we
> want to control here, there might be some clocks only be needed when
> accessing mmu registers.
>
> but i'm not very sure about that, will confirm it with Simon Xue.
confirmed with Simon, there might be some iommus don't have a pd, and
the CONFIG_PM could be disabled.
so it might be better to control clocks in iommu driver itself.
^ permalink raw reply [flat|nested] 101+ messages in thread
* Re: [PATCH v4 08/13] iommu/rockchip: Control clocks needed to access the IOMMU
@ 2018-01-22 4:09 ` JeffyChen
0 siblings, 0 replies; 101+ messages in thread
From: JeffyChen @ 2018-01-22 4:09 UTC (permalink / raw)
To: Randy Li, Robin Murphy, linux-kernel, tfiga
Cc: Mark Rutland, devicetree, xxm, Joerg Roedel, jcliang,
linux-rockchip, iommu, Rob Herring, linux-arm-kernel,
Heiko Stuebner
Hi Randy,
On 01/22/2018 10:15 AM, JeffyChen wrote:
> Hi Randy,
>
> On 01/22/2018 09:18 AM, Randy Li wrote:
>>>
>> Also the power domain driver could manage the clocks as well, I would
>> suggest to use pm_runtime_*.
>
> actually the clocks required by pm domain may not be the same as what we
> want to control here, there might be some clocks only be needed when
> accessing mmu registers.
>
> but i'm not very sure about that, will confirm it with Simon Xue.
confirmed with Simon, there might be some iommus don't have a pd, and
the CONFIG_PM could be disabled.
so it might be better to control clocks in iommu driver itself.
^ permalink raw reply [flat|nested] 101+ messages in thread
* [PATCH v4 08/13] iommu/rockchip: Control clocks needed to access the IOMMU
@ 2018-01-22 4:09 ` JeffyChen
0 siblings, 0 replies; 101+ messages in thread
From: JeffyChen @ 2018-01-22 4:09 UTC (permalink / raw)
To: linux-arm-kernel
Hi Randy,
On 01/22/2018 10:15 AM, JeffyChen wrote:
> Hi Randy,
>
> On 01/22/2018 09:18 AM, Randy Li wrote:
>>>
>> Also the power domain driver could manage the clocks as well, I would
>> suggest to use pm_runtime_*.
>
> actually the clocks required by pm domain may not be the same as what we
> want to control here, there might be some clocks only be needed when
> accessing mmu registers.
>
> but i'm not very sure about that, will confirm it with Simon Xue.
confirmed with Simon, there might be some iommus don't have a pd, and
the CONFIG_PM could be disabled.
so it might be better to control clocks in iommu driver itself.
^ permalink raw reply [flat|nested] 101+ messages in thread
[parent not found: <5A6563FA.8080602-TNX95d0MmH7DzftRWevZcw@public.gmane.org>]
* Re: [PATCH v4 08/13] iommu/rockchip: Control clocks needed to access the IOMMU
2018-01-22 4:09 ` JeffyChen
(?)
@ 2018-01-24 9:51 ` Tomasz Figa
-1 siblings, 0 replies; 101+ messages in thread
From: Tomasz Figa @ 2018-01-24 9:51 UTC (permalink / raw)
To: JeffyChen
Cc: Mark Rutland, devicetree-u79uwXL29TY76Z2rM5mHXA, Randy Li,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, Ricky Liang,
open list:ARM/Rockchip SoC...,
list-Y9sIeH5OGRo@public.gmane.org:IOMMU DRIVERS <iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA@public.gmane.org>, Joerg Roedel <joro-zLv9SwRftAIdnm+yROfE0A@public.gmane.org>, ,
Rob Herring,
list-Y9sIeH5OGRo@public.gmane.org:IOMMU DRIVERS <iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA@public.gmane.org>, Joerg Roedel <joro-zLv9SwRftAIdnm+yROfE0A@public.gmane.org>, ,
Heiko Stuebner
On Mon, Jan 22, 2018 at 1:09 PM, JeffyChen <jeffy.chen-TNX95d0MmH7DzftRWevZcw@public.gmane.org> wrote:
> Hi Randy,
>
>
> On 01/22/2018 10:15 AM, JeffyChen wrote:
>>
>> Hi Randy,
>>
>> On 01/22/2018 09:18 AM, Randy Li wrote:
>>>>
>>>>
>>> Also the power domain driver could manage the clocks as well, I would
>>> suggest to use pm_runtime_*.
>>
>>
>> actually the clocks required by pm domain may not be the same as what we
>> want to control here, there might be some clocks only be needed when
>> accessing mmu registers.
>>
>> but i'm not very sure about that, will confirm it with Simon Xue.
>
>
> confirmed with Simon, there might be some iommus don't have a pd, and the
> CONFIG_PM could be disabled.
>
> so it might be better to control clocks in iommu driver itself.
>
Agreed with Jeffy.
I'd give Reviewed-by, but this is my own patch reposted by Jeffy
(thanks!), so it wouldn't have any value. :)
Best regards,
Tomasz
^ permalink raw reply [flat|nested] 101+ messages in thread
* Re: [PATCH v4 08/13] iommu/rockchip: Control clocks needed to access the IOMMU
@ 2018-01-24 9:51 ` Tomasz Figa
0 siblings, 0 replies; 101+ messages in thread
From: Tomasz Figa @ 2018-01-24 9:51 UTC (permalink / raw)
To: JeffyChen
Cc: Randy Li, Robin Murphy, linux-kernel, Mark Rutland, devicetree,
simon xue, Joerg Roedel, Ricky Liang,
open list:ARM/Rockchip SoC...,
list@263.net:IOMMU DRIVERS <iommu@lists.linux-foundation.org>, Joerg Roedel <joro@8bytes.org>,,
Rob Herring,
list@263.net:IOMMU DRIVERS <iommu@lists.linux-foundation.org>, Joerg Roedel <joro@8bytes.org>,,
Heiko Stuebner
On Mon, Jan 22, 2018 at 1:09 PM, JeffyChen <jeffy.chen@rock-chips.com> wrote:
> Hi Randy,
>
>
> On 01/22/2018 10:15 AM, JeffyChen wrote:
>>
>> Hi Randy,
>>
>> On 01/22/2018 09:18 AM, Randy Li wrote:
>>>>
>>>>
>>> Also the power domain driver could manage the clocks as well, I would
>>> suggest to use pm_runtime_*.
>>
>>
>> actually the clocks required by pm domain may not be the same as what we
>> want to control here, there might be some clocks only be needed when
>> accessing mmu registers.
>>
>> but i'm not very sure about that, will confirm it with Simon Xue.
>
>
> confirmed with Simon, there might be some iommus don't have a pd, and the
> CONFIG_PM could be disabled.
>
> so it might be better to control clocks in iommu driver itself.
>
Agreed with Jeffy.
I'd give Reviewed-by, but this is my own patch reposted by Jeffy
(thanks!), so it wouldn't have any value. :)
Best regards,
Tomasz
^ permalink raw reply [flat|nested] 101+ messages in thread
* [PATCH v4 08/13] iommu/rockchip: Control clocks needed to access the IOMMU
@ 2018-01-24 9:51 ` Tomasz Figa
0 siblings, 0 replies; 101+ messages in thread
From: Tomasz Figa @ 2018-01-24 9:51 UTC (permalink / raw)
To: linux-arm-kernel
On Mon, Jan 22, 2018 at 1:09 PM, JeffyChen <jeffy.chen@rock-chips.com> wrote:
> Hi Randy,
>
>
> On 01/22/2018 10:15 AM, JeffyChen wrote:
>>
>> Hi Randy,
>>
>> On 01/22/2018 09:18 AM, Randy Li wrote:
>>>>
>>>>
>>> Also the power domain driver could manage the clocks as well, I would
>>> suggest to use pm_runtime_*.
>>
>>
>> actually the clocks required by pm domain may not be the same as what we
>> want to control here, there might be some clocks only be needed when
>> accessing mmu registers.
>>
>> but i'm not very sure about that, will confirm it with Simon Xue.
>
>
> confirmed with Simon, there might be some iommus don't have a pd, and the
> CONFIG_PM could be disabled.
>
> so it might be better to control clocks in iommu driver itself.
>
Agreed with Jeffy.
I'd give Reviewed-by, but this is my own patch reposted by Jeffy
(thanks!), so it wouldn't have any value. :)
Best regards,
Tomasz
^ permalink raw reply [flat|nested] 101+ messages in thread
* Re: [PATCH v4 08/13] iommu/rockchip: Control clocks needed to access the IOMMU
2018-01-22 4:09 ` JeffyChen
(?)
@ 2018-01-25 9:42 ` Randy Li
-1 siblings, 0 replies; 101+ messages in thread
From: Randy Li @ 2018-01-25 9:42 UTC (permalink / raw)
To: JeffyChen, tfiga-F7+t8E8rja9g9hUCZPvPmw
Cc: Robin Murphy, linux-kernel-u79uwXL29TY76Z2rM5mHXA, Mark Rutland,
devicetree-u79uwXL29TY76Z2rM5mHXA, xxm-TNX95d0MmH7DzftRWevZcw,
Joerg Roedel, jcliang-F7+t8E8rja9g9hUCZPvPmw,
linux-rockchip-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA, Rob Herring,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Heiko Stuebner
On 01/22/2018 12:09 PM, JeffyChen wrote:
> Hi Randy,
>
> On 01/22/2018 10:15 AM, JeffyChen wrote:
>> Hi Randy,
>>
>> On 01/22/2018 09:18 AM, Randy Li wrote:
>>>>
>>> Also the power domain driver could manage the clocks as well, I would
>>> suggest to use pm_runtime_*.
>>
>> actually the clocks required by pm domain may not be the same as what we
>> want to control here, there might be some clocks only be needed when
>> accessing mmu registers.
>>
>> but i'm not very sure about that, will confirm it with Simon Xue.
>
> confirmed with Simon, there might be some iommus don't have a pd, and
We use the pd to control the NIU node(not on upstream), without a pd or
fake pd, none of the platform would work.
> the CONFIG_PM could be disabled.I am hard to believe a modern platform can work without that.
>
> so it might be better to control clocks in iommu driver itself.I won't insist how the version of the iommu patch on the upstream, I
just post an idea here.
The version for kernel 4.4 is under internal review, the implementation
has been modified many times.
I would suggest the managing clocks in pd is a more easy way and don't
need to spare those thing in two places.
>
>
> _______________________________________________
> Linux-rockchip mailing list
> Linux-rockchip-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org
> http://lists.infradead.org/mailman/listinfo/linux-rockchip
>
--
Randy Li
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 101+ messages in thread
* Re: [PATCH v4 08/13] iommu/rockchip: Control clocks needed to access the IOMMU
@ 2018-01-25 9:42 ` Randy Li
0 siblings, 0 replies; 101+ messages in thread
From: Randy Li @ 2018-01-25 9:42 UTC (permalink / raw)
To: JeffyChen, tfiga
Cc: Robin Murphy, linux-kernel, Mark Rutland, devicetree, xxm,
Joerg Roedel, jcliang, linux-rockchip, iommu, Rob Herring,
linux-arm-kernel, Heiko Stuebner
On 01/22/2018 12:09 PM, JeffyChen wrote:
> Hi Randy,
>
> On 01/22/2018 10:15 AM, JeffyChen wrote:
>> Hi Randy,
>>
>> On 01/22/2018 09:18 AM, Randy Li wrote:
>>>>
>>> Also the power domain driver could manage the clocks as well, I would
>>> suggest to use pm_runtime_*.
>>
>> actually the clocks required by pm domain may not be the same as what we
>> want to control here, there might be some clocks only be needed when
>> accessing mmu registers.
>>
>> but i'm not very sure about that, will confirm it with Simon Xue.
>
> confirmed with Simon, there might be some iommus don't have a pd, and
We use the pd to control the NIU node(not on upstream), without a pd or
fake pd, none of the platform would work.
> the CONFIG_PM could be disabled.I am hard to believe a modern platform can work without that.
>
> so it might be better to control clocks in iommu driver itself.I won't insist how the version of the iommu patch on the upstream, I
just post an idea here.
The version for kernel 4.4 is under internal review, the implementation
has been modified many times.
I would suggest the managing clocks in pd is a more easy way and don't
need to spare those thing in two places.
>
>
> _______________________________________________
> Linux-rockchip mailing list
> Linux-rockchip@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-rockchip
>
--
Randy Li
^ permalink raw reply [flat|nested] 101+ messages in thread
* [PATCH v4 08/13] iommu/rockchip: Control clocks needed to access the IOMMU
@ 2018-01-25 9:42 ` Randy Li
0 siblings, 0 replies; 101+ messages in thread
From: Randy Li @ 2018-01-25 9:42 UTC (permalink / raw)
To: linux-arm-kernel
On 01/22/2018 12:09 PM, JeffyChen wrote:
> Hi Randy,
>
> On 01/22/2018 10:15 AM, JeffyChen wrote:
>> Hi Randy,
>>
>> On 01/22/2018 09:18 AM, Randy Li wrote:
>>>>
>>> Also the power domain driver could manage the clocks as well, I would
>>> suggest to use pm_runtime_*.
>>
>> actually the clocks required by pm domain may not be the same as what we
>> want to control here, there might be some clocks only be needed when
>> accessing mmu registers.
>>
>> but i'm not very sure about that, will confirm it with Simon Xue.
>
> confirmed with Simon, there might be some iommus don't have a pd, and
We use the pd to control the NIU node(not on upstream), without a pd or
fake pd, none of the platform would work.
> the CONFIG_PM could be disabled.I am hard to believe a modern platform can work without that.
>
> so it might be better to control clocks in iommu driver itself.I won't insist how the version of the iommu patch on the upstream, I
just post an idea here.
The version for kernel 4.4 is under internal review, the implementation
has been modified many times.
I would suggest the managing clocks in pd is a more easy way and don't
need to spare those thing in two places.
>
>
> _______________________________________________
> Linux-rockchip mailing list
> Linux-rockchip at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-rockchip
>
--
Randy Li
^ permalink raw reply [flat|nested] 101+ messages in thread
[parent not found: <c05d4794-b76d-cfaa-d7ed-c44108117ee2-TNX95d0MmH7DzftRWevZcw@public.gmane.org>]
* Re: [PATCH v4 08/13] iommu/rockchip: Control clocks needed to access the IOMMU
2018-01-25 9:42 ` Randy Li
(?)
@ 2018-01-25 10:24 ` JeffyChen
-1 siblings, 0 replies; 101+ messages in thread
From: JeffyChen @ 2018-01-25 10:24 UTC (permalink / raw)
To: Randy Li, tfiga-F7+t8E8rja9g9hUCZPvPmw
Cc: Mark Rutland, devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
jcliang-F7+t8E8rja9g9hUCZPvPmw,
linux-rockchip-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA, Rob Herring,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Heiko Stuebner
On 01/25/2018 05:42 PM, Randy Li wrote:
>>>
>>
>> confirmed with Simon, there might be some iommus don't have a pd, and
> We use the pd to control the NIU node(not on upstream), without a pd or
> fake pd, none of the platform would work.
after talked offline, it's possible to have iommu without pd in upstream
kernel(and chromeos kernel), but on our internal kernel, the drivers
would require pd(or fake pd) to reset modules when error happens.
anyway, i think that means we do need clock control here.
>> the CONFIG_PM could be disabled.I am hard to believe a modern platform
>> can work without that.
>>
>> so it might be better to control clocks in iommu driver itself.
>I won't
> insist how the version of the iommu patch on the upstream, I
> just post an idea here.
> The version for kernel 4.4 is under internal review, the implementation
> has been modified many times.
>
> I would suggest the managing clocks in pd is a more easy way and don't
> need to spare those thing in two places.
^ permalink raw reply [flat|nested] 101+ messages in thread
* Re: [PATCH v4 08/13] iommu/rockchip: Control clocks needed to access the IOMMU
@ 2018-01-25 10:24 ` JeffyChen
0 siblings, 0 replies; 101+ messages in thread
From: JeffyChen @ 2018-01-25 10:24 UTC (permalink / raw)
To: Randy Li, tfiga
Cc: Robin Murphy, linux-kernel, Mark Rutland, devicetree, xxm,
Joerg Roedel, jcliang, linux-rockchip, iommu, Rob Herring,
linux-arm-kernel, Heiko Stuebner
On 01/25/2018 05:42 PM, Randy Li wrote:
>>>
>>
>> confirmed with Simon, there might be some iommus don't have a pd, and
> We use the pd to control the NIU node(not on upstream), without a pd or
> fake pd, none of the platform would work.
after talked offline, it's possible to have iommu without pd in upstream
kernel(and chromeos kernel), but on our internal kernel, the drivers
would require pd(or fake pd) to reset modules when error happens.
anyway, i think that means we do need clock control here.
>> the CONFIG_PM could be disabled.I am hard to believe a modern platform
>> can work without that.
>>
>> so it might be better to control clocks in iommu driver itself.
>I won't
> insist how the version of the iommu patch on the upstream, I
> just post an idea here.
> The version for kernel 4.4 is under internal review, the implementation
> has been modified many times.
>
> I would suggest the managing clocks in pd is a more easy way and don't
> need to spare those thing in two places.
^ permalink raw reply [flat|nested] 101+ messages in thread
* [PATCH v4 08/13] iommu/rockchip: Control clocks needed to access the IOMMU
@ 2018-01-25 10:24 ` JeffyChen
0 siblings, 0 replies; 101+ messages in thread
From: JeffyChen @ 2018-01-25 10:24 UTC (permalink / raw)
To: linux-arm-kernel
On 01/25/2018 05:42 PM, Randy Li wrote:
>>>
>>
>> confirmed with Simon, there might be some iommus don't have a pd, and
> We use the pd to control the NIU node(not on upstream), without a pd or
> fake pd, none of the platform would work.
after talked offline, it's possible to have iommu without pd in upstream
kernel(and chromeos kernel), but on our internal kernel, the drivers
would require pd(or fake pd) to reset modules when error happens.
anyway, i think that means we do need clock control here.
>> the CONFIG_PM could be disabled.I am hard to believe a modern platform
>> can work without that.
>>
>> so it might be better to control clocks in iommu driver itself.
>I won't
> insist how the version of the iommu patch on the upstream, I
> just post an idea here.
> The version for kernel 4.4 is under internal review, the implementation
> has been modified many times.
>
> I would suggest the managing clocks in pd is a more easy way and don't
> need to spare those thing in two places.
^ permalink raw reply [flat|nested] 101+ messages in thread
[parent not found: <5A69B065.30501-TNX95d0MmH7DzftRWevZcw@public.gmane.org>]
* Re: [PATCH v4 08/13] iommu/rockchip: Control clocks needed to access the IOMMU
2018-01-25 10:24 ` JeffyChen
(?)
@ 2018-02-23 10:36 ` JeffyChen
-1 siblings, 0 replies; 101+ messages in thread
From: JeffyChen @ 2018-02-23 10:36 UTC (permalink / raw)
To: Randy Li, tfiga-F7+t8E8rja9g9hUCZPvPmw
Cc: Mark Rutland, devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
jcliang-F7+t8E8rja9g9hUCZPvPmw,
linux-rockchip-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA, Rob Herring,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Heiko Stuebner
Hi guys,
On 01/25/2018 06:24 PM, JeffyChen wrote:
> On 01/25/2018 05:42 PM, Randy Li wrote:
>>>>
>>>
>>> confirmed with Simon, there might be some iommus don't have a pd, and
>> We use the pd to control the NIU node(not on upstream), without a pd or
>> fake pd, none of the platform would work.
> after talked offline, it's possible to have iommu without pd in upstream
> kernel(and chromeos kernel), but on our internal kernel, the drivers
> would require pd(or fake pd) to reset modules when error happens.
>
> anyway, i think that means we do need clock control here.
found another reason to not depend on pd to control clocks.
currently we are using pd's pm_clk to keep clocks enabled during power
on. but in our pd binding doc, that is not needed:
- clocks (optional): phandles to clocks which need to be enabled while
power domain
switches state.
confirmed with Caesar, the pm_clk only required for some old
chips(rk3288 for example) due to hardware issue.
and i tested my chromebook kevin(rk3399), it works well after remove the
pm_clk:
+++ b/drivers/soc/rockchip/pm_domains.c
@@ -478,7 +478,6 @@ static int rockchip_pm_add_one_domain(struct
rockchip_pmu *pmu,
pd->genpd.power_on = rockchip_pd_power_on;
pd->genpd.attach_dev = rockchip_pd_attach_dev;
pd->genpd.detach_dev = rockchip_pd_detach_dev;
- pd->genpd.flags = GENPD_FLAG_PM_CLK;
will do more tests and send patch tomorrow.
>
>>> the CONFIG_PM could be disabled.I am hard to believe a modern platform
>>> can work without that.
>>>
>>> so it might be better to control clocks in iommu driver itself.
>> I won't
>> insist how the version of the iommu patch on the upstream, I
>> just post an idea here.
>> The version for kernel 4.4 is under internal review, the implementation
>> has been modified many times.
>>
>> I would suggest the managing clocks in pd is a more easy way and don't
>> need to spare those thing in two places.
^ permalink raw reply [flat|nested] 101+ messages in thread* Re: [PATCH v4 08/13] iommu/rockchip: Control clocks needed to access the IOMMU
@ 2018-02-23 10:36 ` JeffyChen
0 siblings, 0 replies; 101+ messages in thread
From: JeffyChen @ 2018-02-23 10:36 UTC (permalink / raw)
To: Randy Li, tfiga
Cc: Robin Murphy, linux-kernel, Mark Rutland, devicetree, xxm,
Joerg Roedel, jcliang, linux-rockchip, iommu, Rob Herring,
linux-arm-kernel, Heiko Stuebner
Hi guys,
On 01/25/2018 06:24 PM, JeffyChen wrote:
> On 01/25/2018 05:42 PM, Randy Li wrote:
>>>>
>>>
>>> confirmed with Simon, there might be some iommus don't have a pd, and
>> We use the pd to control the NIU node(not on upstream), without a pd or
>> fake pd, none of the platform would work.
> after talked offline, it's possible to have iommu without pd in upstream
> kernel(and chromeos kernel), but on our internal kernel, the drivers
> would require pd(or fake pd) to reset modules when error happens.
>
> anyway, i think that means we do need clock control here.
found another reason to not depend on pd to control clocks.
currently we are using pd's pm_clk to keep clocks enabled during power
on. but in our pd binding doc, that is not needed:
- clocks (optional): phandles to clocks which need to be enabled while
power domain
switches state.
confirmed with Caesar, the pm_clk only required for some old
chips(rk3288 for example) due to hardware issue.
and i tested my chromebook kevin(rk3399), it works well after remove the
pm_clk:
+++ b/drivers/soc/rockchip/pm_domains.c
@@ -478,7 +478,6 @@ static int rockchip_pm_add_one_domain(struct
rockchip_pmu *pmu,
pd->genpd.power_on = rockchip_pd_power_on;
pd->genpd.attach_dev = rockchip_pd_attach_dev;
pd->genpd.detach_dev = rockchip_pd_detach_dev;
- pd->genpd.flags = GENPD_FLAG_PM_CLK;
will do more tests and send patch tomorrow.
>
>>> the CONFIG_PM could be disabled.I am hard to believe a modern platform
>>> can work without that.
>>>
>>> so it might be better to control clocks in iommu driver itself.
>> I won't
>> insist how the version of the iommu patch on the upstream, I
>> just post an idea here.
>> The version for kernel 4.4 is under internal review, the implementation
>> has been modified many times.
>>
>> I would suggest the managing clocks in pd is a more easy way and don't
>> need to spare those thing in two places.
^ permalink raw reply [flat|nested] 101+ messages in thread* [PATCH v4 08/13] iommu/rockchip: Control clocks needed to access the IOMMU
@ 2018-02-23 10:36 ` JeffyChen
0 siblings, 0 replies; 101+ messages in thread
From: JeffyChen @ 2018-02-23 10:36 UTC (permalink / raw)
To: linux-arm-kernel
Hi guys,
On 01/25/2018 06:24 PM, JeffyChen wrote:
> On 01/25/2018 05:42 PM, Randy Li wrote:
>>>>
>>>
>>> confirmed with Simon, there might be some iommus don't have a pd, and
>> We use the pd to control the NIU node(not on upstream), without a pd or
>> fake pd, none of the platform would work.
> after talked offline, it's possible to have iommu without pd in upstream
> kernel(and chromeos kernel), but on our internal kernel, the drivers
> would require pd(or fake pd) to reset modules when error happens.
>
> anyway, i think that means we do need clock control here.
found another reason to not depend on pd to control clocks.
currently we are using pd's pm_clk to keep clocks enabled during power
on. but in our pd binding doc, that is not needed:
- clocks (optional): phandles to clocks which need to be enabled while
power domain
switches state.
confirmed with Caesar, the pm_clk only required for some old
chips(rk3288 for example) due to hardware issue.
and i tested my chromebook kevin(rk3399), it works well after remove the
pm_clk:
+++ b/drivers/soc/rockchip/pm_domains.c
@@ -478,7 +478,6 @@ static int rockchip_pm_add_one_domain(struct
rockchip_pmu *pmu,
pd->genpd.power_on = rockchip_pd_power_on;
pd->genpd.attach_dev = rockchip_pd_attach_dev;
pd->genpd.detach_dev = rockchip_pd_detach_dev;
- pd->genpd.flags = GENPD_FLAG_PM_CLK;
will do more tests and send patch tomorrow.
>
>>> the CONFIG_PM could be disabled.I am hard to believe a modern platform
>>> can work without that.
>>>
>>> so it might be better to control clocks in iommu driver itself.
>> I won't
>> insist how the version of the iommu patch on the upstream, I
>> just post an idea here.
>> The version for kernel 4.4 is under internal review, the implementation
>> has been modified many times.
>>
>> I would suggest the managing clocks in pd is a more easy way and don't
>> need to spare those thing in two places.
^ permalink raw reply [flat|nested] 101+ messages in thread
* [PATCH v4 09/13] iommu/rockchip: Use IOMMU device for dma mapping operations
2018-01-18 11:52 ` Jeffy Chen
(?)
@ 2018-01-18 11:52 ` Jeffy Chen
-1 siblings, 0 replies; 101+ messages in thread
From: Jeffy Chen @ 2018-01-18 11:52 UTC (permalink / raw)
To: linux-kernel-u79uwXL29TY76Z2rM5mHXA
Cc: Jeffy Chen, jcliang-F7+t8E8rja9g9hUCZPvPmw,
linux-rockchip-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Heiko Stuebner
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 <jeffy.chen-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
Reviewed-by: Tomasz Figa <tfiga-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
---
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 9b85a3050449..bdb7c5de6fc2 100644
--- a/drivers/iommu/rockchip-iommu.c
+++ b/drivers/iommu/rockchip-iommu.c
@@ -77,7 +77,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 */
@@ -98,12 +97,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(&dom->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)
@@ -690,7 +691,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 = &rk_domain->pdev->dev;
u32 *page_table, *dte_addr;
u32 dte_index, dte;
phys_addr_t pt_phys;
@@ -708,9 +708,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);
}
@@ -982,29 +982,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(&pdev->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(&rk_domain->domain))
- goto err_unreg_pdev;
+ return NULL;
/*
* rk32xx iommus use a 2 level pagetable.
@@ -1015,11 +1006,10 @@ static struct iommu_domain *rk_iommu_domain_alloc(unsigned type)
if (!rk_domain->dt)
goto err_put_cookie;
- iommu_dev = &pdev->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;
}
@@ -1040,8 +1030,6 @@ static struct iommu_domain *rk_iommu_domain_alloc(unsigned type)
err_put_cookie:
if (type == IOMMU_DOMAIN_DMA)
iommu_put_dma_cookie(&rk_domain->domain);
-err_unreg_pdev:
- platform_device_unregister(pdev);
return NULL;
}
@@ -1058,20 +1046,18 @@ static void rk_iommu_domain_free(struct iommu_domain *domain)
if (rk_dte_is_pt_valid(dte)) {
phys_addr_t pt_phys = rk_dte_pt_address(dte);
u32 *page_table = phys_to_virt(pt_phys);
- dma_unmap_single(&rk_domain->pdev->dev, pt_phys,
+ dma_unmap_single(dma_dev, pt_phys,
SPAGE_SIZE, DMA_TO_DEVICE);
free_page((unsigned long)page_table);
}
}
- dma_unmap_single(&rk_domain->pdev->dev, rk_domain->dt_dma,
+ dma_unmap_single(dma_dev, rk_domain->dt_dma,
SPAGE_SIZE, DMA_TO_DEVICE);
free_page((unsigned long)rk_domain->dt);
if (domain->type == IOMMU_DOMAIN_DMA)
iommu_put_dma_cookie(&rk_domain->domain);
-
- platform_device_unregister(rk_domain->pdev);
}
static bool rk_iommu_is_dev_iommu_master(struct device *dev)
@@ -1194,30 +1180,6 @@ static const struct iommu_ops rk_iommu_ops = {
.pgsize_bitmap = RK_IOMMU_PGSIZE_BITMAP,
};
-static int rk_iommu_domain_probe(struct platform_device *pdev)
-{
- struct device *dev = &pdev->dev;
-
- dev->dma_parms = devm_kzalloc(dev, sizeof(*dev->dma_parms), GFP_KERNEL);
- if (!dev->dma_parms)
- return -ENOMEM;
-
- /* Set dma_ops for dev, otherwise it would be dummy_dma_ops */
- arch_setup_dma_ops(dev, 0, DMA_BIT_MASK(32), NULL, false);
-
- dma_set_max_seg_size(dev, DMA_BIT_MASK(32));
- dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32));
-
- return 0;
-}
-
-static struct platform_driver rk_iommu_domain_driver = {
- .probe = rk_iommu_domain_probe,
- .driver = {
- .name = "rk_iommu_domain",
- },
-};
-
static int rk_iommu_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -1278,6 +1240,14 @@ static int rk_iommu_probe(struct platform_device *pdev)
if (err)
goto err_remove_sysfs;
+ /*
+ * Use the first registered IOMMU device for domain to use with DMA
+ * API, since a domain might not physically correspond to a single
+ * IOMMU device..
+ */
+ if (!dma_dev)
+ dma_dev = &pdev->dev;
+
return 0;
err_remove_sysfs:
iommu_device_sysfs_remove(&iommu->iommu);
@@ -1316,14 +1286,7 @@ static int __init rk_iommu_init(void)
if (ret)
return ret;
- ret = platform_driver_register(&rk_iommu_domain_driver);
- if (ret)
- return ret;
-
- ret = platform_driver_register(&rk_iommu_driver);
- if (ret)
- platform_driver_unregister(&rk_iommu_domain_driver);
- return ret;
+ return platform_driver_register(&rk_iommu_driver);
}
subsys_initcall(rk_iommu_init);
--
2.11.0
^ permalink raw reply related [flat|nested] 101+ messages in thread* [PATCH v4 09/13] iommu/rockchip: Use IOMMU device for dma mapping operations
@ 2018-01-18 11:52 ` Jeffy Chen
0 siblings, 0 replies; 101+ messages in thread
From: Jeffy Chen @ 2018-01-18 11:52 UTC (permalink / raw)
To: linux-kernel
Cc: jcliang, robin.murphy, xxm, tfiga, Jeffy Chen, Heiko Stuebner,
linux-rockchip, iommu, Joerg Roedel, linux-arm-kernel
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 <jeffy.chen@rock-chips.com>
Reviewed-by: Tomasz Figa <tfiga@chromium.org>
---
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 9b85a3050449..bdb7c5de6fc2 100644
--- a/drivers/iommu/rockchip-iommu.c
+++ b/drivers/iommu/rockchip-iommu.c
@@ -77,7 +77,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 */
@@ -98,12 +97,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(&dom->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)
@@ -690,7 +691,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 = &rk_domain->pdev->dev;
u32 *page_table, *dte_addr;
u32 dte_index, dte;
phys_addr_t pt_phys;
@@ -708,9 +708,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);
}
@@ -982,29 +982,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(&pdev->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(&rk_domain->domain))
- goto err_unreg_pdev;
+ return NULL;
/*
* rk32xx iommus use a 2 level pagetable.
@@ -1015,11 +1006,10 @@ static struct iommu_domain *rk_iommu_domain_alloc(unsigned type)
if (!rk_domain->dt)
goto err_put_cookie;
- iommu_dev = &pdev->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;
}
@@ -1040,8 +1030,6 @@ static struct iommu_domain *rk_iommu_domain_alloc(unsigned type)
err_put_cookie:
if (type == IOMMU_DOMAIN_DMA)
iommu_put_dma_cookie(&rk_domain->domain);
-err_unreg_pdev:
- platform_device_unregister(pdev);
return NULL;
}
@@ -1058,20 +1046,18 @@ static void rk_iommu_domain_free(struct iommu_domain *domain)
if (rk_dte_is_pt_valid(dte)) {
phys_addr_t pt_phys = rk_dte_pt_address(dte);
u32 *page_table = phys_to_virt(pt_phys);
- dma_unmap_single(&rk_domain->pdev->dev, pt_phys,
+ dma_unmap_single(dma_dev, pt_phys,
SPAGE_SIZE, DMA_TO_DEVICE);
free_page((unsigned long)page_table);
}
}
- dma_unmap_single(&rk_domain->pdev->dev, rk_domain->dt_dma,
+ dma_unmap_single(dma_dev, rk_domain->dt_dma,
SPAGE_SIZE, DMA_TO_DEVICE);
free_page((unsigned long)rk_domain->dt);
if (domain->type == IOMMU_DOMAIN_DMA)
iommu_put_dma_cookie(&rk_domain->domain);
-
- platform_device_unregister(rk_domain->pdev);
}
static bool rk_iommu_is_dev_iommu_master(struct device *dev)
@@ -1194,30 +1180,6 @@ static const struct iommu_ops rk_iommu_ops = {
.pgsize_bitmap = RK_IOMMU_PGSIZE_BITMAP,
};
-static int rk_iommu_domain_probe(struct platform_device *pdev)
-{
- struct device *dev = &pdev->dev;
-
- dev->dma_parms = devm_kzalloc(dev, sizeof(*dev->dma_parms), GFP_KERNEL);
- if (!dev->dma_parms)
- return -ENOMEM;
-
- /* Set dma_ops for dev, otherwise it would be dummy_dma_ops */
- arch_setup_dma_ops(dev, 0, DMA_BIT_MASK(32), NULL, false);
-
- dma_set_max_seg_size(dev, DMA_BIT_MASK(32));
- dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32));
-
- return 0;
-}
-
-static struct platform_driver rk_iommu_domain_driver = {
- .probe = rk_iommu_domain_probe,
- .driver = {
- .name = "rk_iommu_domain",
- },
-};
-
static int rk_iommu_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -1278,6 +1240,14 @@ static int rk_iommu_probe(struct platform_device *pdev)
if (err)
goto err_remove_sysfs;
+ /*
+ * Use the first registered IOMMU device for domain to use with DMA
+ * API, since a domain might not physically correspond to a single
+ * IOMMU device..
+ */
+ if (!dma_dev)
+ dma_dev = &pdev->dev;
+
return 0;
err_remove_sysfs:
iommu_device_sysfs_remove(&iommu->iommu);
@@ -1316,14 +1286,7 @@ static int __init rk_iommu_init(void)
if (ret)
return ret;
- ret = platform_driver_register(&rk_iommu_domain_driver);
- if (ret)
- return ret;
-
- ret = platform_driver_register(&rk_iommu_driver);
- if (ret)
- platform_driver_unregister(&rk_iommu_domain_driver);
- return ret;
+ return platform_driver_register(&rk_iommu_driver);
}
subsys_initcall(rk_iommu_init);
--
2.11.0
^ permalink raw reply related [flat|nested] 101+ messages in thread* [PATCH v4 09/13] iommu/rockchip: Use IOMMU device for dma mapping operations
@ 2018-01-18 11:52 ` Jeffy Chen
0 siblings, 0 replies; 101+ messages in thread
From: Jeffy Chen @ 2018-01-18 11:52 UTC (permalink / raw)
To: linux-arm-kernel
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 <jeffy.chen@rock-chips.com>
Reviewed-by: Tomasz Figa <tfiga@chromium.org>
---
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 9b85a3050449..bdb7c5de6fc2 100644
--- a/drivers/iommu/rockchip-iommu.c
+++ b/drivers/iommu/rockchip-iommu.c
@@ -77,7 +77,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 */
@@ -98,12 +97,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(&dom->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)
@@ -690,7 +691,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 = &rk_domain->pdev->dev;
u32 *page_table, *dte_addr;
u32 dte_index, dte;
phys_addr_t pt_phys;
@@ -708,9 +708,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);
}
@@ -982,29 +982,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(&pdev->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(&rk_domain->domain))
- goto err_unreg_pdev;
+ return NULL;
/*
* rk32xx iommus use a 2 level pagetable.
@@ -1015,11 +1006,10 @@ static struct iommu_domain *rk_iommu_domain_alloc(unsigned type)
if (!rk_domain->dt)
goto err_put_cookie;
- iommu_dev = &pdev->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;
}
@@ -1040,8 +1030,6 @@ static struct iommu_domain *rk_iommu_domain_alloc(unsigned type)
err_put_cookie:
if (type == IOMMU_DOMAIN_DMA)
iommu_put_dma_cookie(&rk_domain->domain);
-err_unreg_pdev:
- platform_device_unregister(pdev);
return NULL;
}
@@ -1058,20 +1046,18 @@ static void rk_iommu_domain_free(struct iommu_domain *domain)
if (rk_dte_is_pt_valid(dte)) {
phys_addr_t pt_phys = rk_dte_pt_address(dte);
u32 *page_table = phys_to_virt(pt_phys);
- dma_unmap_single(&rk_domain->pdev->dev, pt_phys,
+ dma_unmap_single(dma_dev, pt_phys,
SPAGE_SIZE, DMA_TO_DEVICE);
free_page((unsigned long)page_table);
}
}
- dma_unmap_single(&rk_domain->pdev->dev, rk_domain->dt_dma,
+ dma_unmap_single(dma_dev, rk_domain->dt_dma,
SPAGE_SIZE, DMA_TO_DEVICE);
free_page((unsigned long)rk_domain->dt);
if (domain->type == IOMMU_DOMAIN_DMA)
iommu_put_dma_cookie(&rk_domain->domain);
-
- platform_device_unregister(rk_domain->pdev);
}
static bool rk_iommu_is_dev_iommu_master(struct device *dev)
@@ -1194,30 +1180,6 @@ static const struct iommu_ops rk_iommu_ops = {
.pgsize_bitmap = RK_IOMMU_PGSIZE_BITMAP,
};
-static int rk_iommu_domain_probe(struct platform_device *pdev)
-{
- struct device *dev = &pdev->dev;
-
- dev->dma_parms = devm_kzalloc(dev, sizeof(*dev->dma_parms), GFP_KERNEL);
- if (!dev->dma_parms)
- return -ENOMEM;
-
- /* Set dma_ops for dev, otherwise it would be dummy_dma_ops */
- arch_setup_dma_ops(dev, 0, DMA_BIT_MASK(32), NULL, false);
-
- dma_set_max_seg_size(dev, DMA_BIT_MASK(32));
- dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32));
-
- return 0;
-}
-
-static struct platform_driver rk_iommu_domain_driver = {
- .probe = rk_iommu_domain_probe,
- .driver = {
- .name = "rk_iommu_domain",
- },
-};
-
static int rk_iommu_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -1278,6 +1240,14 @@ static int rk_iommu_probe(struct platform_device *pdev)
if (err)
goto err_remove_sysfs;
+ /*
+ * Use the first registered IOMMU device for domain to use with DMA
+ * API, since a domain might not physically correspond to a single
+ * IOMMU device..
+ */
+ if (!dma_dev)
+ dma_dev = &pdev->dev;
+
return 0;
err_remove_sysfs:
iommu_device_sysfs_remove(&iommu->iommu);
@@ -1316,14 +1286,7 @@ static int __init rk_iommu_init(void)
if (ret)
return ret;
- ret = platform_driver_register(&rk_iommu_domain_driver);
- if (ret)
- return ret;
-
- ret = platform_driver_register(&rk_iommu_driver);
- if (ret)
- platform_driver_unregister(&rk_iommu_domain_driver);
- return ret;
+ return platform_driver_register(&rk_iommu_driver);
}
subsys_initcall(rk_iommu_init);
--
2.11.0
^ permalink raw reply related [flat|nested] 101+ messages in thread[parent not found: <20180118115251.5542-10-jeffy.chen-TNX95d0MmH7DzftRWevZcw@public.gmane.org>]
* Re: [PATCH v4 09/13] iommu/rockchip: Use IOMMU device for dma mapping operations
2018-01-18 11:52 ` Jeffy Chen
(?)
@ 2018-01-18 12:35 ` Robin Murphy
-1 siblings, 0 replies; 101+ messages in thread
From: Robin Murphy @ 2018-01-18 12:35 UTC (permalink / raw)
To: Jeffy Chen, linux-kernel-u79uwXL29TY76Z2rM5mHXA
Cc: Heiko Stuebner, jcliang-F7+t8E8rja9g9hUCZPvPmw,
linux-rockchip-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
On 18/01/18 11:52, Jeffy Chen wrote:
> Use the first registered IOMMU device for dma mapping operations, and
> drop the domain platform device.
>
> This is similar to exynos iommu driver.
I'd been meaning to look into this myself for the sake of removing the
arch_setup_dma_ops() hack, so I'm glad to see it done :)
Reviewed-by: Robin Murphy <robin.murphy-5wv7dgnIgG8@public.gmane.org>
> Signed-off-by: Jeffy Chen <jeffy.chen-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
> Reviewed-by: Tomasz Figa <tfiga-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
> ---
>
> 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 9b85a3050449..bdb7c5de6fc2 100644
> --- a/drivers/iommu/rockchip-iommu.c
> +++ b/drivers/iommu/rockchip-iommu.c
> @@ -77,7 +77,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 */
> @@ -98,12 +97,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(&dom->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)
> @@ -690,7 +691,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 = &rk_domain->pdev->dev;
> u32 *page_table, *dte_addr;
> u32 dte_index, dte;
> phys_addr_t pt_phys;
> @@ -708,9 +708,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);
> }
> @@ -982,29 +982,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(&pdev->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(&rk_domain->domain))
> - goto err_unreg_pdev;
> + return NULL;
>
> /*
> * rk32xx iommus use a 2 level pagetable.
> @@ -1015,11 +1006,10 @@ static struct iommu_domain *rk_iommu_domain_alloc(unsigned type)
> if (!rk_domain->dt)
> goto err_put_cookie;
>
> - iommu_dev = &pdev->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;
> }
>
> @@ -1040,8 +1030,6 @@ static struct iommu_domain *rk_iommu_domain_alloc(unsigned type)
> err_put_cookie:
> if (type == IOMMU_DOMAIN_DMA)
> iommu_put_dma_cookie(&rk_domain->domain);
> -err_unreg_pdev:
> - platform_device_unregister(pdev);
>
> return NULL;
> }
> @@ -1058,20 +1046,18 @@ static void rk_iommu_domain_free(struct iommu_domain *domain)
> if (rk_dte_is_pt_valid(dte)) {
> phys_addr_t pt_phys = rk_dte_pt_address(dte);
> u32 *page_table = phys_to_virt(pt_phys);
> - dma_unmap_single(&rk_domain->pdev->dev, pt_phys,
> + dma_unmap_single(dma_dev, pt_phys,
> SPAGE_SIZE, DMA_TO_DEVICE);
> free_page((unsigned long)page_table);
> }
> }
>
> - dma_unmap_single(&rk_domain->pdev->dev, rk_domain->dt_dma,
> + dma_unmap_single(dma_dev, rk_domain->dt_dma,
> SPAGE_SIZE, DMA_TO_DEVICE);
> free_page((unsigned long)rk_domain->dt);
>
> if (domain->type == IOMMU_DOMAIN_DMA)
> iommu_put_dma_cookie(&rk_domain->domain);
> -
> - platform_device_unregister(rk_domain->pdev);
> }
>
> static bool rk_iommu_is_dev_iommu_master(struct device *dev)
> @@ -1194,30 +1180,6 @@ static const struct iommu_ops rk_iommu_ops = {
> .pgsize_bitmap = RK_IOMMU_PGSIZE_BITMAP,
> };
>
> -static int rk_iommu_domain_probe(struct platform_device *pdev)
> -{
> - struct device *dev = &pdev->dev;
> -
> - dev->dma_parms = devm_kzalloc(dev, sizeof(*dev->dma_parms), GFP_KERNEL);
> - if (!dev->dma_parms)
> - return -ENOMEM;
> -
> - /* Set dma_ops for dev, otherwise it would be dummy_dma_ops */
> - arch_setup_dma_ops(dev, 0, DMA_BIT_MASK(32), NULL, false);
> -
> - dma_set_max_seg_size(dev, DMA_BIT_MASK(32));
> - dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32));
> -
> - return 0;
> -}
> -
> -static struct platform_driver rk_iommu_domain_driver = {
> - .probe = rk_iommu_domain_probe,
> - .driver = {
> - .name = "rk_iommu_domain",
> - },
> -};
> -
> static int rk_iommu_probe(struct platform_device *pdev)
> {
> struct device *dev = &pdev->dev;
> @@ -1278,6 +1240,14 @@ static int rk_iommu_probe(struct platform_device *pdev)
> if (err)
> goto err_remove_sysfs;
>
> + /*
> + * Use the first registered IOMMU device for domain to use with DMA
> + * API, since a domain might not physically correspond to a single
> + * IOMMU device..
> + */
> + if (!dma_dev)
> + dma_dev = &pdev->dev;
> +
> return 0;
> err_remove_sysfs:
> iommu_device_sysfs_remove(&iommu->iommu);
> @@ -1316,14 +1286,7 @@ static int __init rk_iommu_init(void)
> if (ret)
> return ret;
>
> - ret = platform_driver_register(&rk_iommu_domain_driver);
> - if (ret)
> - return ret;
> -
> - ret = platform_driver_register(&rk_iommu_driver);
> - if (ret)
> - platform_driver_unregister(&rk_iommu_domain_driver);
> - return ret;
> + return platform_driver_register(&rk_iommu_driver);
> }
> subsys_initcall(rk_iommu_init);
>
>
^ permalink raw reply [flat|nested] 101+ messages in thread* Re: [PATCH v4 09/13] iommu/rockchip: Use IOMMU device for dma mapping operations
@ 2018-01-18 12:35 ` Robin Murphy
0 siblings, 0 replies; 101+ messages in thread
From: Robin Murphy @ 2018-01-18 12:35 UTC (permalink / raw)
To: Jeffy Chen, linux-kernel
Cc: jcliang, xxm, tfiga, Heiko Stuebner, linux-rockchip, iommu,
Joerg Roedel, linux-arm-kernel
On 18/01/18 11:52, Jeffy Chen wrote:
> Use the first registered IOMMU device for dma mapping operations, and
> drop the domain platform device.
>
> This is similar to exynos iommu driver.
I'd been meaning to look into this myself for the sake of removing the
arch_setup_dma_ops() hack, so I'm glad to see it done :)
Reviewed-by: Robin Murphy <robin.murphy@arm.com>
> Signed-off-by: Jeffy Chen <jeffy.chen@rock-chips.com>
> Reviewed-by: Tomasz Figa <tfiga@chromium.org>
> ---
>
> 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 9b85a3050449..bdb7c5de6fc2 100644
> --- a/drivers/iommu/rockchip-iommu.c
> +++ b/drivers/iommu/rockchip-iommu.c
> @@ -77,7 +77,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 */
> @@ -98,12 +97,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(&dom->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)
> @@ -690,7 +691,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 = &rk_domain->pdev->dev;
> u32 *page_table, *dte_addr;
> u32 dte_index, dte;
> phys_addr_t pt_phys;
> @@ -708,9 +708,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);
> }
> @@ -982,29 +982,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(&pdev->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(&rk_domain->domain))
> - goto err_unreg_pdev;
> + return NULL;
>
> /*
> * rk32xx iommus use a 2 level pagetable.
> @@ -1015,11 +1006,10 @@ static struct iommu_domain *rk_iommu_domain_alloc(unsigned type)
> if (!rk_domain->dt)
> goto err_put_cookie;
>
> - iommu_dev = &pdev->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;
> }
>
> @@ -1040,8 +1030,6 @@ static struct iommu_domain *rk_iommu_domain_alloc(unsigned type)
> err_put_cookie:
> if (type == IOMMU_DOMAIN_DMA)
> iommu_put_dma_cookie(&rk_domain->domain);
> -err_unreg_pdev:
> - platform_device_unregister(pdev);
>
> return NULL;
> }
> @@ -1058,20 +1046,18 @@ static void rk_iommu_domain_free(struct iommu_domain *domain)
> if (rk_dte_is_pt_valid(dte)) {
> phys_addr_t pt_phys = rk_dte_pt_address(dte);
> u32 *page_table = phys_to_virt(pt_phys);
> - dma_unmap_single(&rk_domain->pdev->dev, pt_phys,
> + dma_unmap_single(dma_dev, pt_phys,
> SPAGE_SIZE, DMA_TO_DEVICE);
> free_page((unsigned long)page_table);
> }
> }
>
> - dma_unmap_single(&rk_domain->pdev->dev, rk_domain->dt_dma,
> + dma_unmap_single(dma_dev, rk_domain->dt_dma,
> SPAGE_SIZE, DMA_TO_DEVICE);
> free_page((unsigned long)rk_domain->dt);
>
> if (domain->type == IOMMU_DOMAIN_DMA)
> iommu_put_dma_cookie(&rk_domain->domain);
> -
> - platform_device_unregister(rk_domain->pdev);
> }
>
> static bool rk_iommu_is_dev_iommu_master(struct device *dev)
> @@ -1194,30 +1180,6 @@ static const struct iommu_ops rk_iommu_ops = {
> .pgsize_bitmap = RK_IOMMU_PGSIZE_BITMAP,
> };
>
> -static int rk_iommu_domain_probe(struct platform_device *pdev)
> -{
> - struct device *dev = &pdev->dev;
> -
> - dev->dma_parms = devm_kzalloc(dev, sizeof(*dev->dma_parms), GFP_KERNEL);
> - if (!dev->dma_parms)
> - return -ENOMEM;
> -
> - /* Set dma_ops for dev, otherwise it would be dummy_dma_ops */
> - arch_setup_dma_ops(dev, 0, DMA_BIT_MASK(32), NULL, false);
> -
> - dma_set_max_seg_size(dev, DMA_BIT_MASK(32));
> - dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32));
> -
> - return 0;
> -}
> -
> -static struct platform_driver rk_iommu_domain_driver = {
> - .probe = rk_iommu_domain_probe,
> - .driver = {
> - .name = "rk_iommu_domain",
> - },
> -};
> -
> static int rk_iommu_probe(struct platform_device *pdev)
> {
> struct device *dev = &pdev->dev;
> @@ -1278,6 +1240,14 @@ static int rk_iommu_probe(struct platform_device *pdev)
> if (err)
> goto err_remove_sysfs;
>
> + /*
> + * Use the first registered IOMMU device for domain to use with DMA
> + * API, since a domain might not physically correspond to a single
> + * IOMMU device..
> + */
> + if (!dma_dev)
> + dma_dev = &pdev->dev;
> +
> return 0;
> err_remove_sysfs:
> iommu_device_sysfs_remove(&iommu->iommu);
> @@ -1316,14 +1286,7 @@ static int __init rk_iommu_init(void)
> if (ret)
> return ret;
>
> - ret = platform_driver_register(&rk_iommu_domain_driver);
> - if (ret)
> - return ret;
> -
> - ret = platform_driver_register(&rk_iommu_driver);
> - if (ret)
> - platform_driver_unregister(&rk_iommu_domain_driver);
> - return ret;
> + return platform_driver_register(&rk_iommu_driver);
> }
> subsys_initcall(rk_iommu_init);
>
>
^ permalink raw reply [flat|nested] 101+ messages in thread* [PATCH v4 09/13] iommu/rockchip: Use IOMMU device for dma mapping operations
@ 2018-01-18 12:35 ` Robin Murphy
0 siblings, 0 replies; 101+ messages in thread
From: Robin Murphy @ 2018-01-18 12:35 UTC (permalink / raw)
To: linux-arm-kernel
On 18/01/18 11:52, Jeffy Chen wrote:
> Use the first registered IOMMU device for dma mapping operations, and
> drop the domain platform device.
>
> This is similar to exynos iommu driver.
I'd been meaning to look into this myself for the sake of removing the
arch_setup_dma_ops() hack, so I'm glad to see it done :)
Reviewed-by: Robin Murphy <robin.murphy@arm.com>
> Signed-off-by: Jeffy Chen <jeffy.chen@rock-chips.com>
> Reviewed-by: Tomasz Figa <tfiga@chromium.org>
> ---
>
> 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 9b85a3050449..bdb7c5de6fc2 100644
> --- a/drivers/iommu/rockchip-iommu.c
> +++ b/drivers/iommu/rockchip-iommu.c
> @@ -77,7 +77,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 */
> @@ -98,12 +97,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(&dom->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)
> @@ -690,7 +691,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 = &rk_domain->pdev->dev;
> u32 *page_table, *dte_addr;
> u32 dte_index, dte;
> phys_addr_t pt_phys;
> @@ -708,9 +708,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);
> }
> @@ -982,29 +982,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(&pdev->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(&rk_domain->domain))
> - goto err_unreg_pdev;
> + return NULL;
>
> /*
> * rk32xx iommus use a 2 level pagetable.
> @@ -1015,11 +1006,10 @@ static struct iommu_domain *rk_iommu_domain_alloc(unsigned type)
> if (!rk_domain->dt)
> goto err_put_cookie;
>
> - iommu_dev = &pdev->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;
> }
>
> @@ -1040,8 +1030,6 @@ static struct iommu_domain *rk_iommu_domain_alloc(unsigned type)
> err_put_cookie:
> if (type == IOMMU_DOMAIN_DMA)
> iommu_put_dma_cookie(&rk_domain->domain);
> -err_unreg_pdev:
> - platform_device_unregister(pdev);
>
> return NULL;
> }
> @@ -1058,20 +1046,18 @@ static void rk_iommu_domain_free(struct iommu_domain *domain)
> if (rk_dte_is_pt_valid(dte)) {
> phys_addr_t pt_phys = rk_dte_pt_address(dte);
> u32 *page_table = phys_to_virt(pt_phys);
> - dma_unmap_single(&rk_domain->pdev->dev, pt_phys,
> + dma_unmap_single(dma_dev, pt_phys,
> SPAGE_SIZE, DMA_TO_DEVICE);
> free_page((unsigned long)page_table);
> }
> }
>
> - dma_unmap_single(&rk_domain->pdev->dev, rk_domain->dt_dma,
> + dma_unmap_single(dma_dev, rk_domain->dt_dma,
> SPAGE_SIZE, DMA_TO_DEVICE);
> free_page((unsigned long)rk_domain->dt);
>
> if (domain->type == IOMMU_DOMAIN_DMA)
> iommu_put_dma_cookie(&rk_domain->domain);
> -
> - platform_device_unregister(rk_domain->pdev);
> }
>
> static bool rk_iommu_is_dev_iommu_master(struct device *dev)
> @@ -1194,30 +1180,6 @@ static const struct iommu_ops rk_iommu_ops = {
> .pgsize_bitmap = RK_IOMMU_PGSIZE_BITMAP,
> };
>
> -static int rk_iommu_domain_probe(struct platform_device *pdev)
> -{
> - struct device *dev = &pdev->dev;
> -
> - dev->dma_parms = devm_kzalloc(dev, sizeof(*dev->dma_parms), GFP_KERNEL);
> - if (!dev->dma_parms)
> - return -ENOMEM;
> -
> - /* Set dma_ops for dev, otherwise it would be dummy_dma_ops */
> - arch_setup_dma_ops(dev, 0, DMA_BIT_MASK(32), NULL, false);
> -
> - dma_set_max_seg_size(dev, DMA_BIT_MASK(32));
> - dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32));
> -
> - return 0;
> -}
> -
> -static struct platform_driver rk_iommu_domain_driver = {
> - .probe = rk_iommu_domain_probe,
> - .driver = {
> - .name = "rk_iommu_domain",
> - },
> -};
> -
> static int rk_iommu_probe(struct platform_device *pdev)
> {
> struct device *dev = &pdev->dev;
> @@ -1278,6 +1240,14 @@ static int rk_iommu_probe(struct platform_device *pdev)
> if (err)
> goto err_remove_sysfs;
>
> + /*
> + * Use the first registered IOMMU device for domain to use with DMA
> + * API, since a domain might not physically correspond to a single
> + * IOMMU device..
> + */
> + if (!dma_dev)
> + dma_dev = &pdev->dev;
> +
> return 0;
> err_remove_sysfs:
> iommu_device_sysfs_remove(&iommu->iommu);
> @@ -1316,14 +1286,7 @@ static int __init rk_iommu_init(void)
> if (ret)
> return ret;
>
> - ret = platform_driver_register(&rk_iommu_domain_driver);
> - if (ret)
> - return ret;
> -
> - ret = platform_driver_register(&rk_iommu_driver);
> - if (ret)
> - platform_driver_unregister(&rk_iommu_domain_driver);
> - return ret;
> + return platform_driver_register(&rk_iommu_driver);
> }
> subsys_initcall(rk_iommu_init);
>
>
^ permalink raw reply [flat|nested] 101+ messages in thread
* [PATCH v4 10/13] iommu/rockchip: Use OF_IOMMU to attach devices automatically
2018-01-18 11:52 ` Jeffy Chen
(?)
@ 2018-01-18 11:52 ` Jeffy Chen
-1 siblings, 0 replies; 101+ messages in thread
From: Jeffy Chen @ 2018-01-18 11:52 UTC (permalink / raw)
To: linux-kernel-u79uwXL29TY76Z2rM5mHXA
Cc: xxm-TNX95d0MmH7DzftRWevZcw, Joerg Roedel, Jeffy Chen,
tfiga-F7+t8E8rja9g9hUCZPvPmw, jcliang-F7+t8E8rja9g9hUCZPvPmw,
linux-rockchip-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
robin.murphy-5wv7dgnIgG8,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Heiko Stuebner
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 <jeffy.chen-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
---
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 | 139 +++++++++++++----------------------------
1 file changed, 44 insertions(+), 95 deletions(-)
diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c
index bdb7c5de6fc2..b1f177ae03c7 100644
--- a/drivers/iommu/rockchip-iommu.c
+++ b/drivers/iommu/rockchip-iommu.c
@@ -19,6 +19,7 @@
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/of_iommu.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
@@ -97,6 +98,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,
@@ -872,18 +877,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,
@@ -1060,110 +1056,57 @@ static void rk_iommu_domain_free(struct iommu_domain *domain)
iommu_put_dma_cookie(&rk_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,
- &args);
- 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, &pd->dev, NULL);
+ iommu_device_link(&iommu->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);
- if (iommu)
- iommu_device_link(&iommu->iommu, dev);
-
- iommu_group_put(group);
-
- return 0;
-err_remove_device:
+ iommu_device_unlink(&iommu->iommu, dev);
iommu_group_remove_device(dev);
-err_put_group:
- iommu_group_put(group);
- return ret;
}
-static void rk_iommu_remove_device(struct device *dev)
+static int rk_iommu_of_xlate(struct device *dev,
+ struct of_phandle_args *args)
{
- struct rk_iommu *iommu;
+ struct platform_device *iommu_dev;
+ struct rk_iommudata *data;
- if (!rk_iommu_is_dev_iommu_master(dev))
- return;
+ data = devm_kzalloc(dma_dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
- iommu = rk_iommu_from_dev(dev);
- if (iommu)
- iommu_device_unlink(&iommu->iommu, dev);
+ iommu_dev = of_find_device_by_node(args->np);
+ if (!iommu_dev) {
+ dev_err(dev, "iommu %pOF not found\n", args->np);
+ return -ENODEV;
+ }
- iommu_group_remove_device(dev);
+ data->iommu = platform_get_drvdata(iommu_dev);
+ dev->archdata.iommu = data;
+
+ of_dev_put(iommu_dev);
+
+ return 0;
}
static const struct iommu_ops rk_iommu_ops = {
@@ -1177,7 +1120,9 @@ 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,
.pgsize_bitmap = RK_IOMMU_PGSIZE_BITMAP,
+ .of_xlate = rk_iommu_of_xlate,
};
static int rk_iommu_probe(struct platform_device *pdev)
@@ -1236,6 +1181,8 @@ static int rk_iommu_probe(struct platform_device *pdev)
goto err_put_clocks;
iommu_device_set_ops(&iommu->iommu, &rk_iommu_ops);
+ iommu_device_set_fwnode(&iommu->iommu, &dev->of_node->fwnode);
+
err = iommu_device_register(&iommu->iommu);
if (err)
goto err_remove_sysfs;
@@ -1290,6 +1237,8 @@ static int __init rk_iommu_init(void)
}
subsys_initcall(rk_iommu_init);
+IOMMU_OF_DECLARE(rk_iommu_of, "rockchip,iommu", NULL);
+
MODULE_DESCRIPTION("IOMMU API for Rockchip");
MODULE_AUTHOR("Simon Xue <xxm-TNX95d0MmH7DzftRWevZcw@public.gmane.org> and Daniel Kurtz <djkurtz-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>");
MODULE_ALIAS("platform:rockchip-iommu");
--
2.11.0
^ permalink raw reply related [flat|nested] 101+ messages in thread* [PATCH v4 10/13] iommu/rockchip: Use OF_IOMMU to attach devices automatically
@ 2018-01-18 11:52 ` Jeffy Chen
0 siblings, 0 replies; 101+ messages in thread
From: Jeffy Chen @ 2018-01-18 11:52 UTC (permalink / raw)
To: linux-kernel
Cc: jcliang, robin.murphy, xxm, tfiga, Jeffy Chen, Heiko Stuebner,
linux-rockchip, iommu, Joerg Roedel, linux-arm-kernel
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 <jeffy.chen@rock-chips.com>
---
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 | 139 +++++++++++++----------------------------
1 file changed, 44 insertions(+), 95 deletions(-)
diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c
index bdb7c5de6fc2..b1f177ae03c7 100644
--- a/drivers/iommu/rockchip-iommu.c
+++ b/drivers/iommu/rockchip-iommu.c
@@ -19,6 +19,7 @@
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/of_iommu.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
@@ -97,6 +98,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,
@@ -872,18 +877,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,
@@ -1060,110 +1056,57 @@ static void rk_iommu_domain_free(struct iommu_domain *domain)
iommu_put_dma_cookie(&rk_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,
- &args);
- 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, &pd->dev, NULL);
+ iommu_device_link(&iommu->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);
- if (iommu)
- iommu_device_link(&iommu->iommu, dev);
-
- iommu_group_put(group);
-
- return 0;
-err_remove_device:
+ iommu_device_unlink(&iommu->iommu, dev);
iommu_group_remove_device(dev);
-err_put_group:
- iommu_group_put(group);
- return ret;
}
-static void rk_iommu_remove_device(struct device *dev)
+static int rk_iommu_of_xlate(struct device *dev,
+ struct of_phandle_args *args)
{
- struct rk_iommu *iommu;
+ struct platform_device *iommu_dev;
+ struct rk_iommudata *data;
- if (!rk_iommu_is_dev_iommu_master(dev))
- return;
+ data = devm_kzalloc(dma_dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
- iommu = rk_iommu_from_dev(dev);
- if (iommu)
- iommu_device_unlink(&iommu->iommu, dev);
+ iommu_dev = of_find_device_by_node(args->np);
+ if (!iommu_dev) {
+ dev_err(dev, "iommu %pOF not found\n", args->np);
+ return -ENODEV;
+ }
- iommu_group_remove_device(dev);
+ data->iommu = platform_get_drvdata(iommu_dev);
+ dev->archdata.iommu = data;
+
+ of_dev_put(iommu_dev);
+
+ return 0;
}
static const struct iommu_ops rk_iommu_ops = {
@@ -1177,7 +1120,9 @@ 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,
.pgsize_bitmap = RK_IOMMU_PGSIZE_BITMAP,
+ .of_xlate = rk_iommu_of_xlate,
};
static int rk_iommu_probe(struct platform_device *pdev)
@@ -1236,6 +1181,8 @@ static int rk_iommu_probe(struct platform_device *pdev)
goto err_put_clocks;
iommu_device_set_ops(&iommu->iommu, &rk_iommu_ops);
+ iommu_device_set_fwnode(&iommu->iommu, &dev->of_node->fwnode);
+
err = iommu_device_register(&iommu->iommu);
if (err)
goto err_remove_sysfs;
@@ -1290,6 +1237,8 @@ static int __init rk_iommu_init(void)
}
subsys_initcall(rk_iommu_init);
+IOMMU_OF_DECLARE(rk_iommu_of, "rockchip,iommu", NULL);
+
MODULE_DESCRIPTION("IOMMU API for Rockchip");
MODULE_AUTHOR("Simon Xue <xxm@rock-chips.com> and Daniel Kurtz <djkurtz@chromium.org>");
MODULE_ALIAS("platform:rockchip-iommu");
--
2.11.0
^ permalink raw reply related [flat|nested] 101+ messages in thread* [PATCH v4 10/13] iommu/rockchip: Use OF_IOMMU to attach devices automatically
@ 2018-01-18 11:52 ` Jeffy Chen
0 siblings, 0 replies; 101+ messages in thread
From: Jeffy Chen @ 2018-01-18 11:52 UTC (permalink / raw)
To: linux-arm-kernel
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 <jeffy.chen@rock-chips.com>
---
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 | 139 +++++++++++++----------------------------
1 file changed, 44 insertions(+), 95 deletions(-)
diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c
index bdb7c5de6fc2..b1f177ae03c7 100644
--- a/drivers/iommu/rockchip-iommu.c
+++ b/drivers/iommu/rockchip-iommu.c
@@ -19,6 +19,7 @@
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/of_iommu.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
@@ -97,6 +98,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,
@@ -872,18 +877,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,
@@ -1060,110 +1056,57 @@ static void rk_iommu_domain_free(struct iommu_domain *domain)
iommu_put_dma_cookie(&rk_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,
- &args);
- 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, &pd->dev, NULL);
+ iommu_device_link(&iommu->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);
- if (iommu)
- iommu_device_link(&iommu->iommu, dev);
-
- iommu_group_put(group);
-
- return 0;
-err_remove_device:
+ iommu_device_unlink(&iommu->iommu, dev);
iommu_group_remove_device(dev);
-err_put_group:
- iommu_group_put(group);
- return ret;
}
-static void rk_iommu_remove_device(struct device *dev)
+static int rk_iommu_of_xlate(struct device *dev,
+ struct of_phandle_args *args)
{
- struct rk_iommu *iommu;
+ struct platform_device *iommu_dev;
+ struct rk_iommudata *data;
- if (!rk_iommu_is_dev_iommu_master(dev))
- return;
+ data = devm_kzalloc(dma_dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
- iommu = rk_iommu_from_dev(dev);
- if (iommu)
- iommu_device_unlink(&iommu->iommu, dev);
+ iommu_dev = of_find_device_by_node(args->np);
+ if (!iommu_dev) {
+ dev_err(dev, "iommu %pOF not found\n", args->np);
+ return -ENODEV;
+ }
- iommu_group_remove_device(dev);
+ data->iommu = platform_get_drvdata(iommu_dev);
+ dev->archdata.iommu = data;
+
+ of_dev_put(iommu_dev);
+
+ return 0;
}
static const struct iommu_ops rk_iommu_ops = {
@@ -1177,7 +1120,9 @@ 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,
.pgsize_bitmap = RK_IOMMU_PGSIZE_BITMAP,
+ .of_xlate = rk_iommu_of_xlate,
};
static int rk_iommu_probe(struct platform_device *pdev)
@@ -1236,6 +1181,8 @@ static int rk_iommu_probe(struct platform_device *pdev)
goto err_put_clocks;
iommu_device_set_ops(&iommu->iommu, &rk_iommu_ops);
+ iommu_device_set_fwnode(&iommu->iommu, &dev->of_node->fwnode);
+
err = iommu_device_register(&iommu->iommu);
if (err)
goto err_remove_sysfs;
@@ -1290,6 +1237,8 @@ static int __init rk_iommu_init(void)
}
subsys_initcall(rk_iommu_init);
+IOMMU_OF_DECLARE(rk_iommu_of, "rockchip,iommu", NULL);
+
MODULE_DESCRIPTION("IOMMU API for Rockchip");
MODULE_AUTHOR("Simon Xue <xxm@rock-chips.com> and Daniel Kurtz <djkurtz@chromium.org>");
MODULE_ALIAS("platform:rockchip-iommu");
--
2.11.0
^ permalink raw reply related [flat|nested] 101+ messages in thread[parent not found: <20180118115251.5542-11-jeffy.chen-TNX95d0MmH7DzftRWevZcw@public.gmane.org>]
* Re: [PATCH v4 10/13] iommu/rockchip: Use OF_IOMMU to attach devices automatically
2018-01-18 11:52 ` Jeffy Chen
(?)
@ 2018-01-18 12:46 ` Robin Murphy
-1 siblings, 0 replies; 101+ messages in thread
From: Robin Murphy @ 2018-01-18 12:46 UTC (permalink / raw)
To: Jeffy Chen, linux-kernel-u79uwXL29TY76Z2rM5mHXA
Cc: Heiko Stuebner, jcliang-F7+t8E8rja9g9hUCZPvPmw,
linux-rockchip-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
On 18/01/18 11:52, Jeffy Chen wrote:
> 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 <jeffy.chen-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
> ---
>
> 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 | 139 +++++++++++++----------------------------
> 1 file changed, 44 insertions(+), 95 deletions(-)
>
> diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c
> index bdb7c5de6fc2..b1f177ae03c7 100644
> --- a/drivers/iommu/rockchip-iommu.c
> +++ b/drivers/iommu/rockchip-iommu.c
> @@ -19,6 +19,7 @@
> #include <linux/mm.h>
> #include <linux/module.h>
> #include <linux/of.h>
> +#include <linux/of_iommu.h>
> #include <linux/of_platform.h>
> #include <linux/platform_device.h>
> #include <linux/slab.h>
> @@ -97,6 +98,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,
> @@ -872,18 +877,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,
> @@ -1060,110 +1056,57 @@ static void rk_iommu_domain_free(struct iommu_domain *domain)
> iommu_put_dma_cookie(&rk_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,
> - &args);
> - 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, &pd->dev, NULL);
> + iommu_device_link(&iommu->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);
> - if (iommu)
> - iommu_device_link(&iommu->iommu, dev);
> -
> - iommu_group_put(group);
> -
> - return 0;
>
> -err_remove_device:
> + iommu_device_unlink(&iommu->iommu, dev);
> iommu_group_remove_device(dev);
> -err_put_group:
> - iommu_group_put(group);
> - return ret;
> }
>
> -static void rk_iommu_remove_device(struct device *dev)
> +static int rk_iommu_of_xlate(struct device *dev,
> + struct of_phandle_args *args)
> {
> - struct rk_iommu *iommu;
> + struct platform_device *iommu_dev;
> + struct rk_iommudata *data;
>
> - if (!rk_iommu_is_dev_iommu_master(dev))
> - return;
> + data = devm_kzalloc(dma_dev, sizeof(*data), GFP_KERNEL);
> + if (!data)
> + return -ENOMEM;
>
> - iommu = rk_iommu_from_dev(dev);
> - if (iommu)
> - iommu_device_unlink(&iommu->iommu, dev);
> + iommu_dev = of_find_device_by_node(args->np);
> + if (!iommu_dev) {
> + dev_err(dev, "iommu %pOF not found\n", args->np);
> + return -ENODEV;
Nit: I think this could only happen if the IOMMU device managed to probe
successfully enough to call iommu_device_register(), but then somehow
disappeared from the platform bus - given patch #1, that now seems
impossible enough that it's probably not worth checking for.
Either way, this looks pretty tidy now;
Reviewed-by: Robin Murphy <robin.murphy-5wv7dgnIgG8@public.gmane.org>
> + }
>
> - iommu_group_remove_device(dev);
> + data->iommu = platform_get_drvdata(iommu_dev);
> + dev->archdata.iommu = data;
> +
> + of_dev_put(iommu_dev);
> +
> + return 0;
> }
>
> static const struct iommu_ops rk_iommu_ops = {
> @@ -1177,7 +1120,9 @@ 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,
> .pgsize_bitmap = RK_IOMMU_PGSIZE_BITMAP,
> + .of_xlate = rk_iommu_of_xlate,
> };
>
> static int rk_iommu_probe(struct platform_device *pdev)
> @@ -1236,6 +1181,8 @@ static int rk_iommu_probe(struct platform_device *pdev)
> goto err_put_clocks;
>
> iommu_device_set_ops(&iommu->iommu, &rk_iommu_ops);
> + iommu_device_set_fwnode(&iommu->iommu, &dev->of_node->fwnode);
> +
> err = iommu_device_register(&iommu->iommu);
> if (err)
> goto err_remove_sysfs;
> @@ -1290,6 +1237,8 @@ static int __init rk_iommu_init(void)
> }
> subsys_initcall(rk_iommu_init);
>
> +IOMMU_OF_DECLARE(rk_iommu_of, "rockchip,iommu", NULL);
> +
> MODULE_DESCRIPTION("IOMMU API for Rockchip");
> MODULE_AUTHOR("Simon Xue <xxm-TNX95d0MmH7DzftRWevZcw@public.gmane.org> and Daniel Kurtz <djkurtz-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>");
> MODULE_ALIAS("platform:rockchip-iommu");
>
^ permalink raw reply [flat|nested] 101+ messages in thread* Re: [PATCH v4 10/13] iommu/rockchip: Use OF_IOMMU to attach devices automatically
@ 2018-01-18 12:46 ` Robin Murphy
0 siblings, 0 replies; 101+ messages in thread
From: Robin Murphy @ 2018-01-18 12:46 UTC (permalink / raw)
To: Jeffy Chen, linux-kernel
Cc: jcliang, xxm, tfiga, Heiko Stuebner, linux-rockchip, iommu,
Joerg Roedel, linux-arm-kernel
On 18/01/18 11:52, Jeffy Chen wrote:
> 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 <jeffy.chen@rock-chips.com>
> ---
>
> 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 | 139 +++++++++++++----------------------------
> 1 file changed, 44 insertions(+), 95 deletions(-)
>
> diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c
> index bdb7c5de6fc2..b1f177ae03c7 100644
> --- a/drivers/iommu/rockchip-iommu.c
> +++ b/drivers/iommu/rockchip-iommu.c
> @@ -19,6 +19,7 @@
> #include <linux/mm.h>
> #include <linux/module.h>
> #include <linux/of.h>
> +#include <linux/of_iommu.h>
> #include <linux/of_platform.h>
> #include <linux/platform_device.h>
> #include <linux/slab.h>
> @@ -97,6 +98,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,
> @@ -872,18 +877,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,
> @@ -1060,110 +1056,57 @@ static void rk_iommu_domain_free(struct iommu_domain *domain)
> iommu_put_dma_cookie(&rk_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,
> - &args);
> - 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, &pd->dev, NULL);
> + iommu_device_link(&iommu->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);
> - if (iommu)
> - iommu_device_link(&iommu->iommu, dev);
> -
> - iommu_group_put(group);
> -
> - return 0;
>
> -err_remove_device:
> + iommu_device_unlink(&iommu->iommu, dev);
> iommu_group_remove_device(dev);
> -err_put_group:
> - iommu_group_put(group);
> - return ret;
> }
>
> -static void rk_iommu_remove_device(struct device *dev)
> +static int rk_iommu_of_xlate(struct device *dev,
> + struct of_phandle_args *args)
> {
> - struct rk_iommu *iommu;
> + struct platform_device *iommu_dev;
> + struct rk_iommudata *data;
>
> - if (!rk_iommu_is_dev_iommu_master(dev))
> - return;
> + data = devm_kzalloc(dma_dev, sizeof(*data), GFP_KERNEL);
> + if (!data)
> + return -ENOMEM;
>
> - iommu = rk_iommu_from_dev(dev);
> - if (iommu)
> - iommu_device_unlink(&iommu->iommu, dev);
> + iommu_dev = of_find_device_by_node(args->np);
> + if (!iommu_dev) {
> + dev_err(dev, "iommu %pOF not found\n", args->np);
> + return -ENODEV;
Nit: I think this could only happen if the IOMMU device managed to probe
successfully enough to call iommu_device_register(), but then somehow
disappeared from the platform bus - given patch #1, that now seems
impossible enough that it's probably not worth checking for.
Either way, this looks pretty tidy now;
Reviewed-by: Robin Murphy <robin.murphy@arm.com>
> + }
>
> - iommu_group_remove_device(dev);
> + data->iommu = platform_get_drvdata(iommu_dev);
> + dev->archdata.iommu = data;
> +
> + of_dev_put(iommu_dev);
> +
> + return 0;
> }
>
> static const struct iommu_ops rk_iommu_ops = {
> @@ -1177,7 +1120,9 @@ 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,
> .pgsize_bitmap = RK_IOMMU_PGSIZE_BITMAP,
> + .of_xlate = rk_iommu_of_xlate,
> };
>
> static int rk_iommu_probe(struct platform_device *pdev)
> @@ -1236,6 +1181,8 @@ static int rk_iommu_probe(struct platform_device *pdev)
> goto err_put_clocks;
>
> iommu_device_set_ops(&iommu->iommu, &rk_iommu_ops);
> + iommu_device_set_fwnode(&iommu->iommu, &dev->of_node->fwnode);
> +
> err = iommu_device_register(&iommu->iommu);
> if (err)
> goto err_remove_sysfs;
> @@ -1290,6 +1237,8 @@ static int __init rk_iommu_init(void)
> }
> subsys_initcall(rk_iommu_init);
>
> +IOMMU_OF_DECLARE(rk_iommu_of, "rockchip,iommu", NULL);
> +
> MODULE_DESCRIPTION("IOMMU API for Rockchip");
> MODULE_AUTHOR("Simon Xue <xxm@rock-chips.com> and Daniel Kurtz <djkurtz@chromium.org>");
> MODULE_ALIAS("platform:rockchip-iommu");
>
^ permalink raw reply [flat|nested] 101+ messages in thread* [PATCH v4 10/13] iommu/rockchip: Use OF_IOMMU to attach devices automatically
@ 2018-01-18 12:46 ` Robin Murphy
0 siblings, 0 replies; 101+ messages in thread
From: Robin Murphy @ 2018-01-18 12:46 UTC (permalink / raw)
To: linux-arm-kernel
On 18/01/18 11:52, Jeffy Chen wrote:
> 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 <jeffy.chen@rock-chips.com>
> ---
>
> 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 | 139 +++++++++++++----------------------------
> 1 file changed, 44 insertions(+), 95 deletions(-)
>
> diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c
> index bdb7c5de6fc2..b1f177ae03c7 100644
> --- a/drivers/iommu/rockchip-iommu.c
> +++ b/drivers/iommu/rockchip-iommu.c
> @@ -19,6 +19,7 @@
> #include <linux/mm.h>
> #include <linux/module.h>
> #include <linux/of.h>
> +#include <linux/of_iommu.h>
> #include <linux/of_platform.h>
> #include <linux/platform_device.h>
> #include <linux/slab.h>
> @@ -97,6 +98,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,
> @@ -872,18 +877,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,
> @@ -1060,110 +1056,57 @@ static void rk_iommu_domain_free(struct iommu_domain *domain)
> iommu_put_dma_cookie(&rk_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,
> - &args);
> - 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, &pd->dev, NULL);
> + iommu_device_link(&iommu->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);
> - if (iommu)
> - iommu_device_link(&iommu->iommu, dev);
> -
> - iommu_group_put(group);
> -
> - return 0;
>
> -err_remove_device:
> + iommu_device_unlink(&iommu->iommu, dev);
> iommu_group_remove_device(dev);
> -err_put_group:
> - iommu_group_put(group);
> - return ret;
> }
>
> -static void rk_iommu_remove_device(struct device *dev)
> +static int rk_iommu_of_xlate(struct device *dev,
> + struct of_phandle_args *args)
> {
> - struct rk_iommu *iommu;
> + struct platform_device *iommu_dev;
> + struct rk_iommudata *data;
>
> - if (!rk_iommu_is_dev_iommu_master(dev))
> - return;
> + data = devm_kzalloc(dma_dev, sizeof(*data), GFP_KERNEL);
> + if (!data)
> + return -ENOMEM;
>
> - iommu = rk_iommu_from_dev(dev);
> - if (iommu)
> - iommu_device_unlink(&iommu->iommu, dev);
> + iommu_dev = of_find_device_by_node(args->np);
> + if (!iommu_dev) {
> + dev_err(dev, "iommu %pOF not found\n", args->np);
> + return -ENODEV;
Nit: I think this could only happen if the IOMMU device managed to probe
successfully enough to call iommu_device_register(), but then somehow
disappeared from the platform bus - given patch #1, that now seems
impossible enough that it's probably not worth checking for.
Either way, this looks pretty tidy now;
Reviewed-by: Robin Murphy <robin.murphy@arm.com>
> + }
>
> - iommu_group_remove_device(dev);
> + data->iommu = platform_get_drvdata(iommu_dev);
> + dev->archdata.iommu = data;
> +
> + of_dev_put(iommu_dev);
> +
> + return 0;
> }
>
> static const struct iommu_ops rk_iommu_ops = {
> @@ -1177,7 +1120,9 @@ 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,
> .pgsize_bitmap = RK_IOMMU_PGSIZE_BITMAP,
> + .of_xlate = rk_iommu_of_xlate,
> };
>
> static int rk_iommu_probe(struct platform_device *pdev)
> @@ -1236,6 +1181,8 @@ static int rk_iommu_probe(struct platform_device *pdev)
> goto err_put_clocks;
>
> iommu_device_set_ops(&iommu->iommu, &rk_iommu_ops);
> + iommu_device_set_fwnode(&iommu->iommu, &dev->of_node->fwnode);
> +
> err = iommu_device_register(&iommu->iommu);
> if (err)
> goto err_remove_sysfs;
> @@ -1290,6 +1237,8 @@ static int __init rk_iommu_init(void)
> }
> subsys_initcall(rk_iommu_init);
>
> +IOMMU_OF_DECLARE(rk_iommu_of, "rockchip,iommu", NULL);
> +
> MODULE_DESCRIPTION("IOMMU API for Rockchip");
> MODULE_AUTHOR("Simon Xue <xxm@rock-chips.com> and Daniel Kurtz <djkurtz@chromium.org>");
> MODULE_ALIAS("platform:rockchip-iommu");
>
^ permalink raw reply [flat|nested] 101+ messages in thread
* [PATCH v4 12/13] iommu/rockchip: Add runtime PM support
2018-01-18 11:52 ` Jeffy Chen
(?)
@ 2018-01-18 11:52 ` Jeffy Chen
-1 siblings, 0 replies; 101+ messages in thread
From: Jeffy Chen @ 2018-01-18 11:52 UTC (permalink / raw)
To: linux-kernel-u79uwXL29TY76Z2rM5mHXA
Cc: Jeffy Chen, jcliang-F7+t8E8rja9g9hUCZPvPmw,
linux-rockchip-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Heiko Stuebner
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 <jeffy.chen-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
---
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 | 180 ++++++++++++++++++++++++++++++++---------
1 file changed, 141 insertions(+), 39 deletions(-)
diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c
index 2c095f96c033..e2e7acc3039d 100644
--- a/drivers/iommu/rockchip-iommu.c
+++ b/drivers/iommu/rockchip-iommu.c
@@ -22,6 +22,7 @@
#include <linux/of_iommu.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
@@ -99,6 +100,7 @@ struct rk_iommu {
};
struct rk_iommudata {
+ struct device_link *link; /* runtime PM link from IOMMU to master */
struct rk_iommu *iommu;
};
@@ -583,7 +585,11 @@ 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;
+
+ err = pm_runtime_get_if_in_use(iommu->dev);
+ if (err <= 0 && err != -EINVAL)
+ return ret;
WARN_ON(rk_iommu_enable_clocks(iommu));
@@ -635,6 +641,9 @@ static irqreturn_t rk_iommu_irq(int irq, void *dev_id)
rk_iommu_disable_clocks(iommu);
+ if (pm_runtime_enabled(iommu->dev))
+ pm_runtime_put(iommu->dev);
+
return ret;
}
@@ -676,10 +685,20 @@ static void rk_iommu_zap_iova(struct rk_iommu_domain *rk_domain,
spin_lock_irqsave(&rk_domain->iommus_lock, flags);
list_for_each(pos, &rk_domain->iommus) {
struct rk_iommu *iommu;
+ int ret;
+
iommu = list_entry(pos, struct rk_iommu, node);
- rk_iommu_enable_clocks(iommu);
- rk_iommu_zap_lines(iommu, iova, size);
- rk_iommu_disable_clocks(iommu);
+
+ /* Only zap TLBs of IOMMUs that are powered on. */
+ ret = pm_runtime_get_if_in_use(iommu->dev);
+ if (ret > 0 || ret == -EINVAL) {
+ rk_iommu_enable_clocks(iommu);
+ rk_iommu_zap_lines(iommu, iova, size);
+ rk_iommu_disable_clocks(iommu);
+ }
+
+ if (ret > 0)
+ pm_runtime_put(iommu->dev);
}
spin_unlock_irqrestore(&rk_domain->iommus_lock, flags);
}
@@ -882,22 +901,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(rk_iommu_enable_clocks(iommu));
+ 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);
+ rk_iommu_disable_clocks(iommu);
+}
+
+/* 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 = rk_iommu_enable_clocks(iommu);
if (ret)
return ret;
@@ -910,8 +937,6 @@ static int rk_iommu_attach_device(struct iommu_domain *domain,
if (ret)
goto err_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);
@@ -923,12 +948,6 @@ static int rk_iommu_attach_device(struct iommu_domain *domain,
if (ret)
goto err_disable_stall;
- spin_lock_irqsave(&rk_domain->iommus_lock, flags);
- list_add_tail(&iommu->node, &rk_domain->iommus);
- spin_unlock_irqrestore(&rk_domain->iommus_lock, flags);
-
- dev_dbg(dev, "Attached to iommu domain\n");
-
rk_iommu_disable_stall(iommu);
rk_iommu_disable_clocks(iommu);
@@ -948,31 +967,78 @@ static void rk_iommu_detach_device(struct iommu_domain *domain,
struct rk_iommu *iommu;
struct rk_iommu_domain *rk_domain = to_rk_domain(domain);
unsigned long flags;
- int i;
+ int ret;
/* Allow 'virtual devices' (eg drm) to detach from domain */
iommu = rk_iommu_from_dev(dev);
if (!iommu)
return;
+ dev_dbg(dev, "Detaching from iommu domain\n");
+
+ /* iommu already detached */
+ if (iommu->domain != domain)
+ return;
+
+ iommu->domain = NULL;
+
spin_lock_irqsave(&rk_domain->iommus_lock, flags);
list_del_init(&iommu->node);
spin_unlock_irqrestore(&rk_domain->iommus_lock, flags);
- /* Ignore error while disabling, just keep going */
- WARN_ON(rk_iommu_enable_clocks(iommu));
- 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);
- rk_iommu_disable_clocks(iommu);
+ ret = pm_runtime_get_if_in_use(iommu->dev);
+ if (ret <= 0 && ret != -EINVAL)
+ return;
- iommu->domain = NULL;
+ rk_iommu_shutdown(iommu);
+
+ if (pm_runtime_enabled(iommu->dev))
+ pm_runtime_put(iommu->dev);
+}
+
+static int rk_iommu_attach_device(struct iommu_domain *domain,
+ struct device *dev)
+{
+ struct rk_iommu *iommu;
+ struct rk_iommu_domain *rk_domain = to_rk_domain(domain);
+ unsigned long flags;
+ int ret;
+
+ /*
+ * 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;
+
+ dev_dbg(dev, "Attaching to iommu domain\n");
+
+ /* iommu already attached */
+ if (iommu->domain == domain)
+ return 0;
+
+ if (iommu->domain)
+ rk_iommu_detach_device(iommu->domain, dev);
+
+ iommu->domain = domain;
+
+ spin_lock_irqsave(&rk_domain->iommus_lock, flags);
+ list_add_tail(&iommu->node, &rk_domain->iommus);
+ spin_unlock_irqrestore(&rk_domain->iommus_lock, flags);
- dev_dbg(dev, "Detached from iommu domain\n");
+ ret = pm_runtime_get_if_in_use(iommu->dev);
+ if (ret <= 0 && ret != -EINVAL)
+ return 0;
+
+ ret = rk_iommu_startup(iommu);
+ if (ret)
+ rk_iommu_detach_device(iommu->domain, dev);
+
+ if (pm_runtime_enabled(iommu->dev))
+ pm_runtime_put(iommu->dev);
+
+ return ret;
}
static struct iommu_domain *rk_iommu_domain_alloc(unsigned type)
@@ -1060,17 +1126,21 @@ static int rk_iommu_add_device(struct device *dev)
{
struct iommu_group *group;
struct rk_iommu *iommu;
+ struct rk_iommudata *data;
- iommu = rk_iommu_from_dev(dev);
- if (!iommu)
+ data = dev->archdata.iommu;
+ if (!data)
return -ENODEV;
+ iommu = rk_iommu_from_dev(dev);
+
group = iommu_group_get_for_dev(dev);
if (IS_ERR(group))
return PTR_ERR(group);
iommu_group_put(group);
iommu_device_link(&iommu->iommu, dev);
+ data->link = device_link_add(dev, iommu->dev, DL_FLAG_PM_RUNTIME);
return 0;
}
@@ -1078,9 +1148,11 @@ static int rk_iommu_add_device(struct device *dev)
static void rk_iommu_remove_device(struct device *dev)
{
struct rk_iommu *iommu;
+ struct rk_iommudata *data = dev->archdata.iommu;
iommu = rk_iommu_from_dev(dev);
+ device_link_del(data->link);
iommu_device_unlink(&iommu->iommu, dev);
iommu_group_remove_device(dev);
}
@@ -1197,6 +1269,8 @@ static int rk_iommu_probe(struct platform_device *pdev)
bus_set_iommu(&platform_bus_type, &rk_iommu_ops);
+ pm_runtime_enable(dev);
+
return 0;
err_remove_sysfs:
iommu_device_sysfs_remove(&iommu->iommu);
@@ -1205,6 +1279,33 @@ static int rk_iommu_probe(struct platform_device *pdev)
return err;
}
+static int __maybe_unused rk_iommu_suspend(struct device *dev)
+{
+ struct rk_iommu *iommu = dev_get_drvdata(dev);
+
+ if (!iommu->domain)
+ return 0;
+
+ rk_iommu_shutdown(iommu);
+ return 0;
+}
+
+static int __maybe_unused rk_iommu_resume(struct device *dev)
+{
+ struct rk_iommu *iommu = dev_get_drvdata(dev);
+
+ if (!iommu->domain)
+ return 0;
+
+ return rk_iommu_startup(iommu);
+}
+
+static const struct dev_pm_ops rk_iommu_pm_ops = {
+ SET_RUNTIME_PM_OPS(rk_iommu_suspend, rk_iommu_resume, NULL)
+ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+ pm_runtime_force_resume)
+};
+
static const struct of_device_id rk_iommu_dt_ids[] = {
{ .compatible = "rockchip,iommu" },
{ /* sentinel */ }
@@ -1216,6 +1317,7 @@ static struct platform_driver rk_iommu_driver = {
.driver = {
.name = "rk_iommu",
.of_match_table = rk_iommu_dt_ids,
+ .pm = &rk_iommu_pm_ops,
.suppress_bind_attrs = true,
},
};
--
2.11.0
^ permalink raw reply related [flat|nested] 101+ messages in thread* [PATCH v4 12/13] iommu/rockchip: Add runtime PM support
@ 2018-01-18 11:52 ` Jeffy Chen
0 siblings, 0 replies; 101+ messages in thread
From: Jeffy Chen @ 2018-01-18 11:52 UTC (permalink / raw)
To: linux-kernel
Cc: jcliang, robin.murphy, xxm, tfiga, Jeffy Chen, Heiko Stuebner,
linux-rockchip, iommu, Joerg Roedel, linux-arm-kernel
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 <jeffy.chen@rock-chips.com>
---
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 | 180 ++++++++++++++++++++++++++++++++---------
1 file changed, 141 insertions(+), 39 deletions(-)
diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c
index 2c095f96c033..e2e7acc3039d 100644
--- a/drivers/iommu/rockchip-iommu.c
+++ b/drivers/iommu/rockchip-iommu.c
@@ -22,6 +22,7 @@
#include <linux/of_iommu.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
@@ -99,6 +100,7 @@ struct rk_iommu {
};
struct rk_iommudata {
+ struct device_link *link; /* runtime PM link from IOMMU to master */
struct rk_iommu *iommu;
};
@@ -583,7 +585,11 @@ 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;
+
+ err = pm_runtime_get_if_in_use(iommu->dev);
+ if (err <= 0 && err != -EINVAL)
+ return ret;
WARN_ON(rk_iommu_enable_clocks(iommu));
@@ -635,6 +641,9 @@ static irqreturn_t rk_iommu_irq(int irq, void *dev_id)
rk_iommu_disable_clocks(iommu);
+ if (pm_runtime_enabled(iommu->dev))
+ pm_runtime_put(iommu->dev);
+
return ret;
}
@@ -676,10 +685,20 @@ static void rk_iommu_zap_iova(struct rk_iommu_domain *rk_domain,
spin_lock_irqsave(&rk_domain->iommus_lock, flags);
list_for_each(pos, &rk_domain->iommus) {
struct rk_iommu *iommu;
+ int ret;
+
iommu = list_entry(pos, struct rk_iommu, node);
- rk_iommu_enable_clocks(iommu);
- rk_iommu_zap_lines(iommu, iova, size);
- rk_iommu_disable_clocks(iommu);
+
+ /* Only zap TLBs of IOMMUs that are powered on. */
+ ret = pm_runtime_get_if_in_use(iommu->dev);
+ if (ret > 0 || ret == -EINVAL) {
+ rk_iommu_enable_clocks(iommu);
+ rk_iommu_zap_lines(iommu, iova, size);
+ rk_iommu_disable_clocks(iommu);
+ }
+
+ if (ret > 0)
+ pm_runtime_put(iommu->dev);
}
spin_unlock_irqrestore(&rk_domain->iommus_lock, flags);
}
@@ -882,22 +901,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(rk_iommu_enable_clocks(iommu));
+ 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);
+ rk_iommu_disable_clocks(iommu);
+}
+
+/* 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 = rk_iommu_enable_clocks(iommu);
if (ret)
return ret;
@@ -910,8 +937,6 @@ static int rk_iommu_attach_device(struct iommu_domain *domain,
if (ret)
goto err_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);
@@ -923,12 +948,6 @@ static int rk_iommu_attach_device(struct iommu_domain *domain,
if (ret)
goto err_disable_stall;
- spin_lock_irqsave(&rk_domain->iommus_lock, flags);
- list_add_tail(&iommu->node, &rk_domain->iommus);
- spin_unlock_irqrestore(&rk_domain->iommus_lock, flags);
-
- dev_dbg(dev, "Attached to iommu domain\n");
-
rk_iommu_disable_stall(iommu);
rk_iommu_disable_clocks(iommu);
@@ -948,31 +967,78 @@ static void rk_iommu_detach_device(struct iommu_domain *domain,
struct rk_iommu *iommu;
struct rk_iommu_domain *rk_domain = to_rk_domain(domain);
unsigned long flags;
- int i;
+ int ret;
/* Allow 'virtual devices' (eg drm) to detach from domain */
iommu = rk_iommu_from_dev(dev);
if (!iommu)
return;
+ dev_dbg(dev, "Detaching from iommu domain\n");
+
+ /* iommu already detached */
+ if (iommu->domain != domain)
+ return;
+
+ iommu->domain = NULL;
+
spin_lock_irqsave(&rk_domain->iommus_lock, flags);
list_del_init(&iommu->node);
spin_unlock_irqrestore(&rk_domain->iommus_lock, flags);
- /* Ignore error while disabling, just keep going */
- WARN_ON(rk_iommu_enable_clocks(iommu));
- 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);
- rk_iommu_disable_clocks(iommu);
+ ret = pm_runtime_get_if_in_use(iommu->dev);
+ if (ret <= 0 && ret != -EINVAL)
+ return;
- iommu->domain = NULL;
+ rk_iommu_shutdown(iommu);
+
+ if (pm_runtime_enabled(iommu->dev))
+ pm_runtime_put(iommu->dev);
+}
+
+static int rk_iommu_attach_device(struct iommu_domain *domain,
+ struct device *dev)
+{
+ struct rk_iommu *iommu;
+ struct rk_iommu_domain *rk_domain = to_rk_domain(domain);
+ unsigned long flags;
+ int ret;
+
+ /*
+ * 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;
+
+ dev_dbg(dev, "Attaching to iommu domain\n");
+
+ /* iommu already attached */
+ if (iommu->domain == domain)
+ return 0;
+
+ if (iommu->domain)
+ rk_iommu_detach_device(iommu->domain, dev);
+
+ iommu->domain = domain;
+
+ spin_lock_irqsave(&rk_domain->iommus_lock, flags);
+ list_add_tail(&iommu->node, &rk_domain->iommus);
+ spin_unlock_irqrestore(&rk_domain->iommus_lock, flags);
- dev_dbg(dev, "Detached from iommu domain\n");
+ ret = pm_runtime_get_if_in_use(iommu->dev);
+ if (ret <= 0 && ret != -EINVAL)
+ return 0;
+
+ ret = rk_iommu_startup(iommu);
+ if (ret)
+ rk_iommu_detach_device(iommu->domain, dev);
+
+ if (pm_runtime_enabled(iommu->dev))
+ pm_runtime_put(iommu->dev);
+
+ return ret;
}
static struct iommu_domain *rk_iommu_domain_alloc(unsigned type)
@@ -1060,17 +1126,21 @@ static int rk_iommu_add_device(struct device *dev)
{
struct iommu_group *group;
struct rk_iommu *iommu;
+ struct rk_iommudata *data;
- iommu = rk_iommu_from_dev(dev);
- if (!iommu)
+ data = dev->archdata.iommu;
+ if (!data)
return -ENODEV;
+ iommu = rk_iommu_from_dev(dev);
+
group = iommu_group_get_for_dev(dev);
if (IS_ERR(group))
return PTR_ERR(group);
iommu_group_put(group);
iommu_device_link(&iommu->iommu, dev);
+ data->link = device_link_add(dev, iommu->dev, DL_FLAG_PM_RUNTIME);
return 0;
}
@@ -1078,9 +1148,11 @@ static int rk_iommu_add_device(struct device *dev)
static void rk_iommu_remove_device(struct device *dev)
{
struct rk_iommu *iommu;
+ struct rk_iommudata *data = dev->archdata.iommu;
iommu = rk_iommu_from_dev(dev);
+ device_link_del(data->link);
iommu_device_unlink(&iommu->iommu, dev);
iommu_group_remove_device(dev);
}
@@ -1197,6 +1269,8 @@ static int rk_iommu_probe(struct platform_device *pdev)
bus_set_iommu(&platform_bus_type, &rk_iommu_ops);
+ pm_runtime_enable(dev);
+
return 0;
err_remove_sysfs:
iommu_device_sysfs_remove(&iommu->iommu);
@@ -1205,6 +1279,33 @@ static int rk_iommu_probe(struct platform_device *pdev)
return err;
}
+static int __maybe_unused rk_iommu_suspend(struct device *dev)
+{
+ struct rk_iommu *iommu = dev_get_drvdata(dev);
+
+ if (!iommu->domain)
+ return 0;
+
+ rk_iommu_shutdown(iommu);
+ return 0;
+}
+
+static int __maybe_unused rk_iommu_resume(struct device *dev)
+{
+ struct rk_iommu *iommu = dev_get_drvdata(dev);
+
+ if (!iommu->domain)
+ return 0;
+
+ return rk_iommu_startup(iommu);
+}
+
+static const struct dev_pm_ops rk_iommu_pm_ops = {
+ SET_RUNTIME_PM_OPS(rk_iommu_suspend, rk_iommu_resume, NULL)
+ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+ pm_runtime_force_resume)
+};
+
static const struct of_device_id rk_iommu_dt_ids[] = {
{ .compatible = "rockchip,iommu" },
{ /* sentinel */ }
@@ -1216,6 +1317,7 @@ static struct platform_driver rk_iommu_driver = {
.driver = {
.name = "rk_iommu",
.of_match_table = rk_iommu_dt_ids,
+ .pm = &rk_iommu_pm_ops,
.suppress_bind_attrs = true,
},
};
--
2.11.0
^ permalink raw reply related [flat|nested] 101+ messages in thread* [PATCH v4 12/13] iommu/rockchip: Add runtime PM support
@ 2018-01-18 11:52 ` Jeffy Chen
0 siblings, 0 replies; 101+ messages in thread
From: Jeffy Chen @ 2018-01-18 11:52 UTC (permalink / raw)
To: linux-arm-kernel
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 <jeffy.chen@rock-chips.com>
---
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 | 180 ++++++++++++++++++++++++++++++++---------
1 file changed, 141 insertions(+), 39 deletions(-)
diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c
index 2c095f96c033..e2e7acc3039d 100644
--- a/drivers/iommu/rockchip-iommu.c
+++ b/drivers/iommu/rockchip-iommu.c
@@ -22,6 +22,7 @@
#include <linux/of_iommu.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
@@ -99,6 +100,7 @@ struct rk_iommu {
};
struct rk_iommudata {
+ struct device_link *link; /* runtime PM link from IOMMU to master */
struct rk_iommu *iommu;
};
@@ -583,7 +585,11 @@ 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;
+
+ err = pm_runtime_get_if_in_use(iommu->dev);
+ if (err <= 0 && err != -EINVAL)
+ return ret;
WARN_ON(rk_iommu_enable_clocks(iommu));
@@ -635,6 +641,9 @@ static irqreturn_t rk_iommu_irq(int irq, void *dev_id)
rk_iommu_disable_clocks(iommu);
+ if (pm_runtime_enabled(iommu->dev))
+ pm_runtime_put(iommu->dev);
+
return ret;
}
@@ -676,10 +685,20 @@ static void rk_iommu_zap_iova(struct rk_iommu_domain *rk_domain,
spin_lock_irqsave(&rk_domain->iommus_lock, flags);
list_for_each(pos, &rk_domain->iommus) {
struct rk_iommu *iommu;
+ int ret;
+
iommu = list_entry(pos, struct rk_iommu, node);
- rk_iommu_enable_clocks(iommu);
- rk_iommu_zap_lines(iommu, iova, size);
- rk_iommu_disable_clocks(iommu);
+
+ /* Only zap TLBs of IOMMUs that are powered on. */
+ ret = pm_runtime_get_if_in_use(iommu->dev);
+ if (ret > 0 || ret == -EINVAL) {
+ rk_iommu_enable_clocks(iommu);
+ rk_iommu_zap_lines(iommu, iova, size);
+ rk_iommu_disable_clocks(iommu);
+ }
+
+ if (ret > 0)
+ pm_runtime_put(iommu->dev);
}
spin_unlock_irqrestore(&rk_domain->iommus_lock, flags);
}
@@ -882,22 +901,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(rk_iommu_enable_clocks(iommu));
+ 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);
+ rk_iommu_disable_clocks(iommu);
+}
+
+/* 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 = rk_iommu_enable_clocks(iommu);
if (ret)
return ret;
@@ -910,8 +937,6 @@ static int rk_iommu_attach_device(struct iommu_domain *domain,
if (ret)
goto err_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);
@@ -923,12 +948,6 @@ static int rk_iommu_attach_device(struct iommu_domain *domain,
if (ret)
goto err_disable_stall;
- spin_lock_irqsave(&rk_domain->iommus_lock, flags);
- list_add_tail(&iommu->node, &rk_domain->iommus);
- spin_unlock_irqrestore(&rk_domain->iommus_lock, flags);
-
- dev_dbg(dev, "Attached to iommu domain\n");
-
rk_iommu_disable_stall(iommu);
rk_iommu_disable_clocks(iommu);
@@ -948,31 +967,78 @@ static void rk_iommu_detach_device(struct iommu_domain *domain,
struct rk_iommu *iommu;
struct rk_iommu_domain *rk_domain = to_rk_domain(domain);
unsigned long flags;
- int i;
+ int ret;
/* Allow 'virtual devices' (eg drm) to detach from domain */
iommu = rk_iommu_from_dev(dev);
if (!iommu)
return;
+ dev_dbg(dev, "Detaching from iommu domain\n");
+
+ /* iommu already detached */
+ if (iommu->domain != domain)
+ return;
+
+ iommu->domain = NULL;
+
spin_lock_irqsave(&rk_domain->iommus_lock, flags);
list_del_init(&iommu->node);
spin_unlock_irqrestore(&rk_domain->iommus_lock, flags);
- /* Ignore error while disabling, just keep going */
- WARN_ON(rk_iommu_enable_clocks(iommu));
- 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);
- rk_iommu_disable_clocks(iommu);
+ ret = pm_runtime_get_if_in_use(iommu->dev);
+ if (ret <= 0 && ret != -EINVAL)
+ return;
- iommu->domain = NULL;
+ rk_iommu_shutdown(iommu);
+
+ if (pm_runtime_enabled(iommu->dev))
+ pm_runtime_put(iommu->dev);
+}
+
+static int rk_iommu_attach_device(struct iommu_domain *domain,
+ struct device *dev)
+{
+ struct rk_iommu *iommu;
+ struct rk_iommu_domain *rk_domain = to_rk_domain(domain);
+ unsigned long flags;
+ int ret;
+
+ /*
+ * 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;
+
+ dev_dbg(dev, "Attaching to iommu domain\n");
+
+ /* iommu already attached */
+ if (iommu->domain == domain)
+ return 0;
+
+ if (iommu->domain)
+ rk_iommu_detach_device(iommu->domain, dev);
+
+ iommu->domain = domain;
+
+ spin_lock_irqsave(&rk_domain->iommus_lock, flags);
+ list_add_tail(&iommu->node, &rk_domain->iommus);
+ spin_unlock_irqrestore(&rk_domain->iommus_lock, flags);
- dev_dbg(dev, "Detached from iommu domain\n");
+ ret = pm_runtime_get_if_in_use(iommu->dev);
+ if (ret <= 0 && ret != -EINVAL)
+ return 0;
+
+ ret = rk_iommu_startup(iommu);
+ if (ret)
+ rk_iommu_detach_device(iommu->domain, dev);
+
+ if (pm_runtime_enabled(iommu->dev))
+ pm_runtime_put(iommu->dev);
+
+ return ret;
}
static struct iommu_domain *rk_iommu_domain_alloc(unsigned type)
@@ -1060,17 +1126,21 @@ static int rk_iommu_add_device(struct device *dev)
{
struct iommu_group *group;
struct rk_iommu *iommu;
+ struct rk_iommudata *data;
- iommu = rk_iommu_from_dev(dev);
- if (!iommu)
+ data = dev->archdata.iommu;
+ if (!data)
return -ENODEV;
+ iommu = rk_iommu_from_dev(dev);
+
group = iommu_group_get_for_dev(dev);
if (IS_ERR(group))
return PTR_ERR(group);
iommu_group_put(group);
iommu_device_link(&iommu->iommu, dev);
+ data->link = device_link_add(dev, iommu->dev, DL_FLAG_PM_RUNTIME);
return 0;
}
@@ -1078,9 +1148,11 @@ static int rk_iommu_add_device(struct device *dev)
static void rk_iommu_remove_device(struct device *dev)
{
struct rk_iommu *iommu;
+ struct rk_iommudata *data = dev->archdata.iommu;
iommu = rk_iommu_from_dev(dev);
+ device_link_del(data->link);
iommu_device_unlink(&iommu->iommu, dev);
iommu_group_remove_device(dev);
}
@@ -1197,6 +1269,8 @@ static int rk_iommu_probe(struct platform_device *pdev)
bus_set_iommu(&platform_bus_type, &rk_iommu_ops);
+ pm_runtime_enable(dev);
+
return 0;
err_remove_sysfs:
iommu_device_sysfs_remove(&iommu->iommu);
@@ -1205,6 +1279,33 @@ static int rk_iommu_probe(struct platform_device *pdev)
return err;
}
+static int __maybe_unused rk_iommu_suspend(struct device *dev)
+{
+ struct rk_iommu *iommu = dev_get_drvdata(dev);
+
+ if (!iommu->domain)
+ return 0;
+
+ rk_iommu_shutdown(iommu);
+ return 0;
+}
+
+static int __maybe_unused rk_iommu_resume(struct device *dev)
+{
+ struct rk_iommu *iommu = dev_get_drvdata(dev);
+
+ if (!iommu->domain)
+ return 0;
+
+ return rk_iommu_startup(iommu);
+}
+
+static const struct dev_pm_ops rk_iommu_pm_ops = {
+ SET_RUNTIME_PM_OPS(rk_iommu_suspend, rk_iommu_resume, NULL)
+ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+ pm_runtime_force_resume)
+};
+
static const struct of_device_id rk_iommu_dt_ids[] = {
{ .compatible = "rockchip,iommu" },
{ /* sentinel */ }
@@ -1216,6 +1317,7 @@ static struct platform_driver rk_iommu_driver = {
.driver = {
.name = "rk_iommu",
.of_match_table = rk_iommu_dt_ids,
+ .pm = &rk_iommu_pm_ops,
.suppress_bind_attrs = true,
},
};
--
2.11.0
^ permalink raw reply related [flat|nested] 101+ messages in thread[parent not found: <20180118115251.5542-13-jeffy.chen-TNX95d0MmH7DzftRWevZcw@public.gmane.org>]
* Re: [PATCH v4 12/13] iommu/rockchip: Add runtime PM support
2018-01-18 11:52 ` Jeffy Chen
(?)
@ 2018-01-19 4:01 ` Tomasz Figa
-1 siblings, 0 replies; 101+ messages in thread
From: Tomasz Figa @ 2018-01-19 4:01 UTC (permalink / raw)
To: Jeffy Chen
Cc: Heiko Stuebner, linux-kernel-u79uwXL29TY76Z2rM5mHXA, Ricky Liang,
open list:ARM/Rockchip SoC..., open list:IOMMU DRIVERS,
list-Y9sIeH5OGRo@public.gmane.org:IOMMU DRIVERS <iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA@public.gmane.org>, Joerg Roedel <joro-zLv9SwRftAIdnm+yROfE0A@public.gmane.org>,
On Thu, Jan 18, 2018 at 8:52 PM, Jeffy Chen <jeffy.chen-TNX95d0MmH7DzftRWevZcw@public.gmane.org> 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 <jeffy.chen-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
> ---
>
> 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 | 180 ++++++++++++++++++++++++++++++++---------
> 1 file changed, 141 insertions(+), 39 deletions(-)
>
> diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c
> index 2c095f96c033..e2e7acc3039d 100644
> --- a/drivers/iommu/rockchip-iommu.c
> +++ b/drivers/iommu/rockchip-iommu.c
> @@ -22,6 +22,7 @@
> #include <linux/of_iommu.h>
> #include <linux/of_platform.h>
> #include <linux/platform_device.h>
> +#include <linux/pm_runtime.h>
> #include <linux/slab.h>
> #include <linux/spinlock.h>
>
> @@ -99,6 +100,7 @@ struct rk_iommu {
> };
>
> struct rk_iommudata {
> + struct device_link *link; /* runtime PM link from IOMMU to master */
> struct rk_iommu *iommu;
> };
>
> @@ -583,7 +585,11 @@ 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;
> +
> + err = pm_runtime_get_if_in_use(iommu->dev);
> + if (err <= 0 && err != -EINVAL)
> + return ret;
>
> WARN_ON(rk_iommu_enable_clocks(iommu));
>
> @@ -635,6 +641,9 @@ static irqreturn_t rk_iommu_irq(int irq, void *dev_id)
>
> rk_iommu_disable_clocks(iommu);
>
> + if (pm_runtime_enabled(iommu->dev))
> + pm_runtime_put(iommu->dev);
I think this might be racy. There are some places where
pm_runtime_enable/disable() are called on devices implicitly and I'm
not sure if we're guaranteed that they don't happen between our
pm_runtime_get_if_in_use() and pm_runtime_enabled() calls.
An example of a race-free solution would be to save the
pm_runtime_get_if_in_use() result to a local variable (e.g. bool
need_runtime_put) and then call pm_runtime_put() based on that.
> +
> return ret;
> }
>
> @@ -676,10 +685,20 @@ static void rk_iommu_zap_iova(struct rk_iommu_domain *rk_domain,
> spin_lock_irqsave(&rk_domain->iommus_lock, flags);
> list_for_each(pos, &rk_domain->iommus) {
> struct rk_iommu *iommu;
> + int ret;
> +
> iommu = list_entry(pos, struct rk_iommu, node);
> - rk_iommu_enable_clocks(iommu);
> - rk_iommu_zap_lines(iommu, iova, size);
> - rk_iommu_disable_clocks(iommu);
> +
> + /* Only zap TLBs of IOMMUs that are powered on. */
> + ret = pm_runtime_get_if_in_use(iommu->dev);
> + if (ret > 0 || ret == -EINVAL) {
> + rk_iommu_enable_clocks(iommu);
> + rk_iommu_zap_lines(iommu, iova, size);
> + rk_iommu_disable_clocks(iommu);
> + }
> +
> + if (ret > 0)
> + pm_runtime_put(iommu->dev);
This one nicely avoids the race I mentioned above. :)
> }
> spin_unlock_irqrestore(&rk_domain->iommus_lock, flags);
> }
> @@ -882,22 +901,30 @@ static struct rk_iommu *rk_iommu_from_dev(struct device *dev)
> return data ? data->iommu : NULL;
> }
>
[snip]
> + spin_lock_irqsave(&rk_domain->iommus_lock, flags);
> + list_add_tail(&iommu->node, &rk_domain->iommus);
> + spin_unlock_irqrestore(&rk_domain->iommus_lock, flags);
>
> - dev_dbg(dev, "Detached from iommu domain\n");
> + ret = pm_runtime_get_if_in_use(iommu->dev);
> + if (ret <= 0 && ret != -EINVAL)
> + return 0;
> +
> + ret = rk_iommu_startup(iommu);
> + if (ret)
> + rk_iommu_detach_device(iommu->domain, dev);
> +
> + if (pm_runtime_enabled(iommu->dev))
> + pm_runtime_put(iommu->dev);
Here we should also probably act based on what
pm_runtime_get_if_in_use() returned rather than asking
pm_runtime_enabled().
Best regards,
Tomasz
^ permalink raw reply [flat|nested] 101+ messages in thread* Re: [PATCH v4 12/13] iommu/rockchip: Add runtime PM support
@ 2018-01-19 4:01 ` Tomasz Figa
0 siblings, 0 replies; 101+ messages in thread
From: Tomasz Figa @ 2018-01-19 4:01 UTC (permalink / raw)
To: Jeffy Chen
Cc: linux-kernel, Ricky Liang, Robin Murphy, simon xue,
Heiko Stuebner, open list:ARM/Rockchip SoC...,
open list:IOMMU DRIVERS, Joerg Roedel,
list@263.net:IOMMU DRIVERS <iommu@lists.linux-foundation.org>, Joerg Roedel <joro@8bytes.org>,
On Thu, Jan 18, 2018 at 8:52 PM, Jeffy Chen <jeffy.chen@rock-chips.com> 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 <jeffy.chen@rock-chips.com>
> ---
>
> 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 | 180 ++++++++++++++++++++++++++++++++---------
> 1 file changed, 141 insertions(+), 39 deletions(-)
>
> diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c
> index 2c095f96c033..e2e7acc3039d 100644
> --- a/drivers/iommu/rockchip-iommu.c
> +++ b/drivers/iommu/rockchip-iommu.c
> @@ -22,6 +22,7 @@
> #include <linux/of_iommu.h>
> #include <linux/of_platform.h>
> #include <linux/platform_device.h>
> +#include <linux/pm_runtime.h>
> #include <linux/slab.h>
> #include <linux/spinlock.h>
>
> @@ -99,6 +100,7 @@ struct rk_iommu {
> };
>
> struct rk_iommudata {
> + struct device_link *link; /* runtime PM link from IOMMU to master */
> struct rk_iommu *iommu;
> };
>
> @@ -583,7 +585,11 @@ 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;
> +
> + err = pm_runtime_get_if_in_use(iommu->dev);
> + if (err <= 0 && err != -EINVAL)
> + return ret;
>
> WARN_ON(rk_iommu_enable_clocks(iommu));
>
> @@ -635,6 +641,9 @@ static irqreturn_t rk_iommu_irq(int irq, void *dev_id)
>
> rk_iommu_disable_clocks(iommu);
>
> + if (pm_runtime_enabled(iommu->dev))
> + pm_runtime_put(iommu->dev);
I think this might be racy. There are some places where
pm_runtime_enable/disable() are called on devices implicitly and I'm
not sure if we're guaranteed that they don't happen between our
pm_runtime_get_if_in_use() and pm_runtime_enabled() calls.
An example of a race-free solution would be to save the
pm_runtime_get_if_in_use() result to a local variable (e.g. bool
need_runtime_put) and then call pm_runtime_put() based on that.
> +
> return ret;
> }
>
> @@ -676,10 +685,20 @@ static void rk_iommu_zap_iova(struct rk_iommu_domain *rk_domain,
> spin_lock_irqsave(&rk_domain->iommus_lock, flags);
> list_for_each(pos, &rk_domain->iommus) {
> struct rk_iommu *iommu;
> + int ret;
> +
> iommu = list_entry(pos, struct rk_iommu, node);
> - rk_iommu_enable_clocks(iommu);
> - rk_iommu_zap_lines(iommu, iova, size);
> - rk_iommu_disable_clocks(iommu);
> +
> + /* Only zap TLBs of IOMMUs that are powered on. */
> + ret = pm_runtime_get_if_in_use(iommu->dev);
> + if (ret > 0 || ret == -EINVAL) {
> + rk_iommu_enable_clocks(iommu);
> + rk_iommu_zap_lines(iommu, iova, size);
> + rk_iommu_disable_clocks(iommu);
> + }
> +
> + if (ret > 0)
> + pm_runtime_put(iommu->dev);
This one nicely avoids the race I mentioned above. :)
> }
> spin_unlock_irqrestore(&rk_domain->iommus_lock, flags);
> }
> @@ -882,22 +901,30 @@ static struct rk_iommu *rk_iommu_from_dev(struct device *dev)
> return data ? data->iommu : NULL;
> }
>
[snip]
> + spin_lock_irqsave(&rk_domain->iommus_lock, flags);
> + list_add_tail(&iommu->node, &rk_domain->iommus);
> + spin_unlock_irqrestore(&rk_domain->iommus_lock, flags);
>
> - dev_dbg(dev, "Detached from iommu domain\n");
> + ret = pm_runtime_get_if_in_use(iommu->dev);
> + if (ret <= 0 && ret != -EINVAL)
> + return 0;
> +
> + ret = rk_iommu_startup(iommu);
> + if (ret)
> + rk_iommu_detach_device(iommu->domain, dev);
> +
> + if (pm_runtime_enabled(iommu->dev))
> + pm_runtime_put(iommu->dev);
Here we should also probably act based on what
pm_runtime_get_if_in_use() returned rather than asking
pm_runtime_enabled().
Best regards,
Tomasz
^ permalink raw reply [flat|nested] 101+ messages in thread* [PATCH v4 12/13] iommu/rockchip: Add runtime PM support
@ 2018-01-19 4:01 ` Tomasz Figa
0 siblings, 0 replies; 101+ messages in thread
From: Tomasz Figa @ 2018-01-19 4:01 UTC (permalink / raw)
To: linux-arm-kernel
On Thu, Jan 18, 2018 at 8:52 PM, Jeffy Chen <jeffy.chen@rock-chips.com> 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 <jeffy.chen@rock-chips.com>
> ---
>
> 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 | 180 ++++++++++++++++++++++++++++++++---------
> 1 file changed, 141 insertions(+), 39 deletions(-)
>
> diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c
> index 2c095f96c033..e2e7acc3039d 100644
> --- a/drivers/iommu/rockchip-iommu.c
> +++ b/drivers/iommu/rockchip-iommu.c
> @@ -22,6 +22,7 @@
> #include <linux/of_iommu.h>
> #include <linux/of_platform.h>
> #include <linux/platform_device.h>
> +#include <linux/pm_runtime.h>
> #include <linux/slab.h>
> #include <linux/spinlock.h>
>
> @@ -99,6 +100,7 @@ struct rk_iommu {
> };
>
> struct rk_iommudata {
> + struct device_link *link; /* runtime PM link from IOMMU to master */
> struct rk_iommu *iommu;
> };
>
> @@ -583,7 +585,11 @@ 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;
> +
> + err = pm_runtime_get_if_in_use(iommu->dev);
> + if (err <= 0 && err != -EINVAL)
> + return ret;
>
> WARN_ON(rk_iommu_enable_clocks(iommu));
>
> @@ -635,6 +641,9 @@ static irqreturn_t rk_iommu_irq(int irq, void *dev_id)
>
> rk_iommu_disable_clocks(iommu);
>
> + if (pm_runtime_enabled(iommu->dev))
> + pm_runtime_put(iommu->dev);
I think this might be racy. There are some places where
pm_runtime_enable/disable() are called on devices implicitly and I'm
not sure if we're guaranteed that they don't happen between our
pm_runtime_get_if_in_use() and pm_runtime_enabled() calls.
An example of a race-free solution would be to save the
pm_runtime_get_if_in_use() result to a local variable (e.g. bool
need_runtime_put) and then call pm_runtime_put() based on that.
> +
> return ret;
> }
>
> @@ -676,10 +685,20 @@ static void rk_iommu_zap_iova(struct rk_iommu_domain *rk_domain,
> spin_lock_irqsave(&rk_domain->iommus_lock, flags);
> list_for_each(pos, &rk_domain->iommus) {
> struct rk_iommu *iommu;
> + int ret;
> +
> iommu = list_entry(pos, struct rk_iommu, node);
> - rk_iommu_enable_clocks(iommu);
> - rk_iommu_zap_lines(iommu, iova, size);
> - rk_iommu_disable_clocks(iommu);
> +
> + /* Only zap TLBs of IOMMUs that are powered on. */
> + ret = pm_runtime_get_if_in_use(iommu->dev);
> + if (ret > 0 || ret == -EINVAL) {
> + rk_iommu_enable_clocks(iommu);
> + rk_iommu_zap_lines(iommu, iova, size);
> + rk_iommu_disable_clocks(iommu);
> + }
> +
> + if (ret > 0)
> + pm_runtime_put(iommu->dev);
This one nicely avoids the race I mentioned above. :)
> }
> spin_unlock_irqrestore(&rk_domain->iommus_lock, flags);
> }
> @@ -882,22 +901,30 @@ static struct rk_iommu *rk_iommu_from_dev(struct device *dev)
> return data ? data->iommu : NULL;
> }
>
[snip]
> + spin_lock_irqsave(&rk_domain->iommus_lock, flags);
> + list_add_tail(&iommu->node, &rk_domain->iommus);
> + spin_unlock_irqrestore(&rk_domain->iommus_lock, flags);
>
> - dev_dbg(dev, "Detached from iommu domain\n");
> + ret = pm_runtime_get_if_in_use(iommu->dev);
> + if (ret <= 0 && ret != -EINVAL)
> + return 0;
> +
> + ret = rk_iommu_startup(iommu);
> + if (ret)
> + rk_iommu_detach_device(iommu->domain, dev);
> +
> + if (pm_runtime_enabled(iommu->dev))
> + pm_runtime_put(iommu->dev);
Here we should also probably act based on what
pm_runtime_get_if_in_use() returned rather than asking
pm_runtime_enabled().
Best regards,
Tomasz
^ permalink raw reply [flat|nested] 101+ messages in thread