* [PATCH 07/12] exynos-gsc: Make system PM callbacks available for CONFIG_PM_SLEEP
From: Marek Szyprowski @ 2016-11-09 14:23 UTC (permalink / raw)
To: linux-media, linux-samsung-soc
Cc: Marek Szyprowski, Sylwester Nawrocki, Krzysztof Kozlowski,
Ulf Hansson, Bartlomiej Zolnierkiewicz, Javier Martinez Canillas
In-Reply-To: <1478701441-29107-1-git-send-email-m.szyprowski@samsung.com>
From: Ulf Hansson <ulf.hansson@linaro.org>
There are no need to set up the system PM callbacks unless they are
being used. It also causes compiler warnings about unused functions.
Silence the warnings by making them available for CONFIG_PM_SLEEP.
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
[mszyprow: rebased onto v4.9-rc4]
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
---
drivers/media/platform/exynos-gsc/gsc-core.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/drivers/media/platform/exynos-gsc/gsc-core.c b/drivers/media/platform/exynos-gsc/gsc-core.c
index 9ba1619..af6502c 100644
--- a/drivers/media/platform/exynos-gsc/gsc-core.c
+++ b/drivers/media/platform/exynos-gsc/gsc-core.c
@@ -1166,6 +1166,7 @@ static int gsc_runtime_suspend(struct device *dev)
}
#endif
+#ifdef CONFIG_PM_SLEEP
static int gsc_resume(struct device *dev)
{
struct gsc_dev *gsc = dev_get_drvdata(dev);
@@ -1202,10 +1203,10 @@ static int gsc_suspend(struct device *dev)
return 0;
}
+#endif
static const struct dev_pm_ops gsc_pm_ops = {
- .suspend = gsc_suspend,
- .resume = gsc_resume,
+ SET_SYSTEM_SLEEP_PM_OPS(gsc_suspend, gsc_resume)
SET_RUNTIME_PM_OPS(gsc_runtime_suspend, gsc_runtime_resume, NULL)
};
--
1.9.1
^ permalink raw reply related
* [PATCH 11/12] exynos-gsc: Add missing newline char in debug messages
From: Marek Szyprowski @ 2016-11-09 14:24 UTC (permalink / raw)
To: linux-media, linux-samsung-soc
Cc: Marek Szyprowski, Sylwester Nawrocki, Krzysztof Kozlowski,
Ulf Hansson, Bartlomiej Zolnierkiewicz, Javier Martinez Canillas
In-Reply-To: <1478701441-29107-1-git-send-email-m.szyprowski@samsung.com>
Fix missing newline char in debug messages.
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
---
drivers/media/platform/exynos-gsc/gsc-core.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/media/platform/exynos-gsc/gsc-core.c b/drivers/media/platform/exynos-gsc/gsc-core.c
index ff35909..ac4c96c 100644
--- a/drivers/media/platform/exynos-gsc/gsc-core.c
+++ b/drivers/media/platform/exynos-gsc/gsc-core.c
@@ -1138,7 +1138,7 @@ static int gsc_runtime_resume(struct device *dev)
struct gsc_dev *gsc = dev_get_drvdata(dev);
int ret = 0;
- pr_debug("gsc%d: state: 0x%lx", gsc->id, gsc->state);
+ pr_debug("gsc%d: state: 0x%lx\n", gsc->id, gsc->state);
ret = clk_prepare_enable(gsc->clock);
if (ret)
@@ -1160,7 +1160,7 @@ static int gsc_runtime_suspend(struct device *dev)
if (!ret)
clk_disable_unprepare(gsc->clock);
- pr_debug("gsc%d: state: 0x%lx", gsc->id, gsc->state);
+ pr_debug("gsc%d: state: 0x%lx\n", gsc->id, gsc->state);
return ret;
}
#endif
--
1.9.1
^ permalink raw reply related
* [PATCH 08/12] exynos-gsc: Simplify system PM
From: Marek Szyprowski @ 2016-11-09 14:23 UTC (permalink / raw)
To: linux-media, linux-samsung-soc
Cc: Marek Szyprowski, Sylwester Nawrocki, Krzysztof Kozlowski,
Ulf Hansson, Bartlomiej Zolnierkiewicz, Javier Martinez Canillas
In-Reply-To: <1478701441-29107-1-git-send-email-m.szyprowski@samsung.com>
From: Ulf Hansson <ulf.hansson@linaro.org>
It's not needed to keep a local flag about the current system PM state.
Let's just remove that code and the corresponding debug print.
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
[mszyprow: rebased onto v4.9-rc4]
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
---
drivers/media/platform/exynos-gsc/gsc-core.c | 21 ---------------------
drivers/media/platform/exynos-gsc/gsc-core.h | 3 ---
2 files changed, 24 deletions(-)
diff --git a/drivers/media/platform/exynos-gsc/gsc-core.c b/drivers/media/platform/exynos-gsc/gsc-core.c
index af6502c..4859727 100644
--- a/drivers/media/platform/exynos-gsc/gsc-core.c
+++ b/drivers/media/platform/exynos-gsc/gsc-core.c
@@ -1169,20 +1169,6 @@ static int gsc_runtime_suspend(struct device *dev)
#ifdef CONFIG_PM_SLEEP
static int gsc_resume(struct device *dev)
{
- struct gsc_dev *gsc = dev_get_drvdata(dev);
- unsigned long flags;
-
- pr_debug("gsc%d: state: 0x%lx", gsc->id, gsc->state);
-
- /* Do not resume if the device was idle before system suspend */
- spin_lock_irqsave(&gsc->slock, flags);
- if (!test_and_clear_bit(ST_SUSPEND, &gsc->state) ||
- !gsc_m2m_opened(gsc)) {
- spin_unlock_irqrestore(&gsc->slock, flags);
- return 0;
- }
- spin_unlock_irqrestore(&gsc->slock, flags);
-
if (!pm_runtime_suspended(dev))
return gsc_runtime_resume(dev);
@@ -1191,13 +1177,6 @@ static int gsc_resume(struct device *dev)
static int gsc_suspend(struct device *dev)
{
- struct gsc_dev *gsc = dev_get_drvdata(dev);
-
- pr_debug("gsc%d: state: 0x%lx", gsc->id, gsc->state);
-
- if (test_and_set_bit(ST_SUSPEND, &gsc->state))
- return 0;
-
if (!pm_runtime_suspended(dev))
return gsc_runtime_suspend(dev);
diff --git a/drivers/media/platform/exynos-gsc/gsc-core.h b/drivers/media/platform/exynos-gsc/gsc-core.h
index 7ad7b9d..8480aec 100644
--- a/drivers/media/platform/exynos-gsc/gsc-core.h
+++ b/drivers/media/platform/exynos-gsc/gsc-core.h
@@ -48,9 +48,6 @@
#define GSC_CTX_ABORT (1 << 7)
enum gsc_dev_flags {
- /* for global */
- ST_SUSPEND,
-
/* for m2m node */
ST_M2M_OPEN,
ST_M2M_RUN,
--
1.9.1
^ permalink raw reply related
* [PATCH 06/12] exynos-gsc: Do full clock gating at runtime PM suspend
From: Marek Szyprowski @ 2016-11-09 14:23 UTC (permalink / raw)
To: linux-media, linux-samsung-soc
Cc: Marek Szyprowski, Sylwester Nawrocki, Krzysztof Kozlowski,
Ulf Hansson, Bartlomiej Zolnierkiewicz, Javier Martinez Canillas
In-Reply-To: <1478701441-29107-1-git-send-email-m.szyprowski@samsung.com>
From: Ulf Hansson <ulf.hansson@linaro.org>
To potentially save more power in runtime PM suspend state, let's also
prepare/unprepare the clock from the runtime PM callbacks.
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
[mszyprow: rebased onto v4.9-rc4]
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
---
drivers/media/platform/exynos-gsc/gsc-core.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/media/platform/exynos-gsc/gsc-core.c b/drivers/media/platform/exynos-gsc/gsc-core.c
index 1d3bde3..9ba1619 100644
--- a/drivers/media/platform/exynos-gsc/gsc-core.c
+++ b/drivers/media/platform/exynos-gsc/gsc-core.c
@@ -1141,7 +1141,7 @@ static int gsc_runtime_resume(struct device *dev)
pr_debug("gsc%d: state: 0x%lx", gsc->id, gsc->state);
- ret = clk_enable(gsc->clock);
+ ret = clk_prepare_enable(gsc->clock);
if (ret)
return ret;
@@ -1159,7 +1159,7 @@ static int gsc_runtime_suspend(struct device *dev)
ret = gsc_m2m_suspend(gsc);
if (!ret)
- clk_disable(gsc->clock);
+ clk_disable_unprepare(gsc->clock);
pr_debug("gsc%d: state: 0x%lx", gsc->id, gsc->state);
return ret;
--
1.9.1
^ permalink raw reply related
* [PATCH 09/12] exynos-gsc: Simplify system PM even more
From: Marek Szyprowski @ 2016-11-09 14:23 UTC (permalink / raw)
To: linux-media, linux-samsung-soc
Cc: Marek Szyprowski, Sylwester Nawrocki, Krzysztof Kozlowski,
Ulf Hansson, Bartlomiej Zolnierkiewicz, Javier Martinez Canillas
In-Reply-To: <1478701441-29107-1-git-send-email-m.szyprowski@samsung.com>
System pm callbacks only ensures that device is runtime suspended/resumed,
so remove them and use generic pm_runtime_force_suspend/resume helper.
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
---
drivers/media/platform/exynos-gsc/gsc-core.c | 21 ++-------------------
1 file changed, 2 insertions(+), 19 deletions(-)
diff --git a/drivers/media/platform/exynos-gsc/gsc-core.c b/drivers/media/platform/exynos-gsc/gsc-core.c
index 4859727..1e8b216 100644
--- a/drivers/media/platform/exynos-gsc/gsc-core.c
+++ b/drivers/media/platform/exynos-gsc/gsc-core.c
@@ -1166,26 +1166,9 @@ static int gsc_runtime_suspend(struct device *dev)
}
#endif
-#ifdef CONFIG_PM_SLEEP
-static int gsc_resume(struct device *dev)
-{
- if (!pm_runtime_suspended(dev))
- return gsc_runtime_resume(dev);
-
- return 0;
-}
-
-static int gsc_suspend(struct device *dev)
-{
- if (!pm_runtime_suspended(dev))
- return gsc_runtime_suspend(dev);
-
- return 0;
-}
-#endif
-
static const struct dev_pm_ops gsc_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(gsc_suspend, gsc_resume)
+ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+ pm_runtime_force_resume)
SET_RUNTIME_PM_OPS(gsc_runtime_suspend, gsc_runtime_resume, NULL)
};
--
1.9.1
^ permalink raw reply related
* [PATCH 01/12] exynos-gsc: Simplify clock management
From: Marek Szyprowski @ 2016-11-09 14:23 UTC (permalink / raw)
To: linux-media, linux-samsung-soc
Cc: Marek Szyprowski, Sylwester Nawrocki, Krzysztof Kozlowski,
Ulf Hansson, Bartlomiej Zolnierkiewicz, Javier Martinez Canillas
In-Reply-To: <1478701441-29107-1-git-send-email-m.szyprowski@samsung.com>
From: Ulf Hansson <ulf.hansson@linaro.org>
Instead of having separate functions that fecthes, prepares and
unprepares the clock, let's encapsulate this code into ->probe().
This makes error handling easier and decreases the lines of code.
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
[mszyprow: rebased onto v4.9-rc4]
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
---
drivers/media/platform/exynos-gsc/gsc-core.c | 49 ++++++++--------------------
1 file changed, 14 insertions(+), 35 deletions(-)
diff --git a/drivers/media/platform/exynos-gsc/gsc-core.c b/drivers/media/platform/exynos-gsc/gsc-core.c
index 787bd16..abebbdb 100644
--- a/drivers/media/platform/exynos-gsc/gsc-core.c
+++ b/drivers/media/platform/exynos-gsc/gsc-core.c
@@ -988,36 +988,6 @@ static void *gsc_get_drv_data(struct platform_device *pdev)
return driver_data;
}
-static void gsc_clk_put(struct gsc_dev *gsc)
-{
- if (!IS_ERR(gsc->clock))
- clk_unprepare(gsc->clock);
-}
-
-static int gsc_clk_get(struct gsc_dev *gsc)
-{
- int ret;
-
- dev_dbg(&gsc->pdev->dev, "gsc_clk_get Called\n");
-
- gsc->clock = devm_clk_get(&gsc->pdev->dev, GSC_CLOCK_GATE_NAME);
- if (IS_ERR(gsc->clock)) {
- dev_err(&gsc->pdev->dev, "failed to get clock~~~: %s\n",
- GSC_CLOCK_GATE_NAME);
- return PTR_ERR(gsc->clock);
- }
-
- ret = clk_prepare(gsc->clock);
- if (ret < 0) {
- dev_err(&gsc->pdev->dev, "clock prepare failed for clock: %s\n",
- GSC_CLOCK_GATE_NAME);
- gsc->clock = ERR_PTR(-EINVAL);
- return ret;
- }
-
- return 0;
-}
-
static int gsc_m2m_suspend(struct gsc_dev *gsc)
{
unsigned long flags;
@@ -1085,7 +1055,6 @@ static int gsc_probe(struct platform_device *pdev)
init_waitqueue_head(&gsc->irq_queue);
spin_lock_init(&gsc->slock);
mutex_init(&gsc->lock);
- gsc->clock = ERR_PTR(-EINVAL);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
gsc->regs = devm_ioremap_resource(dev, res);
@@ -1098,9 +1067,19 @@ static int gsc_probe(struct platform_device *pdev)
return -ENXIO;
}
- ret = gsc_clk_get(gsc);
- if (ret)
+ gsc->clock = devm_clk_get(dev, GSC_CLOCK_GATE_NAME);
+ if (IS_ERR(gsc->clock)) {
+ dev_err(dev, "failed to get clock~~~: %s\n",
+ GSC_CLOCK_GATE_NAME);
+ return PTR_ERR(gsc->clock);
+ }
+
+ ret = clk_prepare(gsc->clock);
+ if (ret) {
+ dev_err(&gsc->pdev->dev, "clock prepare failed for clock: %s\n",
+ GSC_CLOCK_GATE_NAME);
return ret;
+ }
ret = devm_request_irq(dev, res->start, gsc_irq_handler,
0, pdev->name, gsc);
@@ -1135,7 +1114,7 @@ static int gsc_probe(struct platform_device *pdev)
err_v4l2:
v4l2_device_unregister(&gsc->v4l2_dev);
err_clk:
- gsc_clk_put(gsc);
+ clk_unprepare(gsc->clock);
return ret;
}
@@ -1148,7 +1127,7 @@ static int gsc_remove(struct platform_device *pdev)
vb2_dma_contig_clear_max_seg_size(&pdev->dev);
pm_runtime_disable(&pdev->dev);
- gsc_clk_put(gsc);
+ clk_unprepare(gsc->clock);
dev_dbg(&pdev->dev, "%s driver unloaded\n", pdev->name);
return 0;
--
1.9.1
^ permalink raw reply related
* [PATCH 05/12] exynos-gsc: Fixup clock management at ->remove()
From: Marek Szyprowski @ 2016-11-09 14:23 UTC (permalink / raw)
To: linux-media, linux-samsung-soc
Cc: Marek Szyprowski, Sylwester Nawrocki, Krzysztof Kozlowski,
Ulf Hansson, Bartlomiej Zolnierkiewicz, Javier Martinez Canillas
In-Reply-To: <1478701441-29107-1-git-send-email-m.szyprowski@samsung.com>
From: Ulf Hansson <ulf.hansson@linaro.org>
To make sure the clock is fully gated in ->remove(), we first need to
to bring the device into full power by invoking pm_runtime_get_sync().
Then, let's both unprepare and disable the clock.
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
[mszyprow: rebased onto v4.9-rc4]
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
---
drivers/media/platform/exynos-gsc/gsc-core.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/drivers/media/platform/exynos-gsc/gsc-core.c b/drivers/media/platform/exynos-gsc/gsc-core.c
index 7e99fda..1d3bde3 100644
--- a/drivers/media/platform/exynos-gsc/gsc-core.c
+++ b/drivers/media/platform/exynos-gsc/gsc-core.c
@@ -1082,12 +1082,15 @@ static int gsc_remove(struct platform_device *pdev)
{
struct gsc_dev *gsc = platform_get_drvdata(pdev);
+ pm_runtime_get_sync(&pdev->dev);
+
gsc_unregister_m2m_device(gsc);
v4l2_device_unregister(&gsc->v4l2_dev);
vb2_dma_contig_clear_max_seg_size(&pdev->dev);
- pm_runtime_disable(&pdev->dev);
- clk_unprepare(gsc->clock);
+ clk_disable_unprepare(gsc->clock);
+
+ pm_runtime_put_noidle(&pdev->dev);
dev_dbg(&pdev->dev, "%s driver unloaded\n", pdev->name);
return 0;
--
1.9.1
^ permalink raw reply related
* [PATCH 04/12] exynos-gsc: Make runtime PM callbacks available for CONFIG_PM
From: Marek Szyprowski @ 2016-11-09 14:23 UTC (permalink / raw)
To: linux-media, linux-samsung-soc
Cc: Marek Szyprowski, Sylwester Nawrocki, Krzysztof Kozlowski,
Ulf Hansson, Bartlomiej Zolnierkiewicz, Javier Martinez Canillas
In-Reply-To: <1478701441-29107-1-git-send-email-m.szyprowski@samsung.com>
From: Ulf Hansson <ulf.hansson@linaro.org>
There are no need to set up the runtime PM callbacks unless they are
being used. It also causes compiler warnings about unused functions.
Silence the warnings by making them available for CONFIG_PM.
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
[mszyprow: rebased onto v4.9-rc4]
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
---
drivers/media/platform/exynos-gsc/gsc-core.c | 79 ++++++++++++++--------------
1 file changed, 40 insertions(+), 39 deletions(-)
diff --git a/drivers/media/platform/exynos-gsc/gsc-core.c b/drivers/media/platform/exynos-gsc/gsc-core.c
index b5a99af..7e99fda 100644
--- a/drivers/media/platform/exynos-gsc/gsc-core.c
+++ b/drivers/media/platform/exynos-gsc/gsc-core.c
@@ -988,43 +988,6 @@ static void *gsc_get_drv_data(struct platform_device *pdev)
return driver_data;
}
-static int gsc_m2m_suspend(struct gsc_dev *gsc)
-{
- unsigned long flags;
- int timeout;
-
- spin_lock_irqsave(&gsc->slock, flags);
- if (!gsc_m2m_pending(gsc)) {
- spin_unlock_irqrestore(&gsc->slock, flags);
- return 0;
- }
- clear_bit(ST_M2M_SUSPENDED, &gsc->state);
- set_bit(ST_M2M_SUSPENDING, &gsc->state);
- spin_unlock_irqrestore(&gsc->slock, flags);
-
- timeout = wait_event_timeout(gsc->irq_queue,
- test_bit(ST_M2M_SUSPENDED, &gsc->state),
- GSC_SHUTDOWN_TIMEOUT);
-
- clear_bit(ST_M2M_SUSPENDING, &gsc->state);
- return timeout == 0 ? -EAGAIN : 0;
-}
-
-static void gsc_m2m_resume(struct gsc_dev *gsc)
-{
- struct gsc_ctx *ctx;
- unsigned long flags;
-
- spin_lock_irqsave(&gsc->slock, flags);
- /* Clear for full H/W setup in first run after resume */
- ctx = gsc->m2m.ctx;
- gsc->m2m.ctx = NULL;
- spin_unlock_irqrestore(&gsc->slock, flags);
-
- if (test_and_clear_bit(ST_M2M_SUSPENDED, &gsc->state))
- gsc_m2m_job_finish(ctx, VB2_BUF_STATE_ERROR);
-}
-
static int gsc_probe(struct platform_device *pdev)
{
struct gsc_dev *gsc;
@@ -1130,6 +1093,44 @@ static int gsc_remove(struct platform_device *pdev)
return 0;
}
+#ifdef CONFIG_PM
+static int gsc_m2m_suspend(struct gsc_dev *gsc)
+{
+ unsigned long flags;
+ int timeout;
+
+ spin_lock_irqsave(&gsc->slock, flags);
+ if (!gsc_m2m_pending(gsc)) {
+ spin_unlock_irqrestore(&gsc->slock, flags);
+ return 0;
+ }
+ clear_bit(ST_M2M_SUSPENDED, &gsc->state);
+ set_bit(ST_M2M_SUSPENDING, &gsc->state);
+ spin_unlock_irqrestore(&gsc->slock, flags);
+
+ timeout = wait_event_timeout(gsc->irq_queue,
+ test_bit(ST_M2M_SUSPENDED, &gsc->state),
+ GSC_SHUTDOWN_TIMEOUT);
+
+ clear_bit(ST_M2M_SUSPENDING, &gsc->state);
+ return timeout == 0 ? -EAGAIN : 0;
+}
+
+static void gsc_m2m_resume(struct gsc_dev *gsc)
+{
+ struct gsc_ctx *ctx;
+ unsigned long flags;
+
+ spin_lock_irqsave(&gsc->slock, flags);
+ /* Clear for full H/W setup in first run after resume */
+ ctx = gsc->m2m.ctx;
+ gsc->m2m.ctx = NULL;
+ spin_unlock_irqrestore(&gsc->slock, flags);
+
+ if (test_and_clear_bit(ST_M2M_SUSPENDED, &gsc->state))
+ gsc_m2m_job_finish(ctx, VB2_BUF_STATE_ERROR);
+}
+
static int gsc_runtime_resume(struct device *dev)
{
struct gsc_dev *gsc = dev_get_drvdata(dev);
@@ -1160,6 +1161,7 @@ static int gsc_runtime_suspend(struct device *dev)
pr_debug("gsc%d: state: 0x%lx", gsc->id, gsc->state);
return ret;
}
+#endif
static int gsc_resume(struct device *dev)
{
@@ -1201,8 +1203,7 @@ static int gsc_suspend(struct device *dev)
static const struct dev_pm_ops gsc_pm_ops = {
.suspend = gsc_suspend,
.resume = gsc_resume,
- .runtime_suspend = gsc_runtime_suspend,
- .runtime_resume = gsc_runtime_resume,
+ SET_RUNTIME_PM_OPS(gsc_runtime_suspend, gsc_runtime_resume, NULL)
};
static struct platform_driver gsc_driver = {
--
1.9.1
^ permalink raw reply related
* [PATCH 03/12] exynos-gsc: Make driver functional when CONFIG_PM is unset
From: Marek Szyprowski @ 2016-11-09 14:23 UTC (permalink / raw)
To: linux-media, linux-samsung-soc
Cc: Marek Szyprowski, Sylwester Nawrocki, Krzysztof Kozlowski,
Ulf Hansson, Bartlomiej Zolnierkiewicz, Javier Martinez Canillas
In-Reply-To: <1478701441-29107-1-git-send-email-m.szyprowski@samsung.com>
From: Ulf Hansson <ulf.hansson@linaro.org>
The driver depended on CONFIG_PM to be functional. Let's remove that
dependency, by enable the runtime PM resourses during ->probe() and
update the device's runtime PM status to reflect this.
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
[mszyprow: rebased onto v4.9-rc4]
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
---
drivers/media/platform/exynos-gsc/gsc-core.c | 17 ++++++++---------
1 file changed, 8 insertions(+), 9 deletions(-)
diff --git a/drivers/media/platform/exynos-gsc/gsc-core.c b/drivers/media/platform/exynos-gsc/gsc-core.c
index cb4e8bd..b5a99af 100644
--- a/drivers/media/platform/exynos-gsc/gsc-core.c
+++ b/drivers/media/platform/exynos-gsc/gsc-core.c
@@ -1072,7 +1072,7 @@ static int gsc_probe(struct platform_device *pdev)
return PTR_ERR(gsc->clock);
}
- ret = clk_prepare(gsc->clock);
+ ret = clk_prepare_enable(gsc->clock);
if (ret) {
dev_err(&gsc->pdev->dev, "clock prepare failed for clock: %s\n",
GSC_CLOCK_GATE_NAME);
@@ -1095,24 +1095,23 @@ static int gsc_probe(struct platform_device *pdev)
goto err_v4l2;
platform_set_drvdata(pdev, gsc);
- pm_runtime_enable(dev);
- ret = pm_runtime_get_sync(&pdev->dev);
- if (ret < 0)
- goto err_m2m;
+
+ gsc_hw_set_sw_reset(gsc);
+ gsc_wait_reset(gsc);
vb2_dma_contig_set_max_seg_size(dev, DMA_BIT_MASK(32));
dev_dbg(dev, "gsc-%d registered successfully\n", gsc->id);
- pm_runtime_put(dev);
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+
return 0;
-err_m2m:
- gsc_unregister_m2m_device(gsc);
err_v4l2:
v4l2_device_unregister(&gsc->v4l2_dev);
err_clk:
- clk_unprepare(gsc->clock);
+ clk_disable_unprepare(gsc->clock);
return ret;
}
--
1.9.1
^ permalink raw reply related
* [PATCH 02/12] exynos-gsc: Convert gsc_m2m_resume() from int to void
From: Marek Szyprowski @ 2016-11-09 14:23 UTC (permalink / raw)
To: linux-media, linux-samsung-soc
Cc: Marek Szyprowski, Sylwester Nawrocki, Krzysztof Kozlowski,
Ulf Hansson, Bartlomiej Zolnierkiewicz, Javier Martinez Canillas
In-Reply-To: <1478701441-29107-1-git-send-email-m.szyprowski@samsung.com>
From: Ulf Hansson <ulf.hansson@linaro.org>
Since gsc_m2m_resume() always returns 0, convert it to a void instead.
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
[mszyprow: rebased onto v4.9-rc4]
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
---
drivers/media/platform/exynos-gsc/gsc-core.c | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/drivers/media/platform/exynos-gsc/gsc-core.c b/drivers/media/platform/exynos-gsc/gsc-core.c
index abebbdb..cb4e8bd 100644
--- a/drivers/media/platform/exynos-gsc/gsc-core.c
+++ b/drivers/media/platform/exynos-gsc/gsc-core.c
@@ -1010,7 +1010,7 @@ static int gsc_m2m_suspend(struct gsc_dev *gsc)
return timeout == 0 ? -EAGAIN : 0;
}
-static int gsc_m2m_resume(struct gsc_dev *gsc)
+static void gsc_m2m_resume(struct gsc_dev *gsc)
{
struct gsc_ctx *ctx;
unsigned long flags;
@@ -1023,8 +1023,6 @@ static int gsc_m2m_resume(struct gsc_dev *gsc)
if (test_and_clear_bit(ST_M2M_SUSPENDED, &gsc->state))
gsc_m2m_job_finish(ctx, VB2_BUF_STATE_ERROR);
-
- return 0;
}
static int gsc_probe(struct platform_device *pdev)
@@ -1146,8 +1144,9 @@ static int gsc_runtime_resume(struct device *dev)
gsc_hw_set_sw_reset(gsc);
gsc_wait_reset(gsc);
+ gsc_m2m_resume(gsc);
- return gsc_m2m_resume(gsc);
+ return 0;
}
static int gsc_runtime_suspend(struct device *dev)
--
1.9.1
^ permalink raw reply related
* [PATCH 00/12] media: Exynos GScaller driver fixes
From: Marek Szyprowski @ 2016-11-09 14:23 UTC (permalink / raw)
To: linux-media, linux-samsung-soc
Cc: Marek Szyprowski, Sylwester Nawrocki, Krzysztof Kozlowski,
Ulf Hansson, Bartlomiej Zolnierkiewicz, Javier Martinez Canillas
In-Reply-To: <CGME20161109142406eucas1p2c3c158d10fd96d97c57a32ab402acd2e@eucas1p2.samsung.com>
Hi!
This is a collection of various fixes and cleanups for Exynos GScaller
media driver. Most of them comes from the forgotten patchset posted long
time ago by Ulf Hansson:
https://www.mail-archive.com/linux-media@vger.kernel.org/msg80592.html
While testing and rebasing them, I added some more cleanups. Tested on
Exynos5422-based Odroid XU3 board.
Best regards
Marek Szyprowski
Samsung R&D Institute Poland
Patch summary:
Marek Szyprowski (4):
exynos-gsc: Simplify system PM even more
exynos-gsc: Remove unused lclk_freqency entry
exynos-gsc: Add missing newline char in debug messages
exynos-gsc: Use of_device_get_match_data() helper
Ulf Hansson (8):
exynos-gsc: Simplify clock management
exynos-gsc: Convert gsc_m2m_resume() from int to void
exynos-gsc: Make driver functional when CONFIG_PM is unset
exynos-gsc: Make runtime PM callbacks available for CONFIG_PM
exynos-gsc: Fixup clock management at ->remove()
exynos-gsc: Do full clock gating at runtime PM suspend
exynos-gsc: Make system PM callbacks available for CONFIG_PM_SLEEP
exynos-gsc: Simplify system PM
drivers/media/platform/exynos-gsc/gsc-core.c | 214 +++++++++------------------
drivers/media/platform/exynos-gsc/gsc-core.h | 5 -
2 files changed, 73 insertions(+), 146 deletions(-)
--
1.9.1
^ permalink raw reply
* Re: [PATCH 0/2] extend page_track for external usage
From: Paolo Bonzini @ 2016-11-09 14:23 UTC (permalink / raw)
To: Zhenyu Wang, Daniel Vetter
Cc: Jike Song, rkrcmar, kvm, Jani Nikula, Alex Williamson, intel-gfx
In-Reply-To: <20161109020317.i7ntebpkq6cxwfea@zhen-hp.sh.intel.com>
[-- Attachment #1.1: Type: text/plain, Size: 1798 bytes --]
On 09/11/2016 03:03, Zhenyu Wang wrote:
> On 2016.11.07 10:17:54 +0100, Daniel Vetter wrote:
>>>> Paolo, for this case, do you think it's feasible we pick them through
>>>> drm/i915 merge path? As currently initial KVMGT patch sets require these
>>>> exported symbols, that's why I ask how we should handle this dependency.
>>>
>>> Then it's actually a good thing that I dropped from kvm/queue! You can
>>> certainly include these patches, but please do that through a topic branch.
>>>
>>> I've prepared a branch for you
>>> (git://git.kernel.org/pub/scm/virt/kvm/kvm.git branch for-kvmgt). Once
>>> Linus processes my outstanding pull request, the branch will only
>>> include the three page-tracking patches. Please pull that topic branch
>>> into your own branch, and ensure you have a merge commit when you send
>>> the pull request to Daniel. The merge commit ensures that the workflow
>>> was correct; use --no-ff if necessary.
>>>
>>> You can do the same for Jike's patches for the KVM-VFIO device, when
>>> Alex reviews them, and I suppose you'll need a topic branch for mdev
>>> too? I didn't know that KVMGT was planned for 4.10. In the future,
>>> let's synchronize ahead so that we can prepare topic branches for you.
>>
>> Ok, back from the useless wifi at plumbers, I can mail again. Zhenyu
>> confirmed on irc that the initial code pile only needs this. For the
>> cross-maintainer topic tree I prefer a formal pull request with stable
>> tag. Please also cc: intel-gfx on that, since I plan to merge that one
>> directly into i915.
>>
>
> Paolo, could you help to do this for Daniel? Daniel would like to merge
> current KVMGT required change for KVM directly, then I'd base KVMGT change
> on that.
Yes, I'll send it today.
Paolo
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 473 bytes --]
^ permalink raw reply
* Re: question: is it a CVE in relinquish_memory()[xen/arch/x86/domain.c]
From: Jan Beulich @ 2016-11-09 14:22 UTC (permalink / raw)
To: Xuquan (Quan Xu)
Cc: Kevin Tian, Liuxiaojian (alex), George.Dunlap@eu.citrix.com,
Andrew Cooper, Tim Deegan, xen-devel@lists.xen.org,
dgdegra@tycho.nsa.gov
In-Reply-To: <E0A769A898ADB6449596C41F51EF62C6AC27B8@SZXEMI506-MBX.china.huawei.com>
>>> On 09.11.16 at 13:01, <xuquan8@huawei.com> wrote:
> Based on CVE-2015-7814 and commit 1ef01396fdff, ' arm: handle races between
> relinquish_memory and free_domheap_pages'..
> relinquish_memory() [xen/arch/arm/domain.c, arm code],
> when couldn't get a reference -- someone is freeing this page and has already
> committed to doing so, so no more to do here, continue.
>
>
> But in relinquish_memory()[xen/arch/x86/domain.c, __x86__ code], when
> couldn't get a reference -- someone is freeing this page,
> Why adding this page to d->arch.relmem_list again.
> Is it a CVE to double free page, then hit the ''" alloc_heap_pages() :
> BUG_ON(pg[i].count_info != PGC_state_free)"" in creating guests later..
Well, considering that you've even quoted the description of the
patch, it should be clear to you that the difference in behavior
between ARM and x86 is intended. Hence I'm having difficulty
seeing what you actually want to point out.
And then, if you again suspect a security issue in the future,
please ask on security@ first, rather than posting publicly (on
xen-devel@ or elsewhere).
Thanks, Jan
_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel
^ permalink raw reply
* Re: [PATCH 22/25] x86/mcheck: Do the init in one place
From: Sebastian Andrzej Siewior @ 2016-11-09 14:22 UTC (permalink / raw)
To: Borislav Petkov
Cc: Luck, Tony, linux-kernel, rt, linux-edac, x86, Thomas Gleixner
In-Reply-To: <20161108092302.wraci5m2cxqozlew@pd.tnic>
On 2016-11-08 10:23:02 [+0100], Borislav Petkov wrote:
> On Mon, Nov 07, 2016 at 09:12:24PM +0100, Borislav Petkov wrote:
> > On Mon, Nov 07, 2016 at 10:55:24AM -0800, Luck, Tony wrote:
> > > I don't think that helps as much as you'd like it to help (at
> > > least on Intel). A broadcast machine check that finds the boot
> > > CPU has set CR4[MCE]=1 is still going to end up in reset if any
> > > other CPU still has CR4[MCE]=0
> >
> > By leaving/moving the setting of CR4 earlier on all cores, we'll
> > at least make the possible window for such potential resets a lot
> > smaller...
>
> ... and in general, I'm still unsure about *why* we need this change for
> hotplug. bigeasy, can you please clarify first?
I want to get rid of non-symmetrical part and the arch hook which should
be part of the hp notifier itself. I wouldn't be too much afraid about
the when point in time when the notifier runs: It is the *first*
notifier that will be invoked on the target CPU. This is only a few
lines after the old hook. Nothing else long delaying should be invoked.
> Thanks.
Sebastian
^ permalink raw reply
* Re: [Qemu-devel] [PATCH] test-replication: fix leaks
From: Stefan Hajnoczi @ 2016-11-09 14:22 UTC (permalink / raw)
To: Marc-André Lureau; +Cc: qemu-devel, xiecl.fnst
In-Reply-To: <20161109104547.23861-1-marcandre.lureau@redhat.com>
[-- Attachment #1: Type: text/plain, Size: 406 bytes --]
On Wed, Nov 09, 2016 at 02:45:47PM +0400, Marc-André Lureau wrote:
> ASAN spotted:
> SUMMARY: AddressSanitizer: 301990288 byte(s) leaked in 33 allocation(s).
>
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
> tests/test-replication.c | 3 +++
> 1 file changed, 3 insertions(+)
Thanks, applied to my block tree:
https://github.com/stefanha/qemu/commits/block
Stefan
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 455 bytes --]
^ permalink raw reply
* [PATCH] fpga zynq: Check the bitstream for validity
From: Mike Looijmans @ 2016-11-09 14:21 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161108000538.GA13959@obsidianresearch.com>
?On 08-11-16 01:05, Jason Gunthorpe wrote:
> On Tue, Nov 01, 2016 at 06:48:42PM +0100, Michal Simek wrote:
>> On 1.11.2016 16:33, Jason Gunthorpe wrote:
>>> On Tue, Nov 01, 2016 at 07:39:22AM +0100, Michal Simek wrote:
>>>
>>>> Regarding BIT and BIN format. This support is in vivado for a long time
>>>> and it is up2you what you want to support. We have removed that BIT
>>>> support and not doing any swap by saying only BIN format is supported.
>>>
>>> BIN is not supported, it needs a swap as well.
>>>
>>> Moritz has it right, you have to use vivado to create a PROM image to be
>>> compatible with the driver.
>>
>> hm than that's bad.
>
> IMHO, Xilinx made an error with Zynq DevC, the DMA does not accept a
> memory image that is output by the usual Xilinx tools. It should have
> accepted a byte swapped input.
>
> I think Moritz is right, the fpgamgr *should not* alter the bitstream
> in any way. This is important for future work to make the DMA do
> gather and avoid the really bad high-order allocation.
>
> So users will have to provide byte swapped .bin files - the vivado
> write_cfgmem command will produce them - this all needs to be
> documented.
>
> Also, I think Punnaiah (?) was telling me that bitstream encryption
> does not work - DevC must be told the bitstream is encrypted.
> That seems like something that needs work at the fpgamgr level - and
> maybe this driver should auto-detect encryption by looking at the
> bitfile (as is typical for Xilinx programming)
>
I think the basic idea behind the commit is flawed to begin with and the patch
should be discarded completely. The same discussion was done for the Xilinx
FPGA manager driver, which resulted in the decision that the tooling should
create a proper file. This driver should either become obsolete or at least
move into the same direction as the FPGA manager rather than away from that.
Besides political arguments, there's a more pressing technical argument
against this theck as well: The whole check is pointless since the hardware
itself already verifies the validity of the stream. Sending bitstreams
intended for other devices has no effect at all. Even sending random data
doesn't have any effect, the hardware will discard it. There's no reason to
waste CPU cycles duplicating this check in software.
Kind regards,
Mike Looijmans
System Expert
TOPIC Products
Materiaalweg 4, NL-5681 RJ Best
Postbus 440, NL-5680 AK Best
Telefoon: +31 (0) 499 33 69 79
E-mail: mike.looijmans at topicproducts.com
Website: www.topicproducts.com
Please consider the environment before printing this e-mail
^ permalink raw reply
* [PATCH v9 0/8] thunderbolt: Introducing Thunderbolt(TM) Networking
From: Amir Levy @ 2016-11-09 14:20 UTC (permalink / raw)
To: gregkh
Cc: andreas.noever, bhelgaas, corbet, linux-kernel, linux-pci, netdev,
linux-doc, mario_limonciello, thunderbolt-linux, mika.westerberg,
tomas.winkler, xiong.y.zhang, Amir Levy
This driver enables Thunderbolt Networking on non-Apple platforms
running Linux.
Thunderbolt Networking provides peer-to-peer connections to transfer
files between computers, perform PC migrations, and/or set up small
workgroups with shared storage.
This is a virtual connection that emulates an Ethernet adapter that
enables Ethernet networking with the benefit of Thunderbolt superfast
medium capability.
Thunderbolt Networking enables two hosts and several devices that
have a Thunderbolt controller to be connected together in a linear
(Daisy chain) series from a single port.
Thunderbolt Networking for Linux is compatible with Thunderbolt
Networking on systems running macOS or Windows and also supports
Thunderbolt generation 2 and 3 controllers.
Note that all pre-existing Thunderbolt generation 3 features, such as
USB, Display and other Thunderbolt device connectivity will continue
to function exactly as they did prior to enabling Thunderbolt Networking.
Code and Software Specifications:
This kernel code creates a virtual ethernet device for computer to
computer communication over a Thunderbolt cable.
The new driver is a separate driver to the existing Thunderbolt driver.
It is designed to work on systems running Linux that
interface with Intel Connection Manager (ICM) firmware based
Thunderbolt controllers that support Thunderbolt Networking.
The kernel code operates in coordination with the Thunderbolt user-
space daemon to implement full Thunderbolt networking functionality.
Hardware Specifications:
Thunderbolt Hardware specs have not yet been published but are used
where necessary for register definitions.
Acked-by: Andreas Noever <andreas.noever@gmail.com>
Tested-by: Mario Limonciello <mario.limonciello@dell.com>
Changes since v8:
- Added support for more Thunderbolt device IDs
These patches were pushed to GitHub where they can be reviewed more
comfortably with green/red highlighting:
https://github.com/01org/thunderbolt-software-kernel-tree
Daemon code:
https://github.com/01org/thunderbolt-software-daemon
For reference, here's a link to version 8:
[v8]: https://lkml.org/lkml/2016/9/28/378
Amir Levy (8):
thunderbolt: Macro rename
thunderbolt: Updating the register definitions
thunderbolt: Communication with the ICM (firmware)
thunderbolt: Networking state machine
thunderbolt: Networking transmit and receive
thunderbolt: Kconfig for Thunderbolt Networking
thunderbolt: Networking doc
thunderbolt: Adding maintainer entry
Documentation/00-INDEX | 2 +
Documentation/thunderbolt/networking.txt | 132 ++
MAINTAINERS | 8 +-
drivers/thunderbolt/Kconfig | 27 +-
drivers/thunderbolt/Makefile | 3 +-
drivers/thunderbolt/icm/Makefile | 2 +
drivers/thunderbolt/icm/icm_nhi.c | 1520 ++++++++++++++++++++
drivers/thunderbolt/icm/icm_nhi.h | 85 ++
drivers/thunderbolt/icm/net.c | 2254 ++++++++++++++++++++++++++++++
drivers/thunderbolt/icm/net.h | 287 ++++
drivers/thunderbolt/nhi_regs.h | 115 +-
11 files changed, 4426 insertions(+), 9 deletions(-)
create mode 100644 Documentation/thunderbolt/networking.txt
create mode 100644 drivers/thunderbolt/icm/Makefile
create mode 100644 drivers/thunderbolt/icm/icm_nhi.c
create mode 100644 drivers/thunderbolt/icm/icm_nhi.h
create mode 100644 drivers/thunderbolt/icm/net.c
create mode 100644 drivers/thunderbolt/icm/net.h
--
2.7.4
^ permalink raw reply
* [PATCH v7 16/16] drivers: acpi: iort: introduce iort_iommu_configure
From: Lorenzo Pieralisi @ 2016-11-09 14:19 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161109141948.19244-1-lorenzo.pieralisi@arm.com>
DT based systems have a generic kernel API to configure IOMMUs
for devices (ie of_iommu_configure()).
On ARM based ACPI systems, the of_iommu_configure() equivalent can
be implemented atop ACPI IORT kernel API, with the corresponding
functions to map device identifiers to IOMMUs and retrieve the
corresponding IOMMU operations necessary for DMA operations set-up.
By relying on the iommu_fwspec generic kernel infrastructure,
implement the IORT based IOMMU configuration for ARM ACPI systems
and hook it up in the ACPI kernel layer that implements DMA
configuration for a device.
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Tested-by: Hanjun Guo <hanjun.guo@linaro.org>
Tested-by: Tomasz Nowicki <tn@semihalf.com>
Cc: Hanjun Guo <hanjun.guo@linaro.org>
Cc: Tomasz Nowicki <tn@semihalf.com>
Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
---
drivers/acpi/arm64/iort.c | 99 +++++++++++++++++++++++++++++++++++++++++++++++
drivers/acpi/scan.c | 7 +++-
include/linux/acpi_iort.h | 6 +++
3 files changed, 111 insertions(+), 1 deletion(-)
diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index 7d30605..c129c60 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -28,6 +28,8 @@
#define IORT_TYPE_MASK(type) (1 << (type))
#define IORT_MSI_TYPE (1 << ACPI_IORT_NODE_ITS_GROUP)
+#define IORT_IOMMU_TYPE ((1 << ACPI_IORT_NODE_SMMU) | \
+ (1 << ACPI_IORT_NODE_SMMU_V3))
struct iort_its_msi_chip {
struct list_head list;
@@ -501,6 +503,103 @@ struct irq_domain *iort_get_device_domain(struct device *dev, u32 req_id)
return irq_find_matching_fwnode(handle, DOMAIN_BUS_PCI_MSI);
}
+static int __get_pci_rid(struct pci_dev *pdev, u16 alias, void *data)
+{
+ u32 *rid = data;
+
+ *rid = alias;
+ return 0;
+}
+
+static int arm_smmu_iort_xlate(struct device *dev, u32 streamid,
+ struct fwnode_handle *fwnode,
+ const struct iommu_ops *ops)
+{
+ int ret = iommu_fwspec_init(dev, fwnode, ops);
+
+ if (!ret)
+ ret = iommu_fwspec_add_ids(dev, &streamid, 1);
+
+ return ret;
+}
+
+static const struct iommu_ops *iort_iommu_xlate(struct device *dev,
+ struct acpi_iort_node *node,
+ u32 streamid)
+{
+ struct fwnode_handle *iort_fwnode = NULL;
+ const struct iommu_ops *ops = NULL;
+ int ret = -ENODEV;
+
+ if (node) {
+ iort_fwnode = iort_get_fwnode(node);
+ if (!iort_fwnode)
+ return NULL;
+
+ ops = fwnode_iommu_get_ops(iort_fwnode);
+ if (!ops)
+ return NULL;
+
+ ret = arm_smmu_iort_xlate(dev, streamid,
+ iort_fwnode, ops);
+ }
+
+ return ret ? NULL : ops;
+}
+
+/**
+ * iort_iommu_configure - Set-up IOMMU configuration for a device.
+ *
+ * @dev: device to configure
+ *
+ * Returns: iommu_ops pointer on configuration success
+ * NULL on configuration failure
+ */
+const struct iommu_ops *iort_iommu_configure(struct device *dev)
+{
+ struct acpi_iort_node *node, *parent;
+ const struct iommu_ops *ops = NULL;
+ u32 streamid = 0;
+
+ if (dev_is_pci(dev)) {
+ struct pci_bus *bus = to_pci_dev(dev)->bus;
+ u32 rid;
+
+ pci_for_each_dma_alias(to_pci_dev(dev), __get_pci_rid,
+ &rid);
+
+ node = iort_scan_node(ACPI_IORT_NODE_PCI_ROOT_COMPLEX,
+ iort_match_node_callback, &bus->dev);
+ if (!node)
+ return NULL;
+
+ parent = iort_node_map_rid(node, rid, &streamid,
+ IORT_IOMMU_TYPE);
+
+ ops = iort_iommu_xlate(dev, parent, streamid);
+
+ } else {
+ int i = 0;
+
+ node = iort_scan_node(ACPI_IORT_NODE_NAMED_COMPONENT,
+ iort_match_node_callback, dev);
+ if (!node)
+ return NULL;
+
+ parent = iort_node_get_id(node, &streamid,
+ IORT_IOMMU_TYPE, i++);
+
+ while (parent) {
+ ops = iort_iommu_xlate(dev, parent, streamid);
+
+ parent = iort_node_get_id(node, &streamid,
+ IORT_IOMMU_TYPE, i++);
+ }
+ }
+
+ return ops;
+}
+
static void __init acpi_iort_register_irq(int hwirq, const char *name,
int trigger,
struct resource *res)
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 694e0b6..e5f7004 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -7,6 +7,7 @@
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/acpi.h>
+#include <linux/acpi_iort.h>
#include <linux/signal.h>
#include <linux/kthread.h>
#include <linux/dmi.h>
@@ -1377,6 +1378,8 @@ enum dev_dma_attr acpi_get_dma_attr(struct acpi_device *adev)
*/
void acpi_dma_configure(struct device *dev, enum dev_dma_attr attr)
{
+ const struct iommu_ops *iommu;
+
/*
* Set default coherent_dma_mask to 32 bit. Drivers are expected to
* setup the correct supported mask.
@@ -1391,11 +1394,13 @@ void acpi_dma_configure(struct device *dev, enum dev_dma_attr attr)
if (!dev->dma_mask)
dev->dma_mask = &dev->coherent_dma_mask;
+ iommu = iort_iommu_configure(dev);
+
/*
* Assume dma valid range starts at 0 and covers the whole
* coherent_dma_mask.
*/
- arch_setup_dma_ops(dev, 0, dev->coherent_dma_mask + 1, NULL,
+ arch_setup_dma_ops(dev, 0, dev->coherent_dma_mask + 1, iommu,
attr == DEV_DMA_COHERENT);
}
EXPORT_SYMBOL_GPL(acpi_dma_configure);
diff --git a/include/linux/acpi_iort.h b/include/linux/acpi_iort.h
index 79ba1bb..dcb2b60 100644
--- a/include/linux/acpi_iort.h
+++ b/include/linux/acpi_iort.h
@@ -34,6 +34,8 @@ void acpi_iort_init(void);
bool iort_node_match(u8 type);
u32 iort_msi_map_rid(struct device *dev, u32 req_id);
struct irq_domain *iort_get_device_domain(struct device *dev, u32 req_id);
+/* IOMMU interface */
+const struct iommu_ops *iort_iommu_configure(struct device *dev);
#else
static inline void acpi_iort_init(void) { }
static inline bool iort_node_match(u8 type) { return false; }
@@ -42,6 +44,10 @@ static inline u32 iort_msi_map_rid(struct device *dev, u32 req_id)
static inline struct irq_domain *iort_get_device_domain(struct device *dev,
u32 req_id)
{ return NULL; }
+/* IOMMU interface */
+static inline
+const struct iommu_ops *iort_iommu_configure(struct device *dev)
+{ return NULL; }
#endif
#define IORT_ACPI_DECLARE(name, table_id, fn) \
--
2.10.0
^ permalink raw reply related
* [PATCH v7 15/16] drivers: acpi: iort: add single mapping function
From: Lorenzo Pieralisi @ 2016-11-09 14:19 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161109141948.19244-1-lorenzo.pieralisi@arm.com>
The current IORT id mapping API requires components to provide
an input requester ID (a Bus-Device-Function (BDF) identifier for
PCI devices) to translate an input identifier to an output
identifier through an IORT range mapping.
Named components do not have an identifiable source ID therefore
their respective input/output mapping can only be defined in
IORT tables through single mappings, that provide a translation
that does not require any input identifier.
Current IORT interface for requester id mappings (iort_node_map_rid())
is not suitable for components that do not provide a requester id,
so it cannot be used for IORT named components.
Add an interface to the IORT API to enable retrieval of id
by allowing an indexed walk of the single mappings array for
a given component, therefore completing the IORT mapping API.
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Tested-by: Hanjun Guo <hanjun.guo@linaro.org>
Tested-by: Tomasz Nowicki <tn@semihalf.com>
Cc: Hanjun Guo <hanjun.guo@linaro.org>
Cc: Tomasz Nowicki <tn@semihalf.com>
Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
---
drivers/acpi/arm64/iort.c | 39 +++++++++++++++++++++++++++++++++++++++
1 file changed, 39 insertions(+)
diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index 62057c6..7d30605 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -318,6 +318,45 @@ static int iort_id_map(struct acpi_iort_id_mapping *map, u8 type, u32 rid_in,
return 0;
}
+static
+struct acpi_iort_node *iort_node_get_id(struct acpi_iort_node *node,
+ u32 *id_out, u8 type_mask,
+ int index)
+{
+ struct acpi_iort_node *parent;
+ struct acpi_iort_id_mapping *map;
+
+ if (!node->mapping_offset || !node->mapping_count ||
+ index >= node->mapping_count)
+ return NULL;
+
+ map = ACPI_ADD_PTR(struct acpi_iort_id_mapping, node,
+ node->mapping_offset);
+
+ /* Firmware bug! */
+ if (!map->output_reference) {
+ pr_err(FW_BUG "[node %p type %d] ID map has NULL parent reference\n",
+ node, node->type);
+ return NULL;
+ }
+
+ parent = ACPI_ADD_PTR(struct acpi_iort_node, iort_table,
+ map->output_reference);
+
+ if (!(IORT_TYPE_MASK(parent->type) & type_mask))
+ return NULL;
+
+ if (map[index].flags & ACPI_IORT_ID_SINGLE_MAPPING) {
+ if (node->type == ACPI_IORT_NODE_NAMED_COMPONENT ||
+ node->type == ACPI_IORT_NODE_PCI_ROOT_COMPLEX) {
+ *id_out = map[index].output_base;
+ return parent;
+ }
+ }
+
+ return NULL;
+}
+
static struct acpi_iort_node *iort_node_map_rid(struct acpi_iort_node *node,
u32 rid_in, u32 *rid_out,
u8 type_mask)
--
2.10.0
^ permalink raw reply related
* [PATCH v7 15/16] drivers: acpi: iort: add single mapping function
From: Lorenzo Pieralisi @ 2016-11-09 14:19 UTC (permalink / raw)
To: iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA
Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-acpi-u79uwXL29TY76Z2rM5mHXA, Marc Zyngier, Tomasz Nowicki,
Rafael J. Wysocki, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
Will Deacon, Sinan Kaya, linux-pci-u79uwXL29TY76Z2rM5mHXA,
Jon Masters, Dennis Chen, Prem Mallappa
In-Reply-To: <20161109141948.19244-1-lorenzo.pieralisi-5wv7dgnIgG8@public.gmane.org>
The current IORT id mapping API requires components to provide
an input requester ID (a Bus-Device-Function (BDF) identifier for
PCI devices) to translate an input identifier to an output
identifier through an IORT range mapping.
Named components do not have an identifiable source ID therefore
their respective input/output mapping can only be defined in
IORT tables through single mappings, that provide a translation
that does not require any input identifier.
Current IORT interface for requester id mappings (iort_node_map_rid())
is not suitable for components that do not provide a requester id,
so it cannot be used for IORT named components.
Add an interface to the IORT API to enable retrieval of id
by allowing an indexed walk of the single mappings array for
a given component, therefore completing the IORT mapping API.
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi-5wv7dgnIgG8@public.gmane.org>
Tested-by: Hanjun Guo <hanjun.guo-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
Tested-by: Tomasz Nowicki <tn-nYOzD4b6Jr9Wk0Htik3J/w@public.gmane.org>
Cc: Hanjun Guo <hanjun.guo-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
Cc: Tomasz Nowicki <tn-nYOzD4b6Jr9Wk0Htik3J/w@public.gmane.org>
Cc: "Rafael J. Wysocki" <rjw-LthD3rsA81gm4RdzfppkhA@public.gmane.org>
---
drivers/acpi/arm64/iort.c | 39 +++++++++++++++++++++++++++++++++++++++
1 file changed, 39 insertions(+)
diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index 62057c6..7d30605 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -318,6 +318,45 @@ static int iort_id_map(struct acpi_iort_id_mapping *map, u8 type, u32 rid_in,
return 0;
}
+static
+struct acpi_iort_node *iort_node_get_id(struct acpi_iort_node *node,
+ u32 *id_out, u8 type_mask,
+ int index)
+{
+ struct acpi_iort_node *parent;
+ struct acpi_iort_id_mapping *map;
+
+ if (!node->mapping_offset || !node->mapping_count ||
+ index >= node->mapping_count)
+ return NULL;
+
+ map = ACPI_ADD_PTR(struct acpi_iort_id_mapping, node,
+ node->mapping_offset);
+
+ /* Firmware bug! */
+ if (!map->output_reference) {
+ pr_err(FW_BUG "[node %p type %d] ID map has NULL parent reference\n",
+ node, node->type);
+ return NULL;
+ }
+
+ parent = ACPI_ADD_PTR(struct acpi_iort_node, iort_table,
+ map->output_reference);
+
+ if (!(IORT_TYPE_MASK(parent->type) & type_mask))
+ return NULL;
+
+ if (map[index].flags & ACPI_IORT_ID_SINGLE_MAPPING) {
+ if (node->type == ACPI_IORT_NODE_NAMED_COMPONENT ||
+ node->type == ACPI_IORT_NODE_PCI_ROOT_COMPLEX) {
+ *id_out = map[index].output_base;
+ return parent;
+ }
+ }
+
+ return NULL;
+}
+
static struct acpi_iort_node *iort_node_map_rid(struct acpi_iort_node *node,
u32 rid_in, u32 *rid_out,
u8 type_mask)
--
2.10.0
^ permalink raw reply related
* [PATCH v7 14/16] drivers: acpi: iort: replace rid map type with type mask
From: Lorenzo Pieralisi @ 2016-11-09 14:19 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161109141948.19244-1-lorenzo.pieralisi@arm.com>
IORT tables provide data that allow the kernel to carry out
device ID mappings between endpoints and system components
(eg interrupt controllers, IOMMUs). When the mapping for a
given device ID is carried out, the translation mechanism
is done on a per-subsystem basis rather than a component
subtype (ie the IOMMU kernel layer will look for mappings
from a device to all IORT node types corresponding to IOMMU
components), therefore the corresponding mapping API should
work on a range (ie mask) of IORT node types corresponding
to a common set of components (eg IOMMUs) rather than a
specific node type.
Upgrade the IORT iort_node_map_rid() API to work with a
type mask instead of a single node type so that it can
be used for mappings that span multiple components types
(ie IOMMUs).
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Tested-by: Hanjun Guo <hanjun.guo@linaro.org>
Tested-by: Tomasz Nowicki <tn@semihalf.com>
Cc: Hanjun Guo <hanjun.guo@linaro.org>
Cc: Tomasz Nowicki <tn@semihalf.com>
Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
---
drivers/acpi/arm64/iort.c | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index 4708806..62057c6 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -26,6 +26,9 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
+#define IORT_TYPE_MASK(type) (1 << (type))
+#define IORT_MSI_TYPE (1 << ACPI_IORT_NODE_ITS_GROUP)
+
struct iort_its_msi_chip {
struct list_head list;
struct fwnode_handle *fw_node;
@@ -317,7 +320,7 @@ static int iort_id_map(struct acpi_iort_id_mapping *map, u8 type, u32 rid_in,
static struct acpi_iort_node *iort_node_map_rid(struct acpi_iort_node *node,
u32 rid_in, u32 *rid_out,
- u8 type)
+ u8 type_mask)
{
u32 rid = rid_in;
@@ -326,7 +329,7 @@ static struct acpi_iort_node *iort_node_map_rid(struct acpi_iort_node *node,
struct acpi_iort_id_mapping *map;
int i;
- if (node->type == type) {
+ if (IORT_TYPE_MASK(node->type) & type_mask) {
if (rid_out)
*rid_out = rid;
return node;
@@ -399,7 +402,7 @@ u32 iort_msi_map_rid(struct device *dev, u32 req_id)
if (!node)
return req_id;
- iort_node_map_rid(node, req_id, &dev_id, ACPI_IORT_NODE_ITS_GROUP);
+ iort_node_map_rid(node, req_id, &dev_id, IORT_MSI_TYPE);
return dev_id;
}
@@ -421,7 +424,7 @@ static int iort_dev_find_its_id(struct device *dev, u32 req_id,
if (!node)
return -ENXIO;
- node = iort_node_map_rid(node, req_id, NULL, ACPI_IORT_NODE_ITS_GROUP);
+ node = iort_node_map_rid(node, req_id, NULL, IORT_MSI_TYPE);
if (!node)
return -ENXIO;
--
2.10.0
^ permalink raw reply related
* [PATCH v7 16/16] drivers: acpi: iort: introduce iort_iommu_configure
From: Lorenzo Pieralisi @ 2016-11-09 14:19 UTC (permalink / raw)
To: iommu
Cc: Lorenzo Pieralisi, Hanjun Guo, Tomasz Nowicki, Rafael J. Wysocki,
Will Deacon, Marc Zyngier, Robin Murphy, Joerg Roedel,
Jon Masters, Eric Auger, Sinan Kaya, Nate Watterson,
Prem Mallappa, Dennis Chen, linux-acpi, linux-pci, linux-kernel,
linux-arm-kernel
In-Reply-To: <20161109141948.19244-1-lorenzo.pieralisi@arm.com>
DT based systems have a generic kernel API to configure IOMMUs
for devices (ie of_iommu_configure()).
On ARM based ACPI systems, the of_iommu_configure() equivalent can
be implemented atop ACPI IORT kernel API, with the corresponding
functions to map device identifiers to IOMMUs and retrieve the
corresponding IOMMU operations necessary for DMA operations set-up.
By relying on the iommu_fwspec generic kernel infrastructure,
implement the IORT based IOMMU configuration for ARM ACPI systems
and hook it up in the ACPI kernel layer that implements DMA
configuration for a device.
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Tested-by: Hanjun Guo <hanjun.guo@linaro.org>
Tested-by: Tomasz Nowicki <tn@semihalf.com>
Cc: Hanjun Guo <hanjun.guo@linaro.org>
Cc: Tomasz Nowicki <tn@semihalf.com>
Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
---
drivers/acpi/arm64/iort.c | 99 +++++++++++++++++++++++++++++++++++++++++++++++
drivers/acpi/scan.c | 7 +++-
include/linux/acpi_iort.h | 6 +++
3 files changed, 111 insertions(+), 1 deletion(-)
diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index 7d30605..c129c60 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -28,6 +28,8 @@
#define IORT_TYPE_MASK(type) (1 << (type))
#define IORT_MSI_TYPE (1 << ACPI_IORT_NODE_ITS_GROUP)
+#define IORT_IOMMU_TYPE ((1 << ACPI_IORT_NODE_SMMU) | \
+ (1 << ACPI_IORT_NODE_SMMU_V3))
struct iort_its_msi_chip {
struct list_head list;
@@ -501,6 +503,103 @@ struct irq_domain *iort_get_device_domain(struct device *dev, u32 req_id)
return irq_find_matching_fwnode(handle, DOMAIN_BUS_PCI_MSI);
}
+static int __get_pci_rid(struct pci_dev *pdev, u16 alias, void *data)
+{
+ u32 *rid = data;
+
+ *rid = alias;
+ return 0;
+}
+
+static int arm_smmu_iort_xlate(struct device *dev, u32 streamid,
+ struct fwnode_handle *fwnode,
+ const struct iommu_ops *ops)
+{
+ int ret = iommu_fwspec_init(dev, fwnode, ops);
+
+ if (!ret)
+ ret = iommu_fwspec_add_ids(dev, &streamid, 1);
+
+ return ret;
+}
+
+static const struct iommu_ops *iort_iommu_xlate(struct device *dev,
+ struct acpi_iort_node *node,
+ u32 streamid)
+{
+ struct fwnode_handle *iort_fwnode = NULL;
+ const struct iommu_ops *ops = NULL;
+ int ret = -ENODEV;
+
+ if (node) {
+ iort_fwnode = iort_get_fwnode(node);
+ if (!iort_fwnode)
+ return NULL;
+
+ ops = fwnode_iommu_get_ops(iort_fwnode);
+ if (!ops)
+ return NULL;
+
+ ret = arm_smmu_iort_xlate(dev, streamid,
+ iort_fwnode, ops);
+ }
+
+ return ret ? NULL : ops;
+}
+
+/**
+ * iort_iommu_configure - Set-up IOMMU configuration for a device.
+ *
+ * @dev: device to configure
+ *
+ * Returns: iommu_ops pointer on configuration success
+ * NULL on configuration failure
+ */
+const struct iommu_ops *iort_iommu_configure(struct device *dev)
+{
+ struct acpi_iort_node *node, *parent;
+ const struct iommu_ops *ops = NULL;
+ u32 streamid = 0;
+
+ if (dev_is_pci(dev)) {
+ struct pci_bus *bus = to_pci_dev(dev)->bus;
+ u32 rid;
+
+ pci_for_each_dma_alias(to_pci_dev(dev), __get_pci_rid,
+ &rid);
+
+ node = iort_scan_node(ACPI_IORT_NODE_PCI_ROOT_COMPLEX,
+ iort_match_node_callback, &bus->dev);
+ if (!node)
+ return NULL;
+
+ parent = iort_node_map_rid(node, rid, &streamid,
+ IORT_IOMMU_TYPE);
+
+ ops = iort_iommu_xlate(dev, parent, streamid);
+
+ } else {
+ int i = 0;
+
+ node = iort_scan_node(ACPI_IORT_NODE_NAMED_COMPONENT,
+ iort_match_node_callback, dev);
+ if (!node)
+ return NULL;
+
+ parent = iort_node_get_id(node, &streamid,
+ IORT_IOMMU_TYPE, i++);
+
+ while (parent) {
+ ops = iort_iommu_xlate(dev, parent, streamid);
+
+ parent = iort_node_get_id(node, &streamid,
+ IORT_IOMMU_TYPE, i++);
+ }
+ }
+
+ return ops;
+}
+
static void __init acpi_iort_register_irq(int hwirq, const char *name,
int trigger,
struct resource *res)
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 694e0b6..e5f7004 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -7,6 +7,7 @@
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/acpi.h>
+#include <linux/acpi_iort.h>
#include <linux/signal.h>
#include <linux/kthread.h>
#include <linux/dmi.h>
@@ -1377,6 +1378,8 @@ enum dev_dma_attr acpi_get_dma_attr(struct acpi_device *adev)
*/
void acpi_dma_configure(struct device *dev, enum dev_dma_attr attr)
{
+ const struct iommu_ops *iommu;
+
/*
* Set default coherent_dma_mask to 32 bit. Drivers are expected to
* setup the correct supported mask.
@@ -1391,11 +1394,13 @@ void acpi_dma_configure(struct device *dev, enum dev_dma_attr attr)
if (!dev->dma_mask)
dev->dma_mask = &dev->coherent_dma_mask;
+ iommu = iort_iommu_configure(dev);
+
/*
* Assume dma valid range starts at 0 and covers the whole
* coherent_dma_mask.
*/
- arch_setup_dma_ops(dev, 0, dev->coherent_dma_mask + 1, NULL,
+ arch_setup_dma_ops(dev, 0, dev->coherent_dma_mask + 1, iommu,
attr == DEV_DMA_COHERENT);
}
EXPORT_SYMBOL_GPL(acpi_dma_configure);
diff --git a/include/linux/acpi_iort.h b/include/linux/acpi_iort.h
index 79ba1bb..dcb2b60 100644
--- a/include/linux/acpi_iort.h
+++ b/include/linux/acpi_iort.h
@@ -34,6 +34,8 @@ void acpi_iort_init(void);
bool iort_node_match(u8 type);
u32 iort_msi_map_rid(struct device *dev, u32 req_id);
struct irq_domain *iort_get_device_domain(struct device *dev, u32 req_id);
+/* IOMMU interface */
+const struct iommu_ops *iort_iommu_configure(struct device *dev);
#else
static inline void acpi_iort_init(void) { }
static inline bool iort_node_match(u8 type) { return false; }
@@ -42,6 +44,10 @@ static inline u32 iort_msi_map_rid(struct device *dev, u32 req_id)
static inline struct irq_domain *iort_get_device_domain(struct device *dev,
u32 req_id)
{ return NULL; }
+/* IOMMU interface */
+static inline
+const struct iommu_ops *iort_iommu_configure(struct device *dev)
+{ return NULL; }
#endif
#define IORT_ACPI_DECLARE(name, table_id, fn) \
--
2.10.0
^ permalink raw reply related
* [PATCH v7 13/16] drivers: iommu: arm-smmu: add IORT configuration
From: Lorenzo Pieralisi @ 2016-11-09 14:19 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161109141948.19244-1-lorenzo.pieralisi@arm.com>
In ACPI bases systems, in order to be able to create platform
devices and initialize them for ARM SMMU components, the IORT
kernel implementation requires a set of static functions to be
used by the IORT kernel layer to configure platform devices for
ARM SMMU components.
Add static configuration functions to the IORT kernel layer for
the ARM SMMU components, so that the ARM SMMU driver can
initialize its respective platform device by relying on the IORT
kernel infrastructure and by adding a corresponding ACPI device
early probe section entry.
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Tested-by: Hanjun Guo <hanjun.guo@linaro.org>
Tested-by: Tomasz Nowicki <tn@semihalf.com>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Robin Murphy <robin.murphy@arm.com>
Cc: Joerg Roedel <joro@8bytes.org>
---
drivers/acpi/arm64/iort.c | 81 +++++++++++++++++++++++++++++++++++++++++++++
drivers/iommu/arm-smmu.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++-
include/linux/acpi_iort.h | 3 ++
3 files changed, 166 insertions(+), 1 deletion(-)
diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index fd52e4c..4708806 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -548,6 +548,78 @@ static bool __init arm_smmu_v3_is_coherent(struct acpi_iort_node *node)
return smmu->flags & ACPI_IORT_SMMU_V3_COHACC_OVERRIDE;
}
+static int __init arm_smmu_count_resources(struct acpi_iort_node *node)
+{
+ struct acpi_iort_smmu *smmu;
+ int num_irqs;
+ u64 *glb_irq;
+
+ /* Retrieve SMMU specific data */
+ smmu = (struct acpi_iort_smmu *)node->node_data;
+
+ glb_irq = ACPI_ADD_PTR(u64, node, smmu->global_interrupt_offset);
+ if (!IORT_IRQ_MASK(glb_irq[1])) /* 0 means not implemented */
+ num_irqs = 1;
+ else
+ num_irqs = 2;
+
+ num_irqs += smmu->context_interrupt_count;
+
+ return num_irqs + 1;
+}
+
+static void __init arm_smmu_init_resources(struct resource *res,
+ struct acpi_iort_node *node)
+{
+ struct acpi_iort_smmu *smmu;
+ int i, hw_irq, trigger, num_res = 0;
+ u64 *ctx_irq, *glb_irq;
+
+ /* Retrieve SMMU specific data */
+ smmu = (struct acpi_iort_smmu *)node->node_data;
+
+ res[num_res].start = smmu->base_address;
+ res[num_res].end = smmu->base_address + smmu->span - 1;
+ res[num_res].flags = IORESOURCE_MEM;
+ num_res++;
+
+ glb_irq = ACPI_ADD_PTR(u64, node, smmu->global_interrupt_offset);
+ /* Global IRQs */
+ hw_irq = IORT_IRQ_MASK(glb_irq[0]);
+ trigger = IORT_IRQ_TRIGGER_MASK(glb_irq[0]);
+
+ acpi_iort_register_irq(hw_irq, "arm-smmu-global", trigger,
+ &res[num_res++]);
+
+ /* Global IRQs */
+ hw_irq = IORT_IRQ_MASK(glb_irq[1]);
+ if (hw_irq) {
+ trigger = IORT_IRQ_TRIGGER_MASK(glb_irq[1]);
+ acpi_iort_register_irq(hw_irq, "arm-smmu-global", trigger,
+ &res[num_res++]);
+ }
+
+ /* Context IRQs */
+ ctx_irq = ACPI_ADD_PTR(u64, node, smmu->context_interrupt_offset);
+ for (i = 0; i < smmu->context_interrupt_count; i++) {
+ hw_irq = IORT_IRQ_MASK(ctx_irq[i]);
+ trigger = IORT_IRQ_TRIGGER_MASK(ctx_irq[i]);
+
+ acpi_iort_register_irq(hw_irq, "arm-smmu-context", trigger,
+ &res[num_res++]);
+ }
+}
+
+static bool __init arm_smmu_is_coherent(struct acpi_iort_node *node)
+{
+ struct acpi_iort_smmu *smmu;
+
+ /* Retrieve SMMU specific data */
+ smmu = (struct acpi_iort_smmu *)node->node_data;
+
+ return smmu->flags & ACPI_IORT_SMMU_COHERENT_WALK;
+}
+
struct iort_iommu_config {
const char *name;
int (*iommu_init)(struct acpi_iort_node *node);
@@ -564,12 +636,21 @@ static const struct iort_iommu_config iort_arm_smmu_v3_cfg __initconst = {
.iommu_init_resources = arm_smmu_v3_init_resources
};
+static const struct iort_iommu_config iort_arm_smmu_cfg __initconst = {
+ .name = "arm-smmu",
+ .iommu_is_coherent = arm_smmu_is_coherent,
+ .iommu_count_resources = arm_smmu_count_resources,
+ .iommu_init_resources = arm_smmu_init_resources
+};
+
static __init
const struct iort_iommu_config *iort_get_iommu_cfg(struct acpi_iort_node *node)
{
switch (node->type) {
case ACPI_IORT_NODE_SMMU_V3:
return &iort_arm_smmu_v3_cfg;
+ case ACPI_IORT_NODE_SMMU:
+ return &iort_arm_smmu_cfg;
default:
return NULL;
}
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index e1b6951..2e86cbf 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -28,6 +28,8 @@
#define pr_fmt(fmt) "arm-smmu: " fmt
+#include <linux/acpi.h>
+#include <linux/acpi_iort.h>
#include <linux/atomic.h>
#include <linux/delay.h>
#include <linux/dma-iommu.h>
@@ -1904,6 +1906,70 @@ static const struct of_device_id arm_smmu_of_match[] = {
};
MODULE_DEVICE_TABLE(of, arm_smmu_of_match);
+#ifdef CONFIG_ACPI
+static int acpi_smmu_get_data(u32 model, u32 *version, u32 *impl)
+{
+ int ret = 0;
+
+ switch (model) {
+ case ACPI_IORT_SMMU_V1:
+ case ACPI_IORT_SMMU_CORELINK_MMU400:
+ *version = ARM_SMMU_V1;
+ *impl = GENERIC_SMMU;
+ break;
+ case ACPI_IORT_SMMU_V2:
+ *version = ARM_SMMU_V2;
+ *impl = GENERIC_SMMU;
+ break;
+ case ACPI_IORT_SMMU_CORELINK_MMU500:
+ *version = ARM_SMMU_V2;
+ *impl = ARM_MMU500;
+ break;
+ default:
+ ret = -ENODEV;
+ }
+
+ return ret;
+}
+
+static int arm_smmu_device_acpi_probe(struct platform_device *pdev,
+ struct arm_smmu_device *smmu)
+{
+ struct device *dev = smmu->dev;
+ struct acpi_iort_node *node =
+ *(struct acpi_iort_node **)dev_get_platdata(dev);
+ struct acpi_iort_smmu *iort_smmu;
+ u64 *glb_irq;
+ int ret;
+
+ /* Retrieve SMMU1/2 specific data */
+ iort_smmu = (struct acpi_iort_smmu *)node->node_data;
+
+ ret = acpi_smmu_get_data(iort_smmu->model, &smmu->version,
+ &smmu->model);
+ if (ret < 0)
+ return ret;
+
+ glb_irq = ACPI_ADD_PTR(u64, node, iort_smmu->global_interrupt_offset);
+
+ if (!IORT_IRQ_MASK(glb_irq[1])) /* 0 means not implemented */
+ smmu->num_global_irqs = 1;
+ else
+ smmu->num_global_irqs = 2;
+
+ if (iort_smmu->flags & ACPI_IORT_SMMU_COHERENT_WALK)
+ smmu->features |= ARM_SMMU_FEAT_COHERENT_WALK;
+
+ return 0;
+}
+#else
+static inline int arm_smmu_device_acpi_probe(struct platform_device *pdev,
+ struct arm_smmu_device *smmu)
+{
+ return -ENODEV;
+}
+#endif
+
static int arm_smmu_device_dt_probe(struct platform_device *pdev,
struct arm_smmu_device *smmu)
{
@@ -1955,7 +2021,11 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
}
smmu->dev = dev;
- err = arm_smmu_device_dt_probe(pdev, smmu);
+ if (dev->of_node)
+ err = arm_smmu_device_dt_probe(pdev, smmu);
+ else
+ err = arm_smmu_device_acpi_probe(pdev, smmu);
+
if (err)
return err;
@@ -2103,6 +2173,17 @@ IOMMU_OF_DECLARE(arm_mmu401, "arm,mmu-401", arm_smmu_of_init);
IOMMU_OF_DECLARE(arm_mmu500, "arm,mmu-500", arm_smmu_of_init);
IOMMU_OF_DECLARE(cavium_smmuv2, "cavium,smmu-v2", arm_smmu_of_init);
+#ifdef CONFIG_ACPI
+static int __init arm_smmu_acpi_init(struct acpi_table_header *table)
+{
+ if (iort_node_match(ACPI_IORT_NODE_SMMU))
+ return arm_smmu_init();
+
+ return 0;
+}
+IORT_ACPI_DECLARE(arm_smmu, ACPI_SIG_IORT, arm_smmu_acpi_init);
+#endif
+
MODULE_DESCRIPTION("IOMMU API for ARM architected SMMU implementations");
MODULE_AUTHOR("Will Deacon <will.deacon@arm.com>");
MODULE_LICENSE("GPL v2");
diff --git a/include/linux/acpi_iort.h b/include/linux/acpi_iort.h
index 17bb078..79ba1bb 100644
--- a/include/linux/acpi_iort.h
+++ b/include/linux/acpi_iort.h
@@ -23,6 +23,9 @@
#include <linux/fwnode.h>
#include <linux/irqdomain.h>
+#define IORT_IRQ_MASK(irq) (irq & 0xffffffffULL)
+#define IORT_IRQ_TRIGGER_MASK(irq) ((irq >> 32) & 0xffffffffULL)
+
int iort_register_domain_token(int trans_id, struct fwnode_handle *fw_node);
void iort_deregister_domain_token(int trans_id);
struct fwnode_handle *iort_find_domain_token(int trans_id);
--
2.10.0
^ permalink raw reply related
* [PATCH v7 13/16] drivers: iommu: arm-smmu: add IORT configuration
From: Lorenzo Pieralisi @ 2016-11-09 14:19 UTC (permalink / raw)
To: iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA
Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-acpi-u79uwXL29TY76Z2rM5mHXA, Marc Zyngier,
Rafael J. Wysocki, Will Deacon,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-pci-u79uwXL29TY76Z2rM5mHXA, Sinan Kaya, Dennis Chen,
Tomasz Nowicki, Prem Mallappa, Jon Masters
In-Reply-To: <20161109141948.19244-1-lorenzo.pieralisi-5wv7dgnIgG8@public.gmane.org>
In ACPI bases systems, in order to be able to create platform
devices and initialize them for ARM SMMU components, the IORT
kernel implementation requires a set of static functions to be
used by the IORT kernel layer to configure platform devices for
ARM SMMU components.
Add static configuration functions to the IORT kernel layer for
the ARM SMMU components, so that the ARM SMMU driver can
initialize its respective platform device by relying on the IORT
kernel infrastructure and by adding a corresponding ACPI device
early probe section entry.
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi-5wv7dgnIgG8@public.gmane.org>
Tested-by: Hanjun Guo <hanjun.guo-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
Tested-by: Tomasz Nowicki <tn-nYOzD4b6Jr9Wk0Htik3J/w@public.gmane.org>
Cc: Will Deacon <will.deacon-5wv7dgnIgG8@public.gmane.org>
Cc: Robin Murphy <robin.murphy-5wv7dgnIgG8@public.gmane.org>
Cc: Joerg Roedel <joro-zLv9SwRftAIdnm+yROfE0A@public.gmane.org>
---
drivers/acpi/arm64/iort.c | 81 +++++++++++++++++++++++++++++++++++++++++++++
drivers/iommu/arm-smmu.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++-
include/linux/acpi_iort.h | 3 ++
3 files changed, 166 insertions(+), 1 deletion(-)
diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index fd52e4c..4708806 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -548,6 +548,78 @@ static bool __init arm_smmu_v3_is_coherent(struct acpi_iort_node *node)
return smmu->flags & ACPI_IORT_SMMU_V3_COHACC_OVERRIDE;
}
+static int __init arm_smmu_count_resources(struct acpi_iort_node *node)
+{
+ struct acpi_iort_smmu *smmu;
+ int num_irqs;
+ u64 *glb_irq;
+
+ /* Retrieve SMMU specific data */
+ smmu = (struct acpi_iort_smmu *)node->node_data;
+
+ glb_irq = ACPI_ADD_PTR(u64, node, smmu->global_interrupt_offset);
+ if (!IORT_IRQ_MASK(glb_irq[1])) /* 0 means not implemented */
+ num_irqs = 1;
+ else
+ num_irqs = 2;
+
+ num_irqs += smmu->context_interrupt_count;
+
+ return num_irqs + 1;
+}
+
+static void __init arm_smmu_init_resources(struct resource *res,
+ struct acpi_iort_node *node)
+{
+ struct acpi_iort_smmu *smmu;
+ int i, hw_irq, trigger, num_res = 0;
+ u64 *ctx_irq, *glb_irq;
+
+ /* Retrieve SMMU specific data */
+ smmu = (struct acpi_iort_smmu *)node->node_data;
+
+ res[num_res].start = smmu->base_address;
+ res[num_res].end = smmu->base_address + smmu->span - 1;
+ res[num_res].flags = IORESOURCE_MEM;
+ num_res++;
+
+ glb_irq = ACPI_ADD_PTR(u64, node, smmu->global_interrupt_offset);
+ /* Global IRQs */
+ hw_irq = IORT_IRQ_MASK(glb_irq[0]);
+ trigger = IORT_IRQ_TRIGGER_MASK(glb_irq[0]);
+
+ acpi_iort_register_irq(hw_irq, "arm-smmu-global", trigger,
+ &res[num_res++]);
+
+ /* Global IRQs */
+ hw_irq = IORT_IRQ_MASK(glb_irq[1]);
+ if (hw_irq) {
+ trigger = IORT_IRQ_TRIGGER_MASK(glb_irq[1]);
+ acpi_iort_register_irq(hw_irq, "arm-smmu-global", trigger,
+ &res[num_res++]);
+ }
+
+ /* Context IRQs */
+ ctx_irq = ACPI_ADD_PTR(u64, node, smmu->context_interrupt_offset);
+ for (i = 0; i < smmu->context_interrupt_count; i++) {
+ hw_irq = IORT_IRQ_MASK(ctx_irq[i]);
+ trigger = IORT_IRQ_TRIGGER_MASK(ctx_irq[i]);
+
+ acpi_iort_register_irq(hw_irq, "arm-smmu-context", trigger,
+ &res[num_res++]);
+ }
+}
+
+static bool __init arm_smmu_is_coherent(struct acpi_iort_node *node)
+{
+ struct acpi_iort_smmu *smmu;
+
+ /* Retrieve SMMU specific data */
+ smmu = (struct acpi_iort_smmu *)node->node_data;
+
+ return smmu->flags & ACPI_IORT_SMMU_COHERENT_WALK;
+}
+
struct iort_iommu_config {
const char *name;
int (*iommu_init)(struct acpi_iort_node *node);
@@ -564,12 +636,21 @@ static const struct iort_iommu_config iort_arm_smmu_v3_cfg __initconst = {
.iommu_init_resources = arm_smmu_v3_init_resources
};
+static const struct iort_iommu_config iort_arm_smmu_cfg __initconst = {
+ .name = "arm-smmu",
+ .iommu_is_coherent = arm_smmu_is_coherent,
+ .iommu_count_resources = arm_smmu_count_resources,
+ .iommu_init_resources = arm_smmu_init_resources
+};
+
static __init
const struct iort_iommu_config *iort_get_iommu_cfg(struct acpi_iort_node *node)
{
switch (node->type) {
case ACPI_IORT_NODE_SMMU_V3:
return &iort_arm_smmu_v3_cfg;
+ case ACPI_IORT_NODE_SMMU:
+ return &iort_arm_smmu_cfg;
default:
return NULL;
}
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index e1b6951..2e86cbf 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -28,6 +28,8 @@
#define pr_fmt(fmt) "arm-smmu: " fmt
+#include <linux/acpi.h>
+#include <linux/acpi_iort.h>
#include <linux/atomic.h>
#include <linux/delay.h>
#include <linux/dma-iommu.h>
@@ -1904,6 +1906,70 @@ static const struct of_device_id arm_smmu_of_match[] = {
};
MODULE_DEVICE_TABLE(of, arm_smmu_of_match);
+#ifdef CONFIG_ACPI
+static int acpi_smmu_get_data(u32 model, u32 *version, u32 *impl)
+{
+ int ret = 0;
+
+ switch (model) {
+ case ACPI_IORT_SMMU_V1:
+ case ACPI_IORT_SMMU_CORELINK_MMU400:
+ *version = ARM_SMMU_V1;
+ *impl = GENERIC_SMMU;
+ break;
+ case ACPI_IORT_SMMU_V2:
+ *version = ARM_SMMU_V2;
+ *impl = GENERIC_SMMU;
+ break;
+ case ACPI_IORT_SMMU_CORELINK_MMU500:
+ *version = ARM_SMMU_V2;
+ *impl = ARM_MMU500;
+ break;
+ default:
+ ret = -ENODEV;
+ }
+
+ return ret;
+}
+
+static int arm_smmu_device_acpi_probe(struct platform_device *pdev,
+ struct arm_smmu_device *smmu)
+{
+ struct device *dev = smmu->dev;
+ struct acpi_iort_node *node =
+ *(struct acpi_iort_node **)dev_get_platdata(dev);
+ struct acpi_iort_smmu *iort_smmu;
+ u64 *glb_irq;
+ int ret;
+
+ /* Retrieve SMMU1/2 specific data */
+ iort_smmu = (struct acpi_iort_smmu *)node->node_data;
+
+ ret = acpi_smmu_get_data(iort_smmu->model, &smmu->version,
+ &smmu->model);
+ if (ret < 0)
+ return ret;
+
+ glb_irq = ACPI_ADD_PTR(u64, node, iort_smmu->global_interrupt_offset);
+
+ if (!IORT_IRQ_MASK(glb_irq[1])) /* 0 means not implemented */
+ smmu->num_global_irqs = 1;
+ else
+ smmu->num_global_irqs = 2;
+
+ if (iort_smmu->flags & ACPI_IORT_SMMU_COHERENT_WALK)
+ smmu->features |= ARM_SMMU_FEAT_COHERENT_WALK;
+
+ return 0;
+}
+#else
+static inline int arm_smmu_device_acpi_probe(struct platform_device *pdev,
+ struct arm_smmu_device *smmu)
+{
+ return -ENODEV;
+}
+#endif
+
static int arm_smmu_device_dt_probe(struct platform_device *pdev,
struct arm_smmu_device *smmu)
{
@@ -1955,7 +2021,11 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
}
smmu->dev = dev;
- err = arm_smmu_device_dt_probe(pdev, smmu);
+ if (dev->of_node)
+ err = arm_smmu_device_dt_probe(pdev, smmu);
+ else
+ err = arm_smmu_device_acpi_probe(pdev, smmu);
+
if (err)
return err;
@@ -2103,6 +2173,17 @@ IOMMU_OF_DECLARE(arm_mmu401, "arm,mmu-401", arm_smmu_of_init);
IOMMU_OF_DECLARE(arm_mmu500, "arm,mmu-500", arm_smmu_of_init);
IOMMU_OF_DECLARE(cavium_smmuv2, "cavium,smmu-v2", arm_smmu_of_init);
+#ifdef CONFIG_ACPI
+static int __init arm_smmu_acpi_init(struct acpi_table_header *table)
+{
+ if (iort_node_match(ACPI_IORT_NODE_SMMU))
+ return arm_smmu_init();
+
+ return 0;
+}
+IORT_ACPI_DECLARE(arm_smmu, ACPI_SIG_IORT, arm_smmu_acpi_init);
+#endif
+
MODULE_DESCRIPTION("IOMMU API for ARM architected SMMU implementations");
MODULE_AUTHOR("Will Deacon <will.deacon-5wv7dgnIgG8@public.gmane.org>");
MODULE_LICENSE("GPL v2");
diff --git a/include/linux/acpi_iort.h b/include/linux/acpi_iort.h
index 17bb078..79ba1bb 100644
--- a/include/linux/acpi_iort.h
+++ b/include/linux/acpi_iort.h
@@ -23,6 +23,9 @@
#include <linux/fwnode.h>
#include <linux/irqdomain.h>
+#define IORT_IRQ_MASK(irq) (irq & 0xffffffffULL)
+#define IORT_IRQ_TRIGGER_MASK(irq) ((irq >> 32) & 0xffffffffULL)
+
int iort_register_domain_token(int trans_id, struct fwnode_handle *fw_node);
void iort_deregister_domain_token(int trans_id);
struct fwnode_handle *iort_find_domain_token(int trans_id);
--
2.10.0
^ permalink raw reply related
* [PATCH v7 12/16] drivers: iommu: arm-smmu: split probe functions into DT/generic portions
From: Lorenzo Pieralisi @ 2016-11-09 14:19 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161109141948.19244-1-lorenzo.pieralisi@arm.com>
Current ARM SMMU probe functions intermingle HW and DT probing
in the initialization functions to detect and programme the ARM SMMU
driver features. In order to allow probing the ARM SMMU with other
firmwares than DT, this patch splits the ARM SMMU init functions into
DT and HW specific portions so that other FW interfaces (ie ACPI) can
reuse the HW probing functions and skip the DT portion accordingly.
This patch implements no functional change, only code reshuffling.
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Tested-by: Hanjun Guo <hanjun.guo@linaro.org>
Tested-by: Tomasz Nowicki <tn@semihalf.com>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Hanjun Guo <hanjun.guo@linaro.org>
Cc: Robin Murphy <robin.murphy@arm.com>
---
drivers/iommu/arm-smmu.c | 62 +++++++++++++++++++++++++++++-------------------
1 file changed, 37 insertions(+), 25 deletions(-)
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index 8a3c2a4..e1b6951 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -1668,7 +1668,7 @@ static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu)
unsigned long size;
void __iomem *gr0_base = ARM_SMMU_GR0(smmu);
u32 id;
- bool cttw_dt, cttw_reg;
+ bool cttw_reg, cttw_fw = smmu->features & ARM_SMMU_FEAT_COHERENT_WALK;
int i;
dev_notice(smmu->dev, "probing hardware configuration...\n");
@@ -1713,20 +1713,17 @@ static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu)
/*
* In order for DMA API calls to work properly, we must defer to what
- * the DT says about coherency, regardless of what the hardware claims.
+ * the FW says about coherency, regardless of what the hardware claims.
* Fortunately, this also opens up a workaround for systems where the
* ID register value has ended up configured incorrectly.
*/
- cttw_dt = of_dma_is_coherent(smmu->dev->of_node);
cttw_reg = !!(id & ID0_CTTW);
- if (cttw_dt)
- smmu->features |= ARM_SMMU_FEAT_COHERENT_WALK;
- if (cttw_dt || cttw_reg)
+ if (cttw_fw || cttw_reg)
dev_notice(smmu->dev, "\t%scoherent table walk\n",
- cttw_dt ? "" : "non-");
- if (cttw_dt != cttw_reg)
+ cttw_fw ? "" : "non-");
+ if (cttw_fw != cttw_reg)
dev_notice(smmu->dev,
- "\t(IDR0.CTTW overridden by dma-coherent property)\n");
+ "\t(IDR0.CTTW overridden by FW configuration)\n");
/* Max. number of entries we have for stream matching/indexing */
size = 1 << ((id >> ID0_NUMSIDB_SHIFT) & ID0_NUMSIDB_MASK);
@@ -1907,15 +1904,25 @@ static const struct of_device_id arm_smmu_of_match[] = {
};
MODULE_DEVICE_TABLE(of, arm_smmu_of_match);
-static int arm_smmu_device_dt_probe(struct platform_device *pdev)
+static int arm_smmu_device_dt_probe(struct platform_device *pdev,
+ struct arm_smmu_device *smmu)
{
const struct arm_smmu_match_data *data;
- struct resource *res;
- struct arm_smmu_device *smmu;
struct device *dev = &pdev->dev;
- int num_irqs, i, err;
bool legacy_binding;
+ if (of_property_read_u32(dev->of_node, "#global-interrupts",
+ &smmu->num_global_irqs)) {
+ dev_err(dev, "missing #global-interrupts property\n");
+ return -ENODEV;
+ }
+
+ data = of_device_get_match_data(dev);
+ smmu->version = data->version;
+ smmu->model = data->model;
+
+ parse_driver_options(smmu);
+
legacy_binding = of_find_property(dev->of_node, "mmu-masters", NULL);
if (legacy_binding && !using_generic_binding) {
if (!using_legacy_binding)
@@ -1928,6 +1935,19 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev)
return -ENODEV;
}
+ if (of_dma_is_coherent(smmu->dev->of_node))
+ smmu->features |= ARM_SMMU_FEAT_COHERENT_WALK;
+
+ return 0;
+}
+
+static int arm_smmu_device_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ struct arm_smmu_device *smmu;
+ struct device *dev = &pdev->dev;
+ int num_irqs, i, err;
+
smmu = devm_kzalloc(dev, sizeof(*smmu), GFP_KERNEL);
if (!smmu) {
dev_err(dev, "failed to allocate arm_smmu_device\n");
@@ -1935,9 +1955,9 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev)
}
smmu->dev = dev;
- data = of_device_get_match_data(dev);
- smmu->version = data->version;
- smmu->model = data->model;
+ err = arm_smmu_device_dt_probe(pdev, smmu);
+ if (err)
+ return err;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
smmu->base = devm_ioremap_resource(dev, res);
@@ -1945,12 +1965,6 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev)
return PTR_ERR(smmu->base);
smmu->size = resource_size(res);
- if (of_property_read_u32(dev->of_node, "#global-interrupts",
- &smmu->num_global_irqs)) {
- dev_err(dev, "missing #global-interrupts property\n");
- return -ENODEV;
- }
-
num_irqs = 0;
while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, num_irqs))) {
num_irqs++;
@@ -1985,8 +1999,6 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev)
if (err)
return err;
- parse_driver_options(smmu);
-
if (smmu->version == ARM_SMMU_V2 &&
smmu->num_context_banks != smmu->num_context_irqs) {
dev_err(dev,
@@ -2048,7 +2060,7 @@ static struct platform_driver arm_smmu_driver = {
.name = "arm-smmu",
.of_match_table = of_match_ptr(arm_smmu_of_match),
},
- .probe = arm_smmu_device_dt_probe,
+ .probe = arm_smmu_device_probe,
.remove = arm_smmu_device_remove,
};
--
2.10.0
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.