* [PATCHv8 00/21] Tegra,SMMU update V8
@ 2014-05-30 11:20 Hiroshi Doyu
[not found] ` <1401448834-32659-1-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
0 siblings, 1 reply; 31+ messages in thread
From: Hiroshi Doyu @ 2014-05-30 11:20 UTC (permalink / raw)
To: linux-tegra-u79uwXL29TY76Z2rM5mHXA
Hi,
This is the Tegra,SMMU update v8, including Tegra124 support. This
series hasn't been changed so much from v7. Just a few minor fixes are
added, rebased onto next-20140527. Still device population order issue
needs to be solved before being merged. If this problem is solved,
this series can be posted more wider MLs to review/merge.
This series is posted for ones to try your device with IOMMU.
Hiroshi Doyu (21):
of: introduce of_property_for_each_phandle_with_args()
iommu/of: introduce a global iommu device list
iommu/of: check if dependee iommu is ready or not
driver/core: populate devices in order for IOMMUs
iommu/core: add ops->{bound,unbind}_driver()
ARM: tegra: create a DT header defining SWGROUP ID
iommu/tegra: smmu: register device to iommu dynamically
iommu/tegra: smmu: calculate ASID register offset by ID
iommu/tegra: smmu: get swgroups from DT "iommus="
iommu/tegra: smmu: allow duplicate ASID wirte
iommu/tegra: smmu: Rename hwgrp -> swgroups
iommu/tegra: smmu: add SMMU to an global iommu list
iommu/tegra124: smmu: optionaly AHB enables SMMU
iommu/tegra124: smmu: convert swgroup ID to asid offset
iommu/tegra124: smmu: add support platform data
iommu/tegra124: smmu: support more than 32 bit pa
iommu/tegra124: smmu: {TLB,PTC} reset value per SoC
iommu/tegra124: smmu: adjust TLB_FLUSH_ASID bit range
iommu/tegra124: smmu: add multiple asid_security support
ARM: dt: tegra124: add tegra,smmu entry
ARM: dt: tegra124: add sdhci iommus bindings
.../bindings/iommu/nvidia,tegra30-smmu.txt | 4 +-
arch/arm/boot/dts/tegra124.dtsi | 19 +
drivers/base/dd.c | 5 +
drivers/iommu/Kconfig | 1 +
drivers/iommu/iommu.c | 13 +-
drivers/iommu/of_iommu.c | 49 ++
drivers/iommu/tegra-smmu.c | 567 ++++++++++++++-------
drivers/of/base.c | 50 ++
include/dt-bindings/memory/tegra-swgroup.h | 50 ++
include/linux/iommu.h | 4 +
include/linux/of.h | 36 ++
include/linux/of_iommu.h | 22 +
12 files changed, 626 insertions(+), 194 deletions(-)
create mode 100644 include/dt-bindings/memory/tegra-swgroup.h
--
2.0.0.rc1.15.g7e76a2f
^ permalink raw reply [flat|nested] 31+ messages in thread
* [PATCHv8 01/21] of: introduce of_property_for_each_phandle_with_args()
[not found] ` <1401448834-32659-1-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
@ 2014-05-30 11:20 ` Hiroshi Doyu
2014-05-30 11:20 ` [PATCHv8 02/21] iommu/of: introduce a global iommu device list Hiroshi Doyu
` (19 subsequent siblings)
20 siblings, 0 replies; 31+ messages in thread
From: Hiroshi Doyu @ 2014-05-30 11:20 UTC (permalink / raw)
To: linux-tegra-u79uwXL29TY76Z2rM5mHXA
Iterating over a property containing a list of phandles with arguments
is a common operation for device drivers. This patch adds a new
of_property_for_each_phandle_with_args() macro to make the iteration
simpler.
Signed-off-by: Hiroshi Doyu <hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
Cc: Rob Herring <robherring2-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Cc: Grant Likely <grant.likely-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
Reviewed-by: Stephen Warren <swarren-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
drivers/of/base.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++
include/linux/of.h | 36 ++++++++++++++++++++++++++++++++++++
2 files changed, 86 insertions(+)
diff --git a/drivers/of/base.c b/drivers/of/base.c
index 03e7fc6c93e8..9c6834794fd5 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -1492,6 +1492,56 @@ void of_print_phandle_args(const char *msg, const struct of_phandle_args *args)
printk("\n");
}
+void of_phandle_iter_next(struct of_phandle_iter *iter)
+{
+ struct device_node *dn;
+ int i, count;
+
+ if (!iter->cur || (iter->cur >= iter->end))
+ goto err_out;
+
+ dn = of_find_node_by_phandle(be32_to_cpup(iter->cur++));
+ if (!dn)
+ goto err_out;
+
+ if (iter->cells_name) {
+ if (of_property_read_u32(dn, iter->cells_name, &count))
+ goto err_out;
+ } else {
+ count = iter->cell_count;
+ }
+
+ iter->out_args.np = dn;
+ iter->out_args.args_count = count;
+ for (i = 0; i < count; i++)
+ iter->out_args.args[i] = be32_to_cpup(iter->cur++);
+
+ return;
+
+err_out:
+ iter->cur = NULL;
+}
+EXPORT_SYMBOL_GPL(of_phandle_iter_next);
+
+void of_phandle_iter_start(struct of_phandle_iter *iter,
+ const struct device_node *np,
+ const char *list_name, const char *cells_name,
+ int cell_count)
+{
+ size_t bytes;
+
+ iter->cur = of_get_property(np, list_name, &bytes);
+ if (!iter->cur)
+ return;
+ iter->end = iter->cur;
+ if (bytes)
+ iter->end += bytes / sizeof(*iter->cur);
+ iter->cells_name = cells_name;
+ iter->cell_count = cell_count;
+ of_phandle_iter_next(iter);
+}
+EXPORT_SYMBOL_GPL(of_phandle_iter_start);
+
static int __of_parse_phandle_with_args(const struct device_node *np,
const char *list_name,
const char *cells_name,
diff --git a/include/linux/of.h b/include/linux/of.h
index fa362867b453..f925f16ef1a8 100644
--- a/include/linux/of.h
+++ b/include/linux/of.h
@@ -74,6 +74,18 @@ struct of_phandle_args {
uint32_t args[MAX_PHANDLE_ARGS];
};
+/*
+ * keep the state at iterating a list of phandles with variable number
+ * of args
+ */
+struct of_phandle_iter {
+ const __be32 *cur; /* current phandle */
+ const __be32 *end; /* end of the last phandle */
+ const char *cells_name;
+ int cell_count;
+ struct of_phandle_args out_args;
+};
+
extern int of_node_add(struct device_node *node);
/* initialize a node */
@@ -303,6 +315,12 @@ extern int of_parse_phandle_with_fixed_args(const struct device_node *np,
extern int of_count_phandle_with_args(const struct device_node *np,
const char *list_name, const char *cells_name);
+extern void of_phandle_iter_start(struct of_phandle_iter *iter,
+ const struct device_node *np,
+ const char *list_name,
+ const char *cells_name, int cell_count);
+extern void of_phandle_iter_next(struct of_phandle_iter *iter);
+
extern void of_alias_scan(void * (*dt_alloc)(u64 size, u64 align));
extern int of_alias_get_id(struct device_node *np, const char *stem);
@@ -554,6 +572,18 @@ static inline int of_count_phandle_with_args(struct device_node *np,
return -ENOSYS;
}
+static inline void of_phandle_iter_start(struct of_phandle_iter *iter,
+ const struct device_node *np,
+ const char *list_name,
+ const char *cells_name,
+ int cell_count);
+{
+}
+
+static inline void of_phandle_iter_next(struct of_phandle_iter *iter)
+{
+}
+
static inline int of_alias_get_id(struct device_node *np, const char *stem)
{
return -ENOSYS;
@@ -742,6 +772,12 @@ static inline int of_property_read_u32(const struct device_node *np,
for (dn = of_find_node_with_property(NULL, prop_name); dn; \
dn = of_find_node_with_property(dn, prop_name))
+#define of_property_for_each_phandle_with_args(iter, np, list_name, \
+ cells_name, cell_count) \
+ for (of_phandle_iter_start(&iter, np, list_name, \
+ cells_name, cell_count); \
+ iter.cur; of_phandle_iter_next(&iter))
+
static inline int of_get_child_count(const struct device_node *np)
{
struct device_node *child;
--
2.0.0.rc1.15.g7e76a2f
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCHv8 02/21] iommu/of: introduce a global iommu device list
[not found] ` <1401448834-32659-1-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2014-05-30 11:20 ` [PATCHv8 01/21] of: introduce of_property_for_each_phandle_with_args() Hiroshi Doyu
@ 2014-05-30 11:20 ` Hiroshi Doyu
2014-05-30 11:20 ` [PATCHv8 03/21] iommu/of: check if dependee iommu is ready or not Hiroshi Doyu
` (18 subsequent siblings)
20 siblings, 0 replies; 31+ messages in thread
From: Hiroshi Doyu @ 2014-05-30 11:20 UTC (permalink / raw)
To: linux-tegra-u79uwXL29TY76Z2rM5mHXA
This enables to find an populated IOMMU device via a device node. This
can be used to see if an dependee IOMMU is populated or not to keep
correct device population order. Client devices need to wait an IOMMU
to be populated.
Suggested by Thierry Reding and copied his example code.
Signed-off-by: Hiroshi Doyu <hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
Cc: Joerg Roedel <joro-zLv9SwRftAIdnm+yROfE0A@public.gmane.org>
Cc: Thierry Reding <thierry.reding-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
drivers/iommu/of_iommu.c | 36 ++++++++++++++++++++++++++++++++++++
include/linux/of_iommu.h | 16 ++++++++++++++++
2 files changed, 52 insertions(+)
diff --git a/drivers/iommu/of_iommu.c b/drivers/iommu/of_iommu.c
index e550ccb7634e..5d1aeb90eae3 100644
--- a/drivers/iommu/of_iommu.c
+++ b/drivers/iommu/of_iommu.c
@@ -21,6 +21,42 @@
#include <linux/limits.h>
#include <linux/of.h>
#include <linux/of_iommu.h>
+#include <linux/device.h>
+
+static DEFINE_MUTEX(iommus_lock);
+static LIST_HEAD(iommus_list);
+
+void iommu_add(struct iommu *iommu)
+{
+ INIT_LIST_HEAD(&iommu->list);
+ mutex_lock(&iommus_lock);
+ list_add_tail(&iommu->list, &iommus_list);
+ mutex_unlock(&iommus_lock);
+}
+
+void iommu_del(struct iommu *iommu)
+{
+ INIT_LIST_HEAD(&iommu->list);
+ mutex_lock(&iommus_lock);
+ list_del(&iommu->list);
+ mutex_unlock(&iommus_lock);
+}
+
+static struct iommu *of_find_iommu_by_node(struct device_node *np)
+{
+ struct iommu *iommu;
+
+ mutex_lock(&iommus_lock);
+ list_for_each_entry(iommu, &iommus_list, list) {
+ if (iommu->dev->of_node == np) {
+ mutex_unlock(&iommus_lock);
+ return iommu;
+ }
+ }
+ mutex_unlock(&iommus_lock);
+
+ return NULL;
+}
/**
* of_get_dma_window - Parse *dma-window property and returns 0 if found.
diff --git a/include/linux/of_iommu.h b/include/linux/of_iommu.h
index 51a560f34bca..108306898c38 100644
--- a/include/linux/of_iommu.h
+++ b/include/linux/of_iommu.h
@@ -3,10 +3,18 @@
#ifdef CONFIG_OF_IOMMU
+struct iommu {
+ struct list_head list;
+ struct device *dev;
+};
+
extern int of_get_dma_window(struct device_node *dn, const char *prefix,
int index, unsigned long *busno, dma_addr_t *addr,
size_t *size);
+void iommu_add(struct iommu *iommu);
+void iommu_del(struct iommu *iommu);
+
#else
static inline int of_get_dma_window(struct device_node *dn, const char *prefix,
@@ -16,6 +24,14 @@ static inline int of_get_dma_window(struct device_node *dn, const char *prefix,
return -EINVAL;
}
+static inline void iommu_add(struct iommu *iommu)
+{
+}
+
+static inline void iommu_del(struct iommu *iommu)
+{
+}
+
#endif /* CONFIG_OF_IOMMU */
#endif /* __OF_IOMMU_H */
--
2.0.0.rc1.15.g7e76a2f
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCHv8 03/21] iommu/of: check if dependee iommu is ready or not
[not found] ` <1401448834-32659-1-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2014-05-30 11:20 ` [PATCHv8 01/21] of: introduce of_property_for_each_phandle_with_args() Hiroshi Doyu
2014-05-30 11:20 ` [PATCHv8 02/21] iommu/of: introduce a global iommu device list Hiroshi Doyu
@ 2014-05-30 11:20 ` Hiroshi Doyu
2014-05-30 11:20 ` [PATCHv8 04/21] driver/core: populate devices in order for IOMMUs Hiroshi Doyu
` (17 subsequent siblings)
20 siblings, 0 replies; 31+ messages in thread
From: Hiroshi Doyu @ 2014-05-30 11:20 UTC (permalink / raw)
To: linux-tegra-u79uwXL29TY76Z2rM5mHXA
IOMMU devices on the bus need to be poplulated first, then iommu
master devices are done later.
With CONFIG_OF_IOMMU, "iommus=" DT binding would be used to identify
whether a device can be an iommu msater or not. If a device can, we'll
defer to populate that device till an depending iommu device is
populated.
Signed-off-by: Hiroshi Doyu <hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
drivers/iommu/of_iommu.c | 13 +++++++++++++
include/linux/of_iommu.h | 6 ++++++
2 files changed, 19 insertions(+)
diff --git a/drivers/iommu/of_iommu.c b/drivers/iommu/of_iommu.c
index 5d1aeb90eae3..b9f5081515ae 100644
--- a/drivers/iommu/of_iommu.c
+++ b/drivers/iommu/of_iommu.c
@@ -125,3 +125,16 @@ int of_get_dma_window(struct device_node *dn, const char *prefix, int index,
return 0;
}
EXPORT_SYMBOL_GPL(of_get_dma_window);
+
+int of_iommu_attach(struct device *dev)
+{
+ struct of_phandle_iter iter;
+
+ of_property_for_each_phandle_with_args(iter, dev->of_node, "iommus",
+ "iommu-cells", 0) {
+ if (!of_find_iommu_by_node(iter.out_args.np))
+ return -EPROBE_DEFER;
+ }
+
+ return 0;
+}
diff --git a/include/linux/of_iommu.h b/include/linux/of_iommu.h
index 108306898c38..0e2f5681b45a 100644
--- a/include/linux/of_iommu.h
+++ b/include/linux/of_iommu.h
@@ -14,6 +14,7 @@ extern int of_get_dma_window(struct device_node *dn, const char *prefix,
void iommu_add(struct iommu *iommu);
void iommu_del(struct iommu *iommu);
+int of_iommu_attach(struct device *dev);
#else
@@ -32,6 +33,11 @@ static inline void iommu_del(struct iommu *iommu)
{
}
+static inline int of_iommu_attach(struct device *dev)
+{
+ return 0;
+}
+
#endif /* CONFIG_OF_IOMMU */
#endif /* __OF_IOMMU_H */
--
2.0.0.rc1.15.g7e76a2f
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCHv8 04/21] driver/core: populate devices in order for IOMMUs
[not found] ` <1401448834-32659-1-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
` (2 preceding siblings ...)
2014-05-30 11:20 ` [PATCHv8 03/21] iommu/of: check if dependee iommu is ready or not Hiroshi Doyu
@ 2014-05-30 11:20 ` Hiroshi Doyu
2014-05-30 11:20 ` [PATCHv8 05/21] iommu/core: add ops->{bound,unbind}_driver() Hiroshi Doyu
` (16 subsequent siblings)
20 siblings, 0 replies; 31+ messages in thread
From: Hiroshi Doyu @ 2014-05-30 11:20 UTC (permalink / raw)
To: linux-tegra-u79uwXL29TY76Z2rM5mHXA
IOMMU devices on the bus need to be poplulated first, then iommu
master devices are done later.
With CONFIG_OF_IOMMU, "iommus=" DT binding would be used to identify
whether a device can be an iommu msater or not. If a device can, we'll
defer to populate that device till an iommu device is populated. Then,
those deferred iommu master devices are populated and configured with
help of the already populated iommu device.
Signed-off-by: Hiroshi Doyu <hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
Cc: Greg Kroah-Hartman <gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r@public.gmane.org>
---
drivers/base/dd.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index 62ec61e8f84a..ef5069d03831 100644
--- a/drivers/base/dd.c
+++ b/drivers/base/dd.c
@@ -25,6 +25,7 @@
#include <linux/async.h>
#include <linux/pm_runtime.h>
#include <linux/pinctrl/devinfo.h>
+#include <linux/of_iommu.h>
#include "base.h"
#include "power/power.h"
@@ -287,6 +288,10 @@ static int really_probe(struct device *dev, struct device_driver *drv)
dev->driver = drv;
+ ret = of_iommu_attach(dev);
+ if (ret)
+ goto probe_failed;
+
/* If using pinctrl, bind pins now before probing */
ret = pinctrl_bind_pins(dev);
if (ret)
--
2.0.0.rc1.15.g7e76a2f
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCHv8 05/21] iommu/core: add ops->{bound,unbind}_driver()
[not found] ` <1401448834-32659-1-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
` (3 preceding siblings ...)
2014-05-30 11:20 ` [PATCHv8 04/21] driver/core: populate devices in order for IOMMUs Hiroshi Doyu
@ 2014-05-30 11:20 ` Hiroshi Doyu
[not found] ` <1401448834-32659-6-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2014-05-30 11:20 ` [PATCHv8 06/21] ARM: tegra: create a DT header defining SWGROUP ID Hiroshi Doyu
` (15 subsequent siblings)
20 siblings, 1 reply; 31+ messages in thread
From: Hiroshi Doyu @ 2014-05-30 11:20 UTC (permalink / raw)
To: linux-tegra-u79uwXL29TY76Z2rM5mHXA
ops->{bound,unbind}_driver() functions are called at
BUS_NOTIFY_{BOUND,UNBIND}_DRIVER respectively.
This is necessary to control the device population order. IOMMU master
devices depend on an IOMMU device instanciation. IOMMU master devices
can be registered to an IOMMU only after it's successfully
populated. This IOMMU registration is done via
ops->bound_driver(). Currently this population can be deferred if
depending IOMMU device hasn't yet been populated in driver core. This
cannot be done via ops->add_device() since after add_device() device's
population/instanciation can be still deferred via probe().
Signed-off-by: Hiroshi Doyu <hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
drivers/iommu/iommu.c | 13 +++++++++++--
include/linux/iommu.h | 4 ++++
2 files changed, 15 insertions(+), 2 deletions(-)
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index e5555fcfe703..5469d361e7bc 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -540,14 +540,23 @@ static int iommu_bus_notifier(struct notifier_block *nb,
* ADD/DEL call into iommu driver ops if provided, which may
* result in ADD/DEL notifiers to group->notifier
*/
- if (action == BUS_NOTIFY_ADD_DEVICE) {
+ switch (action) {
+ case BUS_NOTIFY_ADD_DEVICE:
if (ops->add_device)
return ops->add_device(dev);
- } else if (action == BUS_NOTIFY_DEL_DEVICE) {
+ case BUS_NOTIFY_DEL_DEVICE:
if (ops->remove_device && dev->iommu_group) {
ops->remove_device(dev);
return 0;
}
+ case BUS_NOTIFY_BOUND_DRIVER:
+ if (ops->bound_driver)
+ ops->bound_driver(dev);
+ break;
+ case BUS_NOTIFY_UNBIND_DRIVER:
+ if (ops->unbind_driver)
+ ops->unbind_driver(dev);
+ break;
}
/*
diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index b96a5b2136e4..141eea25bdea 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -97,6 +97,8 @@ enum iommu_attr {
* @domain_has_cap: domain capabilities query
* @add_device: add device to iommu grouping
* @remove_device: remove device from iommu grouping
+ * @bound_driver: called at BUS_NOTIFY_BOUND_DRIVER
+ * @unbind_driver: called at BUS_NOTIFY_UNBIND_DRIVER
* @domain_get_attr: Query domain attributes
* @domain_set_attr: Change domain attributes
* @pgsize_bitmap: bitmap of supported page sizes
@@ -115,6 +117,8 @@ struct iommu_ops {
unsigned long cap);
int (*add_device)(struct device *dev);
void (*remove_device)(struct device *dev);
+ int (*bound_driver)(struct device *dev);
+ void (*unbind_driver)(struct device *dev);
int (*device_group)(struct device *dev, unsigned int *groupid);
int (*domain_get_attr)(struct iommu_domain *domain,
enum iommu_attr attr, void *data);
--
2.0.0.rc1.15.g7e76a2f
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCHv8 06/21] ARM: tegra: create a DT header defining SWGROUP ID
[not found] ` <1401448834-32659-1-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
` (4 preceding siblings ...)
2014-05-30 11:20 ` [PATCHv8 05/21] iommu/core: add ops->{bound,unbind}_driver() Hiroshi Doyu
@ 2014-05-30 11:20 ` Hiroshi Doyu
2014-05-30 11:20 ` [PATCHv8 07/21] iommu/tegra: smmu: register device to iommu dynamically Hiroshi Doyu
` (14 subsequent siblings)
20 siblings, 0 replies; 31+ messages in thread
From: Hiroshi Doyu @ 2014-05-30 11:20 UTC (permalink / raw)
To: linux-tegra-u79uwXL29TY76Z2rM5mHXA
Create a header file to define the swgroup IDs used by the IOMMU(SMMU)
binding. "swgroup" is a group of H/W clients which a Tegra SoC
supports. This unique ID can be used to calculate MC_SMMU_<swgroup
name>_ASID_0 register offset and MC_<swgroup name>_HOTRESET_*_0
register bit. This will allow the same header to be used by both
device tree files, and drivers implementing this binding, which
guarantees that the two stay in sync. This also makes device trees
more readable by using names instead of magic numbers. For HOTRESET
bit shifting we need another conversion table, which will come later.
Signed-off-by: Hiroshi Doyu <hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
Cc: Mark Zhang <markz-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
include/dt-bindings/memory/tegra-swgroup.h | 50 ++++++++++++++++++++++++++++++
1 file changed, 50 insertions(+)
create mode 100644 include/dt-bindings/memory/tegra-swgroup.h
diff --git a/include/dt-bindings/memory/tegra-swgroup.h b/include/dt-bindings/memory/tegra-swgroup.h
new file mode 100644
index 000000000000..32dd307e5f8e
--- /dev/null
+++ b/include/dt-bindings/memory/tegra-swgroup.h
@@ -0,0 +1,50 @@
+/*
+ * This header provides constants for binding nvidia,swgroup ID
+ */
+
+#ifndef _DT_BINDINGS_MEMORY_TEGRA_SWGROUP_H
+#define _DT_BINDINGS_MEMORY_TEGRA_SWGROUP_H
+
+#define TEGRA_SWGROUP_AFI 0 /* 0x238 */
+#define TEGRA_SWGROUP_AVPC 1 /* 0x23c */
+#define TEGRA_SWGROUP_DC 2 /* 0x240 */
+#define TEGRA_SWGROUP_DCB 3 /* 0x244 */
+#define TEGRA_SWGROUP_EPP 4 /* 0x248 */
+#define TEGRA_SWGROUP_G2 5 /* 0x24c */
+#define TEGRA_SWGROUP_HC 6 /* 0x250 */
+#define TEGRA_SWGROUP_HDA 7 /* 0x254 */
+#define TEGRA_SWGROUP_ISP 8 /* 0x258 */
+#define TEGRA_SWGROUP_ISP2 8
+#define TEGRA_SWGROUP_DC14 9 /* 0x490 *//* Exceptional non-linear */
+#define TEGRA_SWGROUP_DC12 10 /* 0xa88 *//* Exceptional non-linear */
+#define TEGRA_SWGROUP_MPE 11 /* 0x264 */
+#define TEGRA_SWGROUP_MSENC 11
+#define TEGRA_SWGROUP_NV 12 /* 0x268 */
+#define TEGRA_SWGROUP_NV2 13 /* 0x26c */
+#define TEGRA_SWGROUP_PPCS 14 /* 0x270 */
+#define TEGRA_SWGROUP_SATA2 15 /* 0x274 */
+#define TEGRA_SWGROUP_SATA 16 /* 0x278 */
+#define TEGRA_SWGROUP_VDE 17 /* 0x27c */
+#define TEGRA_SWGROUP_VI 18 /* 0x280 */
+#define TEGRA_SWGROUP_VIC 19 /* 0x284 */
+#define TEGRA_SWGROUP_XUSB_HOST 20 /* 0x288 */
+#define TEGRA_SWGROUP_XUSB_DEV 21 /* 0x28c */
+#define TEGRA_SWGROUP_A9AVP 22 /* 0x290 */
+#define TEGRA_SWGROUP_TSEC 23 /* 0x294 */
+#define TEGRA_SWGROUP_PPCS1 24 /* 0x298 */
+#define TEGRA_SWGROUP_SDMMC1A 25 /* 0xa94 *//* Linear shift again */
+#define TEGRA_SWGROUP_SDMMC2A 26 /* 0xa98 */
+#define TEGRA_SWGROUP_SDMMC3A 27 /* 0xa9c */
+#define TEGRA_SWGROUP_SDMMC4A 28 /* 0xaa0 */
+#define TEGRA_SWGROUP_ISP2B 29 /* 0xaa4 */
+#define TEGRA_SWGROUP_GPU 30 /* 0xaa8 */
+#define TEGRA_SWGROUP_GPUB 31 /* 0xaac */
+#define TEGRA_SWGROUP_PPCS2 32 /* 0xab0 */
+
+#define TWO_U32_OF_U64(x) ((x) & 0xffffffff) ((x) >> 32)
+#define TEGRA_SWGROUP_BIT(x) (1ULL << TEGRA_SWGROUP_##x)
+#define TEGRA_SWGROUP_CELLS(x) TWO_U32_OF_U64(TEGRA_SWGROUP_BIT(x))
+
+#define TEGRA_SWGROUP_MAX 64
+
+#endif /* _DT_BINDINGS_MEMORY_TEGRA_SWGROUP_H */
--
2.0.0.rc1.15.g7e76a2f
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCHv8 07/21] iommu/tegra: smmu: register device to iommu dynamically
[not found] ` <1401448834-32659-1-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
` (5 preceding siblings ...)
2014-05-30 11:20 ` [PATCHv8 06/21] ARM: tegra: create a DT header defining SWGROUP ID Hiroshi Doyu
@ 2014-05-30 11:20 ` Hiroshi Doyu
2014-05-30 11:20 ` [PATCHv8 08/21] iommu/tegra: smmu: calculate ASID register offset by ID Hiroshi Doyu
` (13 subsequent siblings)
20 siblings, 0 replies; 31+ messages in thread
From: Hiroshi Doyu @ 2014-05-30 11:20 UTC (permalink / raw)
To: linux-tegra-u79uwXL29TY76Z2rM5mHXA
platform_devices are registered as IOMMU'able dynamically via
add_device() and remove_device().
Tegra SMMU can have multiple address spaces(AS). IOMMU'able devices
can belong to one of them. Multiple IOVA maps are created at boot-up,
which can be attached to devices later. We reserve 2 of them for
static assignment, AS[0] for system default, AS[1] for AHB clusters as
protected domain from others, where there are many traditional
pheripheral devices like USB, SD/MMC. They should be isolated from
some smart devices like host1x for system robustness. Even if smart
devices behaves wrongly, the traditional devices(SD/MMC, USB) wouldn't
be affected, and the system could continue most likely. DMA API(ARM)
needs ARM_DMA_USE_IOMMU to be enabled.
Signed-off-by: Hiroshi Doyu <hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
drivers/iommu/Kconfig | 1 +
drivers/iommu/tegra-smmu.c | 70 +++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 70 insertions(+), 1 deletion(-)
diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index d260605e6d5f..ed4aba0b62eb 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -170,6 +170,7 @@ config TEGRA_IOMMU_SMMU
bool "Tegra SMMU IOMMU Support"
depends on ARCH_TEGRA && TEGRA_AHB
select IOMMU_API
+ select ARM_DMA_USE_IOMMU
help
Enables support for remapping discontiguous physical memory
shared with the operating system into contiguous I/O virtual
diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c
index 605b5b46a903..ae5a1e7b48af 100644
--- a/drivers/iommu/tegra-smmu.c
+++ b/drivers/iommu/tegra-smmu.c
@@ -39,6 +39,9 @@
#include <asm/page.h>
#include <asm/cacheflush.h>
+#include <asm/dma-iommu.h>
+
+#include <dt-bindings/memory/tegra-swgroup.h>
enum smmu_hwgrp {
HWGRP_AFI,
@@ -319,6 +322,8 @@ struct smmu_device {
struct device_node *ahb;
+ struct dma_iommu_mapping **map;
+
int num_as;
struct smmu_as as[0]; /* Run-time allocated array */
};
@@ -947,6 +952,44 @@ static void smmu_iommu_domain_destroy(struct iommu_domain *domain)
dev_dbg(smmu->dev, "smmu_as@%p\n", as);
}
+/*
+ * ASID[0] for the system default
+ * ASID[1] for PPCS("AHB bus children"), which has SDMMC
+ * ASID[2][3].. open for drivers, first come, first served.
+ */
+enum {
+ SYSTEM_DEFAULT,
+ SYSTEM_PROTECTED,
+ NUM_OF_STATIC_MAPS,
+};
+
+static int smmu_iommu_bound_driver(struct device *dev)
+{
+ int err = -EPROBE_DEFER;
+ u32 swgroups = dev->platform_data;
+ struct dma_iommu_mapping *map = NULL;
+
+ if (test_bit(TEGRA_SWGROUP_PPCS, swgroups))
+ map = smmu_handle->map[SYSTEM_PROTECTED];
+ else
+ map = smmu_handle->map[SYSTEM_DEFAULT];
+
+ if (map)
+ err = arm_iommu_attach_device(dev, map);
+ else
+ return -EPROBE_DEFER;
+
+ pr_debug("swgroups=%08lx map=%p err=%d %s\n",
+ swgroups, map, err, dev_name(dev));
+ return err;
+}
+
+static void smmu_iommu_unbind_driver(struct device *dev)
+{
+ dev_dbg(dev, "Detaching from map %p\n", to_dma_iommu_mapping(dev));
+ arm_iommu_detach_device(dev);
+}
+
static struct iommu_ops smmu_iommu_ops = {
.domain_init = smmu_iommu_domain_init,
.domain_destroy = smmu_iommu_domain_destroy,
@@ -956,6 +999,8 @@ static struct iommu_ops smmu_iommu_ops = {
.unmap = smmu_iommu_unmap,
.iova_to_phys = smmu_iommu_iova_to_phys,
.domain_has_cap = smmu_iommu_domain_has_cap,
+ .bound_driver = smmu_iommu_bound_driver,
+ .unbind_driver = smmu_iommu_unbind_driver,
.pgsize_bitmap = SMMU_IOMMU_PGSIZES,
};
@@ -1144,6 +1189,23 @@ static int tegra_smmu_resume(struct device *dev)
return err;
}
+static void tegra_smmu_create_default_map(struct smmu_device *smmu)
+{
+ int i;
+
+ for (i = 0; i < smmu->num_as; i++) {
+ dma_addr_t base = smmu->iovmm_base;
+ size_t size = smmu->page_count << PAGE_SHIFT;
+
+ smmu->map[i] = arm_iommu_create_mapping(&platform_bus_type,
+ base, size);
+ if (IS_ERR(smmu->map[i]))
+ dev_err(smmu->dev,
+ "Couldn't create: asid=%d map=%p %pa-%pa\n",
+ i, smmu->map[i], &base, &base + size - 1);
+ }
+}
+
static int tegra_smmu_probe(struct platform_device *pdev)
{
struct smmu_device *smmu;
@@ -1160,13 +1222,18 @@ static int tegra_smmu_probe(struct platform_device *pdev)
if (of_property_read_u32(dev->of_node, "nvidia,#asids", &asids))
return -ENODEV;
- bytes = sizeof(*smmu) + asids * sizeof(*smmu->as);
+ if (asids < NUM_OF_STATIC_MAPS)
+ return -EINVAL;
+
+ bytes = sizeof(*smmu) + asids * (sizeof(*smmu->as) +
+ sizeof(struct dma_iommu_mapping *));
smmu = devm_kzalloc(dev, bytes, GFP_KERNEL);
if (!smmu) {
dev_err(dev, "failed to allocate smmu_device\n");
return -ENOMEM;
}
+ smmu->map = (struct dma_iommu_mapping **)(smmu->as + asids);
smmu->nregs = pdev->num_resources;
smmu->regs = devm_kzalloc(dev, 2 * smmu->nregs * sizeof(*smmu->regs),
GFP_KERNEL);
@@ -1236,6 +1303,7 @@ static int tegra_smmu_probe(struct platform_device *pdev)
smmu_debugfs_create(smmu);
smmu_handle = smmu;
bus_set_iommu(&platform_bus_type, &smmu_iommu_ops);
+ tegra_smmu_create_default_map(smmu);
return 0;
}
--
2.0.0.rc1.15.g7e76a2f
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCHv8 08/21] iommu/tegra: smmu: calculate ASID register offset by ID
[not found] ` <1401448834-32659-1-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
` (6 preceding siblings ...)
2014-05-30 11:20 ` [PATCHv8 07/21] iommu/tegra: smmu: register device to iommu dynamically Hiroshi Doyu
@ 2014-05-30 11:20 ` Hiroshi Doyu
2014-05-30 11:20 ` [PATCHv8 09/21] iommu/tegra: smmu: get swgroups from DT "iommus=" Hiroshi Doyu
` (12 subsequent siblings)
20 siblings, 0 replies; 31+ messages in thread
From: Hiroshi Doyu @ 2014-05-30 11:20 UTC (permalink / raw)
To: linux-tegra-u79uwXL29TY76Z2rM5mHXA
ASID register offset is caclulated by SWGROUP ID so that we can get
rid of old SoC specific MACROs. This ID conversion is needed for the
unified SMMU driver over Tegra SoCs. We use dt-bindings MACRO instead
of SoC dependent MACROs. The formula is:
MC_SMMU_<swgroup name>_ASID_0 = MC_SMMU_AFI_ASID_0 + ID * 4;
Now SWGROUP ID is the global HardWare Accelerator(HWA) identifier
among all Tegra SoC except Tegra2.
Signed-off-by: Hiroshi Doyu <hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
drivers/iommu/tegra-smmu.c | 111 +++++++--------------------------------------
1 file changed, 17 insertions(+), 94 deletions(-)
diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c
index ae5a1e7b48af..fe351cdd5c05 100644
--- a/drivers/iommu/tegra-smmu.c
+++ b/drivers/iommu/tegra-smmu.c
@@ -43,46 +43,6 @@
#include <dt-bindings/memory/tegra-swgroup.h>
-enum smmu_hwgrp {
- HWGRP_AFI,
- HWGRP_AVPC,
- HWGRP_DC,
- HWGRP_DCB,
- HWGRP_EPP,
- HWGRP_G2,
- HWGRP_HC,
- HWGRP_HDA,
- HWGRP_ISP,
- HWGRP_MPE,
- HWGRP_NV,
- HWGRP_NV2,
- HWGRP_PPCS,
- HWGRP_SATA,
- HWGRP_VDE,
- HWGRP_VI,
-
- HWGRP_COUNT,
-
- HWGRP_END = ~0,
-};
-
-#define HWG_AFI (1 << HWGRP_AFI)
-#define HWG_AVPC (1 << HWGRP_AVPC)
-#define HWG_DC (1 << HWGRP_DC)
-#define HWG_DCB (1 << HWGRP_DCB)
-#define HWG_EPP (1 << HWGRP_EPP)
-#define HWG_G2 (1 << HWGRP_G2)
-#define HWG_HC (1 << HWGRP_HC)
-#define HWG_HDA (1 << HWGRP_HDA)
-#define HWG_ISP (1 << HWGRP_ISP)
-#define HWG_MPE (1 << HWGRP_MPE)
-#define HWG_NV (1 << HWGRP_NV)
-#define HWG_NV2 (1 << HWGRP_NV2)
-#define HWG_PPCS (1 << HWGRP_PPCS)
-#define HWG_SATA (1 << HWGRP_SATA)
-#define HWG_VDE (1 << HWGRP_VDE)
-#define HWG_VI (1 << HWGRP_VI)
-
/* bitmap of the page sizes currently supported */
#define SMMU_IOMMU_PGSIZES (SZ_4K)
@@ -152,21 +112,7 @@ enum {
#define SMMU_TRANSLATION_ENABLE_2 0x230
#define SMMU_AFI_ASID 0x238 /* PCIE */
-#define SMMU_AVPC_ASID 0x23c /* AVP */
-#define SMMU_DC_ASID 0x240 /* Display controller */
-#define SMMU_DCB_ASID 0x244 /* Display controller B */
-#define SMMU_EPP_ASID 0x248 /* Encoder pre-processor */
-#define SMMU_G2_ASID 0x24c /* 2D engine */
-#define SMMU_HC_ASID 0x250 /* Host1x */
-#define SMMU_HDA_ASID 0x254 /* High-def audio */
-#define SMMU_ISP_ASID 0x258 /* Image signal processor */
-#define SMMU_MPE_ASID 0x264 /* MPEG encoder */
-#define SMMU_NV_ASID 0x268 /* (3D) */
-#define SMMU_NV2_ASID 0x26c /* (3D) */
-#define SMMU_PPCS_ASID 0x270 /* AHB */
-#define SMMU_SATA_ASID 0x278 /* SATA */
-#define SMMU_VDE_ASID 0x27c /* Video decoder */
-#define SMMU_VI_ASID 0x280 /* Video input */
+#define SMMU_ASID_BASE SMMU_AFI_ASID
#define SMMU_PDE_NEXT_SHIFT 28
@@ -238,27 +184,7 @@ enum {
#define __smmu_client_enable_hwgrp(c, m) __smmu_client_set_hwgrp(c, m, 1)
#define __smmu_client_disable_hwgrp(c) __smmu_client_set_hwgrp(c, 0, 0)
-#define HWGRP_INIT(client) [HWGRP_##client] = SMMU_##client##_ASID
-
-static const u32 smmu_hwgrp_asid_reg[] = {
- HWGRP_INIT(AFI),
- HWGRP_INIT(AVPC),
- HWGRP_INIT(DC),
- HWGRP_INIT(DCB),
- HWGRP_INIT(EPP),
- HWGRP_INIT(G2),
- HWGRP_INIT(HC),
- HWGRP_INIT(HDA),
- HWGRP_INIT(ISP),
- HWGRP_INIT(MPE),
- HWGRP_INIT(NV),
- HWGRP_INIT(NV2),
- HWGRP_INIT(PPCS),
- HWGRP_INIT(SATA),
- HWGRP_INIT(VDE),
- HWGRP_INIT(VI),
-};
-#define HWGRP_ASID_REG(x) (smmu_hwgrp_asid_reg[x])
+#define HWGRP_ASID_REG(x) ((x) * sizeof(u32) + SMMU_ASID_BASE)
/*
* Per client for address space
@@ -267,7 +193,7 @@ struct smmu_client {
struct device *dev;
struct list_head list;
struct smmu_as *as;
- u32 hwgrp;
+ unsigned long hwgrp[2];
};
/*
@@ -384,41 +310,37 @@ static inline void smmu_write(struct smmu_device *smmu, u32 val, size_t offs)
*/
#define FLUSH_SMMU_REGS(smmu) smmu_read(smmu, SMMU_CONFIG)
-#define smmu_client_hwgrp(c) (u32)((c)->dev->platform_data)
-
static int __smmu_client_set_hwgrp(struct smmu_client *c,
- unsigned long map, int on)
+ unsigned long *map, int on)
{
int i;
struct smmu_as *as = c->as;
u32 val, offs, mask = SMMU_ASID_ENABLE(as->asid);
struct smmu_device *smmu = as->smmu;
- WARN_ON(!on && map);
- if (on && !map)
- return -EINVAL;
if (!on)
- map = smmu_client_hwgrp(c);
+ map = c->hwgrp;
- for_each_set_bit(i, &map, HWGRP_COUNT) {
+ for_each_set_bit(i, map, TEGRA_SWGROUP_MAX) {
offs = HWGRP_ASID_REG(i);
val = smmu_read(smmu, offs);
if (on) {
if (WARN_ON(val & mask))
goto err_hw_busy;
val |= mask;
+ memcpy(c->hwgrp, map, sizeof(u64));
} else {
WARN_ON((val & mask) == mask);
val &= ~mask;
}
smmu_write(smmu, val, offs);
}
+
FLUSH_SMMU_REGS(smmu);
- c->hwgrp = map;
return 0;
err_hw_busy:
- for_each_set_bit(i, &map, HWGRP_COUNT) {
+ for_each_set_bit(i, map, TEGRA_SWGROUP_MAX) {
offs = HWGRP_ASID_REG(i);
val = smmu_read(smmu, offs);
val &= ~mask;
@@ -427,17 +349,18 @@ err_hw_busy:
return -EBUSY;
}
-static int smmu_client_set_hwgrp(struct smmu_client *c, u32 map, int on)
+static int smmu_client_set_hwgrp(struct smmu_client *c,
+ unsigned long *map, int on)
{
- u32 val;
+ int err;
unsigned long flags;
struct smmu_as *as = c->as;
struct smmu_device *smmu = as->smmu;
spin_lock_irqsave(&smmu->lock, flags);
- val = __smmu_client_set_hwgrp(c, map, on);
+ err = __smmu_client_set_hwgrp(c, map, on);
spin_unlock_irqrestore(&smmu->lock, flags);
- return val;
+ return err;
}
/*
@@ -796,7 +719,7 @@ static int smmu_iommu_attach_dev(struct iommu_domain *domain,
struct smmu_as *as = domain->priv;
struct smmu_device *smmu = as->smmu;
struct smmu_client *client, *c;
- u32 map;
+ unsigned long *map;
int err;
client = devm_kzalloc(smmu->dev, sizeof(*c), GFP_KERNEL);
@@ -804,7 +727,7 @@ static int smmu_iommu_attach_dev(struct iommu_domain *domain,
return -ENOMEM;
client->dev = dev;
client->as = as;
- map = (unsigned long)dev->platform_data;
+ map = (unsigned long *)dev->platform_data;
if (!map)
return -EINVAL;
@@ -828,7 +751,7 @@ static int smmu_iommu_attach_dev(struct iommu_domain *domain,
* Reserve "page zero" for AVP vectors using a common dummy
* page.
*/
- if (map & HWG_AVPC) {
+ if (test_bit(TEGRA_SWGROUP_AVPC, map)) {
struct page *page;
page = as->smmu->avp_vector_page;
--
2.0.0.rc1.15.g7e76a2f
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCHv8 09/21] iommu/tegra: smmu: get swgroups from DT "iommus="
[not found] ` <1401448834-32659-1-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
` (7 preceding siblings ...)
2014-05-30 11:20 ` [PATCHv8 08/21] iommu/tegra: smmu: calculate ASID register offset by ID Hiroshi Doyu
@ 2014-05-30 11:20 ` Hiroshi Doyu
2014-05-30 11:20 ` [PATCHv8 10/21] iommu/tegra: smmu: allow duplicate ASID wirte Hiroshi Doyu
` (11 subsequent siblings)
20 siblings, 0 replies; 31+ messages in thread
From: Hiroshi Doyu @ 2014-05-30 11:20 UTC (permalink / raw)
To: linux-tegra-u79uwXL29TY76Z2rM5mHXA
This provides the info about which swgroups a device belongs to. This
info is passed from DT. This is necessary for the unified SMMU driver
among Tegra SoCs since each has different H/W accelerators.
Signed-off-by: Hiroshi Doyu <hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
drivers/iommu/tegra-smmu.c | 134 +++++++++++++++++++++++++++++++++++++++------
1 file changed, 116 insertions(+), 18 deletions(-)
diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c
index fe351cdd5c05..1d3f695d3c66 100644
--- a/drivers/iommu/tegra-smmu.c
+++ b/drivers/iommu/tegra-smmu.c
@@ -190,6 +190,8 @@ enum {
* Per client for address space
*/
struct smmu_client {
+ struct device_node *of_node;
+ struct rb_node node;
struct device *dev;
struct list_head list;
struct smmu_as *as;
@@ -233,6 +235,7 @@ struct smmu_device {
spinlock_t lock;
char *name;
struct device *dev;
+ struct rb_root clients;
struct page *avp_vector_page; /* dummy page shared by all AS's */
/*
@@ -310,6 +313,95 @@ static inline void smmu_write(struct smmu_device *smmu, u32 val, size_t offs)
*/
#define FLUSH_SMMU_REGS(smmu) smmu_read(smmu, SMMU_CONFIG)
+static struct smmu_client *find_smmu_client(struct smmu_device *smmu,
+ struct device_node *dev_node)
+{
+ struct rb_node *node = smmu->clients.rb_node;
+
+ while (node) {
+ struct smmu_client *client;
+
+ client = container_of(node, struct smmu_client, node);
+ if (dev_node < client->of_node)
+ node = node->rb_left;
+ else if (dev_node > client->of_node)
+ node = node->rb_right;
+ else
+ return client;
+ }
+
+ return NULL;
+}
+
+static int insert_smmu_client(struct smmu_device *smmu,
+ struct smmu_client *client)
+{
+ struct rb_node **new, *parent;
+
+ new = &smmu->clients.rb_node;
+ parent = NULL;
+ while (*new) {
+ struct smmu_client *this;
+
+ this = container_of(*new, struct smmu_client, node);
+ parent = *new;
+ if (client->of_node < this->of_node)
+ new = &((*new)->rb_left);
+ else if (client->of_node > this->of_node)
+ new = &((*new)->rb_right);
+ else
+ return -EEXIST;
+ }
+
+ rb_link_node(&client->node, parent, new);
+ rb_insert_color(&client->node, &smmu->clients);
+ return 0;
+}
+
+static int register_smmu_client(struct smmu_device *smmu,
+ struct device *dev, unsigned long *swgroups)
+{
+ struct smmu_client *client;
+
+ client = find_smmu_client(smmu, dev->of_node);
+ if (client) {
+ dev_err(dev,
+ "rejecting multiple registrations for client device %s\n",
+ dev->of_node->full_name);
+ return -EBUSY;
+ }
+
+ client = devm_kzalloc(smmu->dev, sizeof(*client), GFP_KERNEL);
+ if (!client)
+ return -ENOMEM;
+
+ client->dev = dev;
+ client->of_node = dev->of_node;
+ memcpy(client->hwgrp, swgroups, sizeof(u64));
+ return insert_smmu_client(smmu, client);
+}
+
+static int smmu_of_get_swgroups(struct device *dev, unsigned long *swgroups)
+{
+ struct of_phandle_iter iter;
+
+ of_property_for_each_phandle_with_args(iter, dev->of_node, "iommus",
+ "iommu-cells", 0) {
+ if (iter.out_args.np != smmu_handle->iommu.dev->of_node)
+ continue;
+
+ BUG_ON(iter.out_args.args_count != 2);
+
+ memcpy(swgroups, iter.out_args.args, sizeof(u64));
+ pr_debug("swgroups=%08lx %08lx ops=%p %s\n",
+ swgroups[0], swgroups[1],
+ dev->bus->iommu_ops, dev_name(dev));
+ return 0;
+ }
+
+ return -ENODEV;
+}
+
static int __smmu_client_set_hwgrp(struct smmu_client *c,
unsigned long *map, int on)
{
@@ -719,21 +811,16 @@ static int smmu_iommu_attach_dev(struct iommu_domain *domain,
struct smmu_as *as = domain->priv;
struct smmu_device *smmu = as->smmu;
struct smmu_client *client, *c;
- unsigned long *map;
int err;
- client = devm_kzalloc(smmu->dev, sizeof(*c), GFP_KERNEL);
+ client = find_smmu_client(smmu, dev->of_node);
if (!client)
return -ENOMEM;
- client->dev = dev;
- client->as = as;
- map = (unsigned long *)dev->platform_data;
- if (!map)
- return -EINVAL;
- err = smmu_client_enable_hwgrp(client, map);
+ client->as = as;
+ err = smmu_client_enable_hwgrp(client, client->hwgrp);
if (err)
- goto err_hwgrp;
+ return -EINVAL;
spin_lock(&as->client_lock);
list_for_each_entry(c, &as->client, list) {
@@ -751,7 +838,7 @@ static int smmu_iommu_attach_dev(struct iommu_domain *domain,
* Reserve "page zero" for AVP vectors using a common dummy
* page.
*/
- if (test_bit(TEGRA_SWGROUP_AVPC, map)) {
+ if (test_bit(TEGRA_SWGROUP_AVPC, client->hwgrp)) {
struct page *page;
page = as->smmu->avp_vector_page;
@@ -766,8 +853,6 @@ static int smmu_iommu_attach_dev(struct iommu_domain *domain,
err_client:
smmu_client_disable_hwgrp(client);
spin_unlock(&as->client_lock);
-err_hwgrp:
- devm_kfree(smmu->dev, client);
return err;
}
@@ -784,7 +869,6 @@ static void smmu_iommu_detach_dev(struct iommu_domain *domain,
if (c->dev == dev) {
smmu_client_disable_hwgrp(c);
list_del(&c->list);
- devm_kfree(smmu->dev, c);
c->as = NULL;
dev_dbg(smmu->dev,
"%s is detached\n", dev_name(c->dev));
@@ -888,10 +972,23 @@ enum {
static int smmu_iommu_bound_driver(struct device *dev)
{
- int err = -EPROBE_DEFER;
- u32 swgroups = dev->platform_data;
+ int err;
+ unsigned long swgroups[2];
struct dma_iommu_mapping *map = NULL;
+ err = smmu_of_get_swgroups(dev, swgroups);
+ if (err)
+ return -ENODEV;
+
+ if (!find_smmu_client(smmu_handle, dev->of_node)) {
+ err = register_smmu_client(smmu_handle, dev, swgroups);
+ if (err) {
+ dev_err(dev, "failed to add client %s\n",
+ dev_name(dev));
+ return -EINVAL;
+ }
+ }
+
if (test_bit(TEGRA_SWGROUP_PPCS, swgroups))
map = smmu_handle->map[SYSTEM_PROTECTED];
else
@@ -900,10 +997,10 @@ static int smmu_iommu_bound_driver(struct device *dev)
if (map)
err = arm_iommu_attach_device(dev, map);
else
- return -EPROBE_DEFER;
+ return -ENODEV;
- pr_debug("swgroups=%08lx map=%p err=%d %s\n",
- swgroups, map, err, dev_name(dev));
+ pr_debug("swgroups=%08lx %08lx map=%p err=%d %s\n",
+ swgroups[0], swgroups[1], map, err, dev_name(dev));
return err;
}
@@ -1156,6 +1253,7 @@ static int tegra_smmu_probe(struct platform_device *pdev)
return -ENOMEM;
}
+ smmu->clients = RB_ROOT;
smmu->map = (struct dma_iommu_mapping **)(smmu->as + asids);
smmu->nregs = pdev->num_resources;
smmu->regs = devm_kzalloc(dev, 2 * smmu->nregs * sizeof(*smmu->regs),
--
2.0.0.rc1.15.g7e76a2f
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCHv8 10/21] iommu/tegra: smmu: allow duplicate ASID wirte
[not found] ` <1401448834-32659-1-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
` (8 preceding siblings ...)
2014-05-30 11:20 ` [PATCHv8 09/21] iommu/tegra: smmu: get swgroups from DT "iommus=" Hiroshi Doyu
@ 2014-05-30 11:20 ` Hiroshi Doyu
2014-05-30 11:20 ` [PATCHv8 11/21] iommu/tegra: smmu: Rename hwgrp -> swgroups Hiroshi Doyu
` (10 subsequent siblings)
20 siblings, 0 replies; 31+ messages in thread
From: Hiroshi Doyu @ 2014-05-30 11:20 UTC (permalink / raw)
To: linux-tegra-u79uwXL29TY76Z2rM5mHXA
The device, which belongs to the same ASID, can try to enable the same
ASID as the other swgroup devices. This should be allowed but just
skip the actual register write. If the write value is different, it
will return -EINVAL.
Signed-off-by: Hiroshi Doyu <hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
drivers/iommu/tegra-smmu.c | 20 ++++++++------------
1 file changed, 8 insertions(+), 12 deletions(-)
diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c
index 1d3f695d3c66..caa531cb1c50 100644
--- a/drivers/iommu/tegra-smmu.c
+++ b/drivers/iommu/tegra-smmu.c
@@ -417,9 +417,13 @@ static int __smmu_client_set_hwgrp(struct smmu_client *c,
offs = HWGRP_ASID_REG(i);
val = smmu_read(smmu, offs);
if (on) {
- if (WARN_ON(val & mask))
- goto err_hw_busy;
- val |= mask;
+ if (val) {
+ if (WARN_ON(val != mask))
+ return -EINVAL;
+ goto skip;
+ }
+
+ val = mask;
memcpy(c->hwgrp, map, sizeof(u64));
} else {
WARN_ON((val & mask) == mask);
@@ -429,16 +433,8 @@ static int __smmu_client_set_hwgrp(struct smmu_client *c,
}
FLUSH_SMMU_REGS(smmu);
+skip:
return 0;
-
-err_hw_busy:
- for_each_set_bit(i, map, TEGRA_SWGROUP_MAX) {
- offs = HWGRP_ASID_REG(i);
- val = smmu_read(smmu, offs);
- val &= ~mask;
- smmu_write(smmu, val, offs);
- }
- return -EBUSY;
}
static int smmu_client_set_hwgrp(struct smmu_client *c,
--
2.0.0.rc1.15.g7e76a2f
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCHv8 11/21] iommu/tegra: smmu: Rename hwgrp -> swgroups
[not found] ` <1401448834-32659-1-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
` (9 preceding siblings ...)
2014-05-30 11:20 ` [PATCHv8 10/21] iommu/tegra: smmu: allow duplicate ASID wirte Hiroshi Doyu
@ 2014-05-30 11:20 ` Hiroshi Doyu
2014-05-30 11:20 ` [PATCHv8 12/21] iommu/tegra: smmu: add SMMU to an global iommu list Hiroshi Doyu
` (9 subsequent siblings)
20 siblings, 0 replies; 31+ messages in thread
From: Hiroshi Doyu @ 2014-05-30 11:20 UTC (permalink / raw)
To: linux-tegra-u79uwXL29TY76Z2rM5mHXA
Use the correct term for SWGROUP related variables and macros.
The term "swgroup" is the collection of "memory client". A "memory
client" usually represents a HardWare Accelerator(HWA) like
GPU. Sometimes a strut device can belong to multiple "swgroup" so that
"swgroup's'" is used here. This "swgroups" is the term used in Tegra
TRM. Rename along with TRM.
Signed-off-by: Hiroshi Doyu <hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
drivers/iommu/tegra-smmu.c | 36 ++++++++++++++++++------------------
1 file changed, 18 insertions(+), 18 deletions(-)
diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c
index caa531cb1c50..5cb0e2a2b267 100644
--- a/drivers/iommu/tegra-smmu.c
+++ b/drivers/iommu/tegra-smmu.c
@@ -179,12 +179,12 @@ enum {
#define NUM_SMMU_REG_BANKS 3
-#define smmu_client_enable_hwgrp(c, m) smmu_client_set_hwgrp(c, m, 1)
-#define smmu_client_disable_hwgrp(c) smmu_client_set_hwgrp(c, 0, 0)
-#define __smmu_client_enable_hwgrp(c, m) __smmu_client_set_hwgrp(c, m, 1)
-#define __smmu_client_disable_hwgrp(c) __smmu_client_set_hwgrp(c, 0, 0)
+#define smmu_client_enable_swgroups(c, m) smmu_client_set_swgroups(c, m, 1)
+#define smmu_client_disable_swgroups(c) smmu_client_set_swgroups(c, 0, 0)
+#define __smmu_client_enable_swgroups(c, m) __smmu_client_set_swgroups(c, m, 1)
+#define __smmu_client_disable_swgroups(c) __smmu_client_set_swgroups(c, 0, 0)
-#define HWGRP_ASID_REG(x) ((x) * sizeof(u32) + SMMU_ASID_BASE)
+#define SWGROUPS_ASID_REG(x) ((x) * sizeof(u32) + SMMU_ASID_BASE)
/*
* Per client for address space
@@ -195,7 +195,7 @@ struct smmu_client {
struct device *dev;
struct list_head list;
struct smmu_as *as;
- unsigned long hwgrp[2];
+ unsigned long swgroups[2];
};
/*
@@ -377,7 +377,7 @@ static int register_smmu_client(struct smmu_device *smmu,
client->dev = dev;
client->of_node = dev->of_node;
- memcpy(client->hwgrp, swgroups, sizeof(u64));
+ memcpy(client->swgroups, swgroups, sizeof(u64));
return insert_smmu_client(smmu, client);
}
@@ -402,7 +402,7 @@ static int smmu_of_get_swgroups(struct device *dev, unsigned long *swgroups)
return -ENODEV;
}
-static int __smmu_client_set_hwgrp(struct smmu_client *c,
+static int __smmu_client_set_swgroups(struct smmu_client *c,
unsigned long *map, int on)
{
int i;
@@ -411,10 +411,10 @@ static int __smmu_client_set_hwgrp(struct smmu_client *c,
struct smmu_device *smmu = as->smmu;
if (!on)
- map = c->hwgrp;
+ map = c->swgroups;
for_each_set_bit(i, map, TEGRA_SWGROUP_MAX) {
- offs = HWGRP_ASID_REG(i);
+ offs = SWGROUPS_ASID_REG(i);
val = smmu_read(smmu, offs);
if (on) {
if (val) {
@@ -424,7 +424,7 @@ static int __smmu_client_set_hwgrp(struct smmu_client *c,
}
val = mask;
- memcpy(c->hwgrp, map, sizeof(u64));
+ memcpy(c->swgroups, map, sizeof(u64));
} else {
WARN_ON((val & mask) == mask);
val &= ~mask;
@@ -437,7 +437,7 @@ skip:
return 0;
}
-static int smmu_client_set_hwgrp(struct smmu_client *c,
+static int smmu_client_set_swgroups(struct smmu_client *c,
unsigned long *map, int on)
{
int err;
@@ -446,7 +446,7 @@ static int smmu_client_set_hwgrp(struct smmu_client *c,
struct smmu_device *smmu = as->smmu;
spin_lock_irqsave(&smmu->lock, flags);
- err = __smmu_client_set_hwgrp(c, map, on);
+ err = __smmu_client_set_swgroups(c, map, on);
spin_unlock_irqrestore(&smmu->lock, flags);
return err;
}
@@ -486,7 +486,7 @@ static int smmu_setup_regs(struct smmu_device *smmu)
smmu_write(smmu, val, SMMU_PTB_DATA);
list_for_each_entry(c, &as->client, list)
- __smmu_client_set_hwgrp(c, c->hwgrp, 1);
+ __smmu_client_set_swgroups(c, c->swgroups, 1);
}
smmu_write(smmu, smmu->translation_enable_0, SMMU_TRANSLATION_ENABLE_0);
@@ -814,7 +814,7 @@ static int smmu_iommu_attach_dev(struct iommu_domain *domain,
return -ENOMEM;
client->as = as;
- err = smmu_client_enable_hwgrp(client, client->hwgrp);
+ err = smmu_client_enable_swgroups(client, client->swgroups);
if (err)
return -EINVAL;
@@ -834,7 +834,7 @@ static int smmu_iommu_attach_dev(struct iommu_domain *domain,
* Reserve "page zero" for AVP vectors using a common dummy
* page.
*/
- if (test_bit(TEGRA_SWGROUP_AVPC, client->hwgrp)) {
+ if (test_bit(TEGRA_SWGROUP_AVPC, client->swgroups)) {
struct page *page;
page = as->smmu->avp_vector_page;
@@ -847,7 +847,7 @@ static int smmu_iommu_attach_dev(struct iommu_domain *domain,
return 0;
err_client:
- smmu_client_disable_hwgrp(client);
+ smmu_client_disable_swgroups(client);
spin_unlock(&as->client_lock);
return err;
}
@@ -863,7 +863,7 @@ static void smmu_iommu_detach_dev(struct iommu_domain *domain,
list_for_each_entry(c, &as->client, list) {
if (c->dev == dev) {
- smmu_client_disable_hwgrp(c);
+ smmu_client_disable_swgroups(c);
list_del(&c->list);
c->as = NULL;
dev_dbg(smmu->dev,
--
2.0.0.rc1.15.g7e76a2f
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCHv8 12/21] iommu/tegra: smmu: add SMMU to an global iommu list
[not found] ` <1401448834-32659-1-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
` (10 preceding siblings ...)
2014-05-30 11:20 ` [PATCHv8 11/21] iommu/tegra: smmu: Rename hwgrp -> swgroups Hiroshi Doyu
@ 2014-05-30 11:20 ` Hiroshi Doyu
2014-05-30 11:20 ` [PATCHv8 13/21] iommu/tegra124: smmu: optionaly AHB enables SMMU Hiroshi Doyu
` (8 subsequent siblings)
20 siblings, 0 replies; 31+ messages in thread
From: Hiroshi Doyu @ 2014-05-30 11:20 UTC (permalink / raw)
To: linux-tegra-u79uwXL29TY76Z2rM5mHXA
This allows to inquire if SMMU is populated or not.
Suggested by Thierry Reding and copied his example code.
Signed-off-by: Hiroshi Doyu <hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
Cc: Thierry Reding <thierry.reding-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
drivers/iommu/tegra-smmu.c | 53 +++++++++++++++++++++++++---------------------
1 file changed, 29 insertions(+), 24 deletions(-)
diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c
index 5cb0e2a2b267..4a326476c364 100644
--- a/drivers/iommu/tegra-smmu.c
+++ b/drivers/iommu/tegra-smmu.c
@@ -225,6 +225,8 @@ struct smmu_debugfs_info {
* Per SMMU device - IOMMU device
*/
struct smmu_device {
+ struct iommu iommu;
+
void __iomem *regbase; /* register offset base */
void __iomem **regs; /* register block start address array */
void __iomem **rege; /* register block end address array */
@@ -234,7 +236,6 @@ struct smmu_device {
unsigned long page_count; /* total remappable size */
spinlock_t lock;
char *name;
- struct device *dev;
struct rb_root clients;
struct page *avp_vector_page; /* dummy page shared by all AS's */
@@ -371,7 +372,7 @@ static int register_smmu_client(struct smmu_device *smmu,
return -EBUSY;
}
- client = devm_kzalloc(smmu->dev, sizeof(*client), GFP_KERNEL);
+ client = devm_kzalloc(smmu->iommu.dev, sizeof(*client), GFP_KERNEL);
if (!client)
return -ENOMEM;
@@ -526,7 +527,7 @@ static void free_ptbl(struct smmu_as *as, dma_addr_t iova)
unsigned long *pdir = (unsigned long *)page_address(as->pdir_page);
if (pdir[pdn] != _PDE_VACANT(pdn)) {
- dev_dbg(as->smmu->dev, "pdn: %lx\n", pdn);
+ dev_dbg(as->smmu->iommu.dev, "pdn: %lx\n", pdn);
ClearPageReserved(SMMU_EX_PTBL_PAGE(pdir[pdn]));
__free_page(SMMU_EX_PTBL_PAGE(pdir[pdn]));
@@ -541,7 +542,7 @@ static void free_pdir(struct smmu_as *as)
{
unsigned addr;
int count;
- struct device *dev = as->smmu->dev;
+ struct device *dev = as->smmu->iommu.dev;
if (!as->pdir_page)
return;
@@ -584,11 +585,11 @@ static unsigned long *locate_pte(struct smmu_as *as,
unsigned long addr = SMMU_PDN_TO_ADDR(pdn);
/* Vacant - allocate a new page table */
- dev_dbg(as->smmu->dev, "New PTBL pdn: %lx\n", pdn);
+ dev_dbg(as->smmu->iommu.dev, "New PTBL pdn: %lx\n", pdn);
*ptbl_page_p = alloc_page(GFP_ATOMIC);
if (!*ptbl_page_p) {
- dev_err(as->smmu->dev,
+ dev_err(as->smmu->iommu.dev,
"failed to allocate smmu_device page table\n");
return NULL;
}
@@ -648,7 +649,7 @@ static int alloc_pdir(struct smmu_as *as)
/*
* do the allocation, then grab as->lock
*/
- cnt = devm_kzalloc(smmu->dev,
+ cnt = devm_kzalloc(smmu->iommu.dev,
sizeof(cnt[0]) * SMMU_PDIR_COUNT,
GFP_KERNEL);
page = alloc_page(GFP_KERNEL | __GFP_DMA);
@@ -662,7 +663,8 @@ static int alloc_pdir(struct smmu_as *as)
}
if (!page || !cnt) {
- dev_err(smmu->dev, "failed to allocate at %s\n", __func__);
+ dev_err(smmu->iommu.dev,
+ "failed to allocate at %s\n", __func__);
err = -ENOMEM;
goto err_out;
}
@@ -692,7 +694,7 @@ static int alloc_pdir(struct smmu_as *as)
err_out:
spin_unlock_irqrestore(&as->lock, flags);
- devm_kfree(smmu->dev, cnt);
+ devm_kfree(smmu->iommu.dev, cnt);
if (page)
__free_page(page);
return err;
@@ -747,7 +749,7 @@ static int smmu_iommu_map(struct iommu_domain *domain, unsigned long iova,
unsigned long pfn = __phys_to_pfn(pa);
unsigned long flags;
- dev_dbg(as->smmu->dev, "[%d] %08lx:%pa\n", as->asid, iova, &pa);
+ dev_dbg(as->smmu->iommu.dev, "[%d] %08lx:%pa\n", as->asid, iova, &pa);
if (!pfn_valid(pfn))
return -ENOMEM;
@@ -764,7 +766,7 @@ static size_t smmu_iommu_unmap(struct iommu_domain *domain, unsigned long iova,
struct smmu_as *as = domain->priv;
unsigned long flags;
- dev_dbg(as->smmu->dev, "[%d] %08lx\n", as->asid, iova);
+ dev_dbg(as->smmu->iommu.dev, "[%d] %08lx\n", as->asid, iova);
spin_lock_irqsave(&as->lock, flags);
__smmu_iommu_unmap(as, iova);
@@ -787,7 +789,7 @@ static phys_addr_t smmu_iommu_iova_to_phys(struct iommu_domain *domain,
pte = locate_pte(as, iova, true, &page, &count);
pfn = *pte & SMMU_PFN_MASK;
WARN_ON(!pfn_valid(pfn));
- dev_dbg(as->smmu->dev,
+ dev_dbg(as->smmu->iommu.dev,
"iova:%08llx pfn:%08lx asid:%d\n", (unsigned long long)iova,
pfn, as->asid);
@@ -821,7 +823,7 @@ static int smmu_iommu_attach_dev(struct iommu_domain *domain,
spin_lock(&as->client_lock);
list_for_each_entry(c, &as->client, list) {
if (c->dev == dev) {
- dev_err(smmu->dev,
+ dev_err(smmu->iommu.dev,
"%s is already attached\n", dev_name(c->dev));
err = -EINVAL;
goto err_client;
@@ -843,7 +845,7 @@ static int smmu_iommu_attach_dev(struct iommu_domain *domain,
pr_info("Reserve \"page zero\" for AVP vectors using a common dummy\n");
}
- dev_dbg(smmu->dev, "%s is attached\n", dev_name(dev));
+ dev_dbg(smmu->iommu.dev, "%s is attached\n", dev_name(dev));
return 0;
err_client:
@@ -866,12 +868,12 @@ static void smmu_iommu_detach_dev(struct iommu_domain *domain,
smmu_client_disable_swgroups(c);
list_del(&c->list);
c->as = NULL;
- dev_dbg(smmu->dev,
+ dev_dbg(smmu->iommu.dev,
"%s is detached\n", dev_name(c->dev));
goto out;
}
}
- dev_err(smmu->dev, "Couldn't find %s\n", dev_name(dev));
+ dev_err(smmu->iommu.dev, "Couldn't find %s\n", dev_name(dev));
out:
spin_unlock(&as->client_lock);
}
@@ -898,7 +900,7 @@ static int smmu_iommu_domain_init(struct iommu_domain *domain)
break;
}
if (i == smmu->num_as)
- dev_err(smmu->dev, "no free AS\n");
+ dev_err(smmu->iommu.dev, "no free AS\n");
return err;
found:
@@ -919,7 +921,7 @@ found:
smmu->page_count * SMMU_PAGE_SIZE - 1;
domain->geometry.force_aperture = true;
- dev_dbg(smmu->dev, "smmu_as@%p\n", as);
+ dev_dbg(smmu->iommu.dev, "smmu_as@%p\n", as);
return 0;
}
@@ -952,7 +954,7 @@ static void smmu_iommu_domain_destroy(struct iommu_domain *domain)
spin_unlock_irqrestore(&as->lock, flags);
domain->priv = NULL;
- dev_dbg(smmu->dev, "smmu_as@%p\n", as);
+ dev_dbg(smmu->iommu.dev, "smmu_as@%p\n", as);
}
/*
@@ -1084,7 +1086,7 @@ static ssize_t smmu_debugfs_stats_write(struct file *file,
break;
}
- dev_dbg(smmu->dev, "%s() %08x, %08x @%08x\n", __func__,
+ dev_dbg(smmu->iommu.dev, "%s() %08x, %08x @%08x\n", __func__,
val, smmu_read(smmu, offs), offs);
return count;
@@ -1106,7 +1108,7 @@ static int smmu_debugfs_stats_show(struct seq_file *s, void *v)
val = smmu_read(smmu, offs);
seq_printf(s, "%s:%08x ", stats[i], val);
- dev_dbg(smmu->dev, "%s() %s %08x @%08x\n", __func__,
+ dev_dbg(smmu->iommu.dev, "%s() %s %08x @%08x\n", __func__,
stats[i], val, offs);
}
seq_printf(s, "\n");
@@ -1144,7 +1146,7 @@ static void smmu_debugfs_create(struct smmu_device *smmu)
if (!smmu->debugfs_info)
return;
- root = debugfs_create_dir(dev_name(smmu->dev), NULL);
+ root = debugfs_create_dir(dev_name(smmu->iommu.dev), NULL);
if (!root)
goto err_out;
smmu->debugfs_root = root;
@@ -1216,7 +1218,7 @@ static void tegra_smmu_create_default_map(struct smmu_device *smmu)
smmu->map[i] = arm_iommu_create_mapping(&platform_bus_type,
base, size);
if (IS_ERR(smmu->map[i]))
- dev_err(smmu->dev,
+ dev_err(smmu->iommu.dev,
"Couldn't create: asid=%d map=%p %pa-%pa\n",
i, smmu->map[i], &base, &base + size - 1);
}
@@ -1284,7 +1286,7 @@ static int tegra_smmu_probe(struct platform_device *pdev)
if (!smmu->ahb)
return -ENODEV;
- smmu->dev = dev;
+ smmu->iommu.dev = dev;
smmu->num_as = asids;
smmu->iovmm_base = base;
smmu->page_count = size;
@@ -1321,6 +1323,8 @@ static int tegra_smmu_probe(struct platform_device *pdev)
smmu_handle = smmu;
bus_set_iommu(&platform_bus_type, &smmu_iommu_ops);
tegra_smmu_create_default_map(smmu);
+
+ iommu_add(&smmu->iommu);
return 0;
}
@@ -1336,6 +1340,7 @@ static int tegra_smmu_remove(struct platform_device *pdev)
free_pdir(&smmu->as[i]);
__free_page(smmu->avp_vector_page);
smmu_handle = NULL;
+ iommu_del(&smmu->iommu);
return 0;
}
--
2.0.0.rc1.15.g7e76a2f
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCHv8 13/21] iommu/tegra124: smmu: optionaly AHB enables SMMU
[not found] ` <1401448834-32659-1-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
` (11 preceding siblings ...)
2014-05-30 11:20 ` [PATCHv8 12/21] iommu/tegra: smmu: add SMMU to an global iommu list Hiroshi Doyu
@ 2014-05-30 11:20 ` Hiroshi Doyu
2014-05-30 11:20 ` [PATCHv8 14/21] iommu/tegra124: smmu: convert swgroup ID to asid offset Hiroshi Doyu
` (7 subsequent siblings)
20 siblings, 0 replies; 31+ messages in thread
From: Hiroshi Doyu @ 2014-05-30 11:20 UTC (permalink / raw)
To: linux-tegra-u79uwXL29TY76Z2rM5mHXA
SMMU used to depend on AHB bus. AHB driver needs to be populated and
AHB_XBAR_CTRL_SMMU_INIT_DONE bit needs to be set earliear than SMMU
being populated. Later Tegra SoC (>= T124) doesn't need AHB to enable
SMMU on AHB_XBAR_CTRL for AHB_XBAR_CTRL_SMMU_INIT_DONE any more. This
setting bit is now optional, depending on DT passing ahb phandle or
not.
Signed-off-by: Hiroshi Doyu <hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
drivers/iommu/tegra-smmu.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c
index 4a326476c364..20dddc305fb2 100644
--- a/drivers/iommu/tegra-smmu.c
+++ b/drivers/iommu/tegra-smmu.c
@@ -499,7 +499,10 @@ static int smmu_setup_regs(struct smmu_device *smmu)
smmu_flush_regs(smmu, 1);
- return tegra_ahb_enable_smmu(smmu->ahb);
+ if (smmu->ahb)
+ return tegra_ahb_enable_smmu(smmu->ahb);
+
+ return 0;
}
static void flush_ptc_and_tlb(struct smmu_device *smmu,
@@ -1283,9 +1286,6 @@ static int tegra_smmu_probe(struct platform_device *pdev)
return -EINVAL;
smmu->ahb = of_parse_phandle(dev->of_node, "nvidia,ahb", 0);
- if (!smmu->ahb)
- return -ENODEV;
-
smmu->iommu.dev = dev;
smmu->num_as = asids;
smmu->iovmm_base = base;
--
2.0.0.rc1.15.g7e76a2f
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCHv8 14/21] iommu/tegra124: smmu: convert swgroup ID to asid offset
[not found] ` <1401448834-32659-1-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
` (12 preceding siblings ...)
2014-05-30 11:20 ` [PATCHv8 13/21] iommu/tegra124: smmu: optionaly AHB enables SMMU Hiroshi Doyu
@ 2014-05-30 11:20 ` Hiroshi Doyu
2014-05-30 11:20 ` [PATCHv8 15/21] iommu/tegra124: smmu: add support platform data Hiroshi Doyu
` (6 subsequent siblings)
20 siblings, 0 replies; 31+ messages in thread
From: Hiroshi Doyu @ 2014-05-30 11:20 UTC (permalink / raw)
To: linux-tegra-u79uwXL29TY76Z2rM5mHXA
Provide a conversion table from swgroup ID to MC_SMMU_<swgroup
name>_ASID_0 register offset to support non-linear conversion. This
conversion used to be exactly linear but after T124 we need a
conversion table to support non-linear cases. We would also need
another table to convert swgroup ID to HOTRESET bit.
Signed-off-by: Hiroshi Doyu <hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
drivers/iommu/tegra-smmu.c | 21 ++++++++++++++++++---
1 file changed, 18 insertions(+), 3 deletions(-)
diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c
index 20dddc305fb2..080dbda874e5 100644
--- a/drivers/iommu/tegra-smmu.c
+++ b/drivers/iommu/tegra-smmu.c
@@ -184,8 +184,6 @@ enum {
#define __smmu_client_enable_swgroups(c, m) __smmu_client_set_swgroups(c, m, 1)
#define __smmu_client_disable_swgroups(c) __smmu_client_set_swgroups(c, 0, 0)
-#define SWGROUPS_ASID_REG(x) ((x) * sizeof(u32) + SMMU_ASID_BASE)
-
/*
* Per client for address space
*/
@@ -314,6 +312,23 @@ static inline void smmu_write(struct smmu_device *smmu, u32 val, size_t offs)
*/
#define FLUSH_SMMU_REGS(smmu) smmu_read(smmu, SMMU_CONFIG)
+static size_t smmu_get_asid_offset(int id)
+{
+ switch (id) {
+ case TEGRA_SWGROUP_DC14:
+ return 0x490;
+ case TEGRA_SWGROUP_DC12:
+ return 0xa88;
+ case TEGRA_SWGROUP_AFI...TEGRA_SWGROUP_ISP:
+ case TEGRA_SWGROUP_MPE...TEGRA_SWGROUP_PPCS1:
+ return (id - TEGRA_SWGROUP_AFI) * sizeof(u32) + SMMU_ASID_BASE;
+ case TEGRA_SWGROUP_SDMMC1A...63:
+ return (id - TEGRA_SWGROUP_SDMMC1A) * sizeof(u32) + 0xa94;
+ };
+
+ BUG();
+}
+
static struct smmu_client *find_smmu_client(struct smmu_device *smmu,
struct device_node *dev_node)
{
@@ -415,7 +430,7 @@ static int __smmu_client_set_swgroups(struct smmu_client *c,
map = c->swgroups;
for_each_set_bit(i, map, TEGRA_SWGROUP_MAX) {
- offs = SWGROUPS_ASID_REG(i);
+ offs = smmu_get_asid_offset(i);
val = smmu_read(smmu, offs);
if (on) {
if (val) {
--
2.0.0.rc1.15.g7e76a2f
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCHv8 15/21] iommu/tegra124: smmu: add support platform data
[not found] ` <1401448834-32659-1-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
` (13 preceding siblings ...)
2014-05-30 11:20 ` [PATCHv8 14/21] iommu/tegra124: smmu: convert swgroup ID to asid offset Hiroshi Doyu
@ 2014-05-30 11:20 ` Hiroshi Doyu
[not found] ` <1401448834-32659-16-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2014-05-30 11:20 ` [PATCHv8 16/21] iommu/tegra124: smmu: support more than 32 bit pa Hiroshi Doyu
` (5 subsequent siblings)
20 siblings, 1 reply; 31+ messages in thread
From: Hiroshi Doyu @ 2014-05-30 11:20 UTC (permalink / raw)
To: linux-tegra-u79uwXL29TY76Z2rM5mHXA
The later Tegra SoC(>= T124) has more registers for
MC_SMMU_TRANSLATION_ENABLE_*. Now those info is provided as platfrom
data. If those varies a lot on SoCs in the future, we can consider
putting them into DT later.
Signed-off-by: Hiroshi Doyu <hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
.../bindings/iommu/nvidia,tegra30-smmu.txt | 4 +-
drivers/iommu/tegra-smmu.c | 68 ++++++++++++++--------
2 files changed, 47 insertions(+), 25 deletions(-)
diff --git a/Documentation/devicetree/bindings/iommu/nvidia,tegra30-smmu.txt b/Documentation/devicetree/bindings/iommu/nvidia,tegra30-smmu.txt
index 89fb5434b730..38b444ff1d4c 100644
--- a/Documentation/devicetree/bindings/iommu/nvidia,tegra30-smmu.txt
+++ b/Documentation/devicetree/bindings/iommu/nvidia,tegra30-smmu.txt
@@ -1,8 +1,8 @@
NVIDIA Tegra 30 IOMMU H/W, SMMU (System Memory Management Unit)
Required properties:
-- compatible : "nvidia,tegra30-smmu"
-- reg : Should contain 3 register banks(address and length) for each
+- compatible : "nvidia,tegra124-smmu", "nvidia,tegra30-smmu"
+- reg : Can contain multiple register banks(address and length) for each
of the SMMU register blocks.
- interrupts : Should contain MC General interrupt.
- nvidia,#asids : # of ASIDs
diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c
index 080dbda874e5..12a4a8f68538 100644
--- a/drivers/iommu/tegra-smmu.c
+++ b/drivers/iommu/tegra-smmu.c
@@ -32,6 +32,7 @@
#include <linux/iommu.h>
#include <linux/io.h>
#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/of_iommu.h>
#include <linux/debugfs.h>
#include <linux/seq_file.h>
@@ -108,8 +109,6 @@ enum {
(SMMU_STATS_CACHE_COUNT_BASE + 8 * cache + 4 * hitmiss)
#define SMMU_TRANSLATION_ENABLE_0 0x228
-#define SMMU_TRANSLATION_ENABLE_1 0x22c
-#define SMMU_TRANSLATION_ENABLE_2 0x230
#define SMMU_AFI_ASID 0x238 /* PCIE */
#define SMMU_ASID_BASE SMMU_AFI_ASID
@@ -237,12 +236,12 @@ struct smmu_device {
struct rb_root clients;
struct page *avp_vector_page; /* dummy page shared by all AS's */
+ int nr_xlats; /* number of translation_enable registers */
+
/*
* Register image savers for suspend/resume
*/
- unsigned long translation_enable_0;
- unsigned long translation_enable_1;
- unsigned long translation_enable_2;
+ u32 *xlat;
unsigned long asid_security;
struct dentry *debugfs_root;
@@ -256,6 +255,11 @@ struct smmu_device {
struct smmu_as as[0]; /* Run-time allocated array */
};
+struct smmu_platform_data {
+ int asids; /* number of asids */
+ int nr_xlats; /* number of translation_enable registers */
+};
+
static struct smmu_device *smmu_handle; /* unique for a system */
/*
@@ -505,9 +509,10 @@ static int smmu_setup_regs(struct smmu_device *smmu)
__smmu_client_set_swgroups(c, c->swgroups, 1);
}
- smmu_write(smmu, smmu->translation_enable_0, SMMU_TRANSLATION_ENABLE_0);
- smmu_write(smmu, smmu->translation_enable_1, SMMU_TRANSLATION_ENABLE_1);
- smmu_write(smmu, smmu->translation_enable_2, SMMU_TRANSLATION_ENABLE_2);
+ for (i = 0; i < smmu->nr_xlats; i++)
+ smmu_write(smmu, smmu->xlat[i],
+ SMMU_TRANSLATION_ENABLE_0 + i * sizeof(u32));
+
smmu_write(smmu, smmu->asid_security, SMMU_ASID_SECURITY);
smmu_write(smmu, SMMU_TLB_CONFIG_RESET_VAL, SMMU_CACHE_CONFIG(_TLB));
smmu_write(smmu, SMMU_PTC_CONFIG_RESET_VAL, SMMU_CACHE_CONFIG(_PTC));
@@ -1204,11 +1209,13 @@ err_out:
static int tegra_smmu_suspend(struct device *dev)
{
+ int i;
struct smmu_device *smmu = dev_get_drvdata(dev);
- smmu->translation_enable_0 = smmu_read(smmu, SMMU_TRANSLATION_ENABLE_0);
- smmu->translation_enable_1 = smmu_read(smmu, SMMU_TRANSLATION_ENABLE_1);
- smmu->translation_enable_2 = smmu_read(smmu, SMMU_TRANSLATION_ENABLE_2);
+ for (i = 0; i < smmu->nr_xlats; i++)
+ smmu->xlat[i] = smmu_read(smmu,
+ SMMU_TRANSLATION_ENABLE_0 + i * sizeof(u32));
+
smmu->asid_security = smmu_read(smmu, SMMU_ASID_SECURITY);
return 0;
}
@@ -1242,6 +1249,18 @@ static void tegra_smmu_create_default_map(struct smmu_device *smmu)
}
}
+static const struct smmu_platform_data tegra124_smmu_pdata = {
+ .asids = 128,
+ .nr_xlats = 4,
+};
+
+static struct of_device_id tegra_smmu_of_match[] = {
+ { .compatible = "nvidia,tegra124-smmu", .data = &tegra124_smmu_pdata, },
+ { .compatible = "nvidia,tegra30-smmu", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, tegra_smmu_of_match);
+
static int tegra_smmu_probe(struct platform_device *pdev)
{
struct smmu_device *smmu;
@@ -1249,20 +1268,29 @@ static int tegra_smmu_probe(struct platform_device *pdev)
int i, asids, err = 0;
dma_addr_t uninitialized_var(base);
size_t bytes, uninitialized_var(size);
+ const struct of_device_id *match;
+ const struct smmu_platform_data *pdata;
+ int nr_xlats;
if (smmu_handle)
return -EIO;
BUILD_BUG_ON(PAGE_SHIFT != SMMU_PAGE_SHIFT);
- if (of_property_read_u32(dev->of_node, "nvidia,#asids", &asids))
- return -ENODEV;
+ match = of_match_device(tegra_smmu_of_match, &pdev->dev);
+ if (!match)
+ return -EINVAL;
+ pdata = match->data;
+ nr_xlats = (pdata && pdata->nr_xlats) ? pdata->nr_xlats : 3;
+ if (of_property_read_u32(dev->of_node, "nvidia,#asids", &asids))
+ asids = (pdata && pdata->asids) ? pdata->asids : 4;
if (asids < NUM_OF_STATIC_MAPS)
return -EINVAL;
bytes = sizeof(*smmu) + asids * (sizeof(*smmu->as) +
sizeof(struct dma_iommu_mapping *));
+ bytes += sizeof(u32) * nr_xlats;
smmu = devm_kzalloc(dev, bytes, GFP_KERNEL);
if (!smmu) {
dev_err(dev, "failed to allocate smmu_device\n");
@@ -1271,6 +1299,7 @@ static int tegra_smmu_probe(struct platform_device *pdev)
smmu->clients = RB_ROOT;
smmu->map = (struct dma_iommu_mapping **)(smmu->as + asids);
+ smmu->xlat = (u32 *)(smmu->map + smmu->num_as);
smmu->nregs = pdev->num_resources;
smmu->regs = devm_kzalloc(dev, 2 * smmu->nregs * sizeof(*smmu->regs),
GFP_KERNEL);
@@ -1303,13 +1332,12 @@ static int tegra_smmu_probe(struct platform_device *pdev)
smmu->ahb = of_parse_phandle(dev->of_node, "nvidia,ahb", 0);
smmu->iommu.dev = dev;
smmu->num_as = asids;
+ smmu->nr_xlats = nr_xlats;
smmu->iovmm_base = base;
smmu->page_count = size;
-
- smmu->translation_enable_0 = ~0;
- smmu->translation_enable_1 = ~0;
- smmu->translation_enable_2 = ~0;
smmu->asid_security = 0;
+ for (i = 0; i < smmu->nr_xlats; i++)
+ smmu->xlat[i] = ~0;
for (i = 0; i < smmu->num_as; i++) {
struct smmu_as *as = &smmu->as[i];
@@ -1364,12 +1392,6 @@ static const struct dev_pm_ops tegra_smmu_pm_ops = {
.resume = tegra_smmu_resume,
};
-static struct of_device_id tegra_smmu_of_match[] = {
- { .compatible = "nvidia,tegra30-smmu", },
- { },
-};
-MODULE_DEVICE_TABLE(of, tegra_smmu_of_match);
-
static struct platform_driver tegra_smmu_driver = {
.probe = tegra_smmu_probe,
.remove = tegra_smmu_remove,
--
2.0.0.rc1.15.g7e76a2f
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCHv8 16/21] iommu/tegra124: smmu: support more than 32 bit pa
[not found] ` <1401448834-32659-1-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
` (14 preceding siblings ...)
2014-05-30 11:20 ` [PATCHv8 15/21] iommu/tegra124: smmu: add support platform data Hiroshi Doyu
@ 2014-05-30 11:20 ` Hiroshi Doyu
2014-05-30 11:20 ` [PATCHv8 17/21] iommu/tegra124: smmu: {TLB,PTC} reset value per SoC Hiroshi Doyu
` (4 subsequent siblings)
20 siblings, 0 replies; 31+ messages in thread
From: Hiroshi Doyu @ 2014-05-30 11:20 UTC (permalink / raw)
To: linux-tegra-u79uwXL29TY76Z2rM5mHXA
Add support for more than 32 bit physical address. If physical
address space is 32bit, there will be no register write
happening. Based on Pavan's internal patch.
Signed-off-by: Hiroshi Doyu <hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
Cc: Pavan Kunapuli <pkunapuli-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
Cc: Mark Zhang <markz-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
drivers/iommu/tegra-smmu.c | 36 +++++++++++++++++++++++++++++-------
1 file changed, 29 insertions(+), 7 deletions(-)
diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c
index 12a4a8f68538..24fe16f1a1d8 100644
--- a/drivers/iommu/tegra-smmu.c
+++ b/drivers/iommu/tegra-smmu.c
@@ -101,6 +101,8 @@ enum {
#define SMMU_PTC_FLUSH_TYPE_ADR 1
#define SMMU_PTC_FLUSH_ADR_SHIFT 4
+#define SMMU_PTC_FLUSH_1 0x9b8
+
#define SMMU_ASID_SECURITY 0x38
#define SMMU_STATS_CACHE_COUNT_BASE 0x1f0
@@ -143,7 +145,7 @@ enum {
#define SMMU_PDIR_SHIFT 12
#define SMMU_PDE_SHIFT 12
#define SMMU_PTE_SHIFT 12
-#define SMMU_PFN_MASK 0x000fffff
+#define SMMU_PFN_MASK 0x0fffffff
#define SMMU_ADDR_TO_PFN(addr) ((addr) >> 12)
#define SMMU_ADDR_TO_PDN(addr) ((addr) >> 22)
@@ -258,6 +260,7 @@ struct smmu_device {
struct smmu_platform_data {
int asids; /* number of asids */
int nr_xlats; /* number of translation_enable registers */
+ bool lpae; /* PA > 32 bit */
};
static struct smmu_device *smmu_handle; /* unique for a system */
@@ -301,6 +304,8 @@ static inline void smmu_write(struct smmu_device *smmu, u32 val, size_t offs)
#define VA_PAGE_TO_PA(va, page) \
(page_to_phys(page) + ((unsigned long)(va) & ~PAGE_MASK))
+#define VA_PAGE_TO_PA_HI(va, page) (u32)((u64)page_to_phys(page) >> 32)
+
#define FLUSH_CPU_DCACHE(va, page, size) \
do { \
unsigned long _pa_ = VA_PAGE_TO_PA(va, page); \
@@ -525,6 +530,20 @@ static int smmu_setup_regs(struct smmu_device *smmu)
return 0;
}
+static void flush_ptc_by_addr(struct smmu_device *smmu, unsigned long *pte,
+ struct page *page)
+{
+ u32 val;
+
+ val = VA_PAGE_TO_PA_HI(pte, page);
+ smmu_write(smmu, val, SMMU_PTC_FLUSH_1);
+
+ val = SMMU_PTC_FLUSH_TYPE_ADR | VA_PAGE_TO_PA(pte, page);
+ smmu_write(smmu, val, SMMU_PTC_FLUSH);
+
+ FLUSH_SMMU_REGS(smmu);
+}
+
static void flush_ptc_and_tlb(struct smmu_device *smmu,
struct smmu_as *as, dma_addr_t iova,
unsigned long *pte, struct page *page, int is_pde)
@@ -534,9 +553,8 @@ static void flush_ptc_and_tlb(struct smmu_device *smmu,
? SMMU_TLB_FLUSH_VA(iova, SECTION)
: SMMU_TLB_FLUSH_VA(iova, GROUP);
- val = SMMU_PTC_FLUSH_TYPE_ADR | VA_PAGE_TO_PA(pte, page);
- smmu_write(smmu, val, SMMU_PTC_FLUSH);
- FLUSH_SMMU_REGS(smmu);
+ flush_ptc_by_addr(smmu, pte, page);
+
val = tlb_flush_va |
SMMU_TLB_FLUSH_ASID_MATCH__ENABLE |
(as->asid << SMMU_TLB_FLUSH_ASID_SHIFT);
@@ -701,9 +719,9 @@ static int alloc_pdir(struct smmu_as *as)
for (pdn = 0; pdn < SMMU_PDIR_COUNT; pdn++)
pdir[pdn] = _PDE_VACANT(pdn);
FLUSH_CPU_DCACHE(pdir, as->pdir_page, SMMU_PDIR_SIZE);
- val = SMMU_PTC_FLUSH_TYPE_ADR | VA_PAGE_TO_PA(pdir, as->pdir_page);
- smmu_write(smmu, val, SMMU_PTC_FLUSH);
- FLUSH_SMMU_REGS(as->smmu);
+
+ flush_ptc_by_addr(as->smmu, pdir, page);
+
val = SMMU_TLB_FLUSH_VA_MATCH_ALL |
SMMU_TLB_FLUSH_ASID_MATCH__ENABLE |
(as->asid << SMMU_TLB_FLUSH_ASID_SHIFT);
@@ -1252,6 +1270,10 @@ static void tegra_smmu_create_default_map(struct smmu_device *smmu)
static const struct smmu_platform_data tegra124_smmu_pdata = {
.asids = 128,
.nr_xlats = 4,
+ .lpae = true,
+ .nr_asid_secs = 8,
+ .tlb_reset = SMMU_TLB_CONFIG_RESET_VAL | SMMU_TLB_RR_ARB | 0x20,
+ .ptc_reset = SMMU_PTC_CONFIG_RESET_VAL | SMMU_PTC_REQ_LIMIT,
};
static struct of_device_id tegra_smmu_of_match[] = {
--
2.0.0.rc1.15.g7e76a2f
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCHv8 17/21] iommu/tegra124: smmu: {TLB,PTC} reset value per SoC
[not found] ` <1401448834-32659-1-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
` (15 preceding siblings ...)
2014-05-30 11:20 ` [PATCHv8 16/21] iommu/tegra124: smmu: support more than 32 bit pa Hiroshi Doyu
@ 2014-05-30 11:20 ` Hiroshi Doyu
2014-05-30 11:20 ` [PATCHv8 18/21] iommu/tegra124: smmu: adjust TLB_FLUSH_ASID bit range Hiroshi Doyu
` (3 subsequent siblings)
20 siblings, 0 replies; 31+ messages in thread
From: Hiroshi Doyu @ 2014-05-30 11:20 UTC (permalink / raw)
To: linux-tegra-u79uwXL29TY76Z2rM5mHXA
T124 has some new register bits in {TLB,PTC}_CONFIG:
- TLB_RR_ARB and PTC_REQ_LIMIT
- TLB_ACTIVE_LINES 0x20 instead of 0x10
They are defined as platform data now.
Signed-off-by: Hiroshi Doyu <hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
drivers/iommu/tegra-smmu.c | 17 +++++++++++++----
1 file changed, 13 insertions(+), 4 deletions(-)
diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c
index 24fe16f1a1d8..7f13133eab0a 100644
--- a/drivers/iommu/tegra-smmu.c
+++ b/drivers/iommu/tegra-smmu.c
@@ -71,12 +71,13 @@ enum {
#define SMMU_CACHE_CONFIG_STATS_TEST (1 << SMMU_CACHE_CONFIG_STATS_TEST_SHIFT)
#define SMMU_TLB_CONFIG_HIT_UNDER_MISS__ENABLE (1 << 29)
-#define SMMU_TLB_CONFIG_ACTIVE_LINES__VALUE 0x10
-#define SMMU_TLB_CONFIG_RESET_VAL 0x20000010
+#define SMMU_TLB_CONFIG_RESET_VAL 0x20000000
+#define SMMU_TLB_RR_ARB (1 << 28)
#define SMMU_PTC_CONFIG_CACHE__ENABLE (1 << 29)
#define SMMU_PTC_CONFIG_INDEX_MAP__PATTERN 0x3f
#define SMMU_PTC_CONFIG_RESET_VAL 0x2000003f
+#define SMMU_PTC_REQ_LIMIT (8 << 24)
#define SMMU_PTB_ASID 0x1c
#define SMMU_PTB_ASID_CURRENT_SHIFT 0
@@ -239,6 +240,8 @@ struct smmu_device {
struct page *avp_vector_page; /* dummy page shared by all AS's */
int nr_xlats; /* number of translation_enable registers */
+ u32 tlb_reset; /* TLB config reset value */
+ u32 ptc_reset; /* PTC config reset value */
/*
* Register image savers for suspend/resume
@@ -261,6 +264,8 @@ struct smmu_platform_data {
int asids; /* number of asids */
int nr_xlats; /* number of translation_enable registers */
bool lpae; /* PA > 32 bit */
+ u32 tlb_reset; /* TLB config reset value */
+ u32 ptc_reset; /* PTC config reset value */
};
static struct smmu_device *smmu_handle; /* unique for a system */
@@ -519,8 +524,8 @@ static int smmu_setup_regs(struct smmu_device *smmu)
SMMU_TRANSLATION_ENABLE_0 + i * sizeof(u32));
smmu_write(smmu, smmu->asid_security, SMMU_ASID_SECURITY);
- smmu_write(smmu, SMMU_TLB_CONFIG_RESET_VAL, SMMU_CACHE_CONFIG(_TLB));
- smmu_write(smmu, SMMU_PTC_CONFIG_RESET_VAL, SMMU_CACHE_CONFIG(_PTC));
+ smmu_write(smmu, smmu->ptc_reset, SMMU_CACHE_CONFIG(_PTC));
+ smmu_write(smmu, smmu->tlb_reset, SMMU_CACHE_CONFIG(_TLB));
smmu_flush_regs(smmu, 1);
@@ -1323,6 +1328,10 @@ static int tegra_smmu_probe(struct platform_device *pdev)
smmu->map = (struct dma_iommu_mapping **)(smmu->as + asids);
smmu->xlat = (u32 *)(smmu->map + smmu->num_as);
smmu->nregs = pdev->num_resources;
+ smmu->tlb_reset = (pdata && pdata->tlb_reset) ? pdata->tlb_reset :
+ (SMMU_TLB_CONFIG_RESET_VAL | 0x10);
+ smmu->ptc_reset = (pdata && pdata->ptc_reset) ? pdata->ptc_reset :
+ (SMMU_PTC_CONFIG_RESET_VAL | SMMU_PTC_REQ_LIMIT);
smmu->regs = devm_kzalloc(dev, 2 * smmu->nregs * sizeof(*smmu->regs),
GFP_KERNEL);
smmu->rege = smmu->regs + smmu->nregs;
--
2.0.0.rc1.15.g7e76a2f
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCHv8 18/21] iommu/tegra124: smmu: adjust TLB_FLUSH_ASID bit range
[not found] ` <1401448834-32659-1-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
` (16 preceding siblings ...)
2014-05-30 11:20 ` [PATCHv8 17/21] iommu/tegra124: smmu: {TLB,PTC} reset value per SoC Hiroshi Doyu
@ 2014-05-30 11:20 ` Hiroshi Doyu
2014-05-30 11:20 ` [PATCHv8 19/21] iommu/tegra124: smmu: add multiple asid_security support Hiroshi Doyu
` (2 subsequent siblings)
20 siblings, 0 replies; 31+ messages in thread
From: Hiroshi Doyu @ 2014-05-30 11:20 UTC (permalink / raw)
To: linux-tegra-u79uwXL29TY76Z2rM5mHXA
TLB_FLUSH_ASID bit range depends on the number of asids to support
other number than the current 4, especially for a new Tegra124. Based
on Terje's internal patch.
Signed-off-by: Hiroshi Doyu <hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
Cc: Terje Bergstrom <tbergstrom-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
drivers/iommu/tegra-smmu.c | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c
index 7f13133eab0a..f499ca1f8498 100644
--- a/drivers/iommu/tegra-smmu.c
+++ b/drivers/iommu/tegra-smmu.c
@@ -92,11 +92,14 @@ enum {
#define SMMU_TLB_FLUSH_VA_MATCH_ALL 0
#define SMMU_TLB_FLUSH_VA_MATCH_SECTION 2
#define SMMU_TLB_FLUSH_VA_MATCH_GROUP 3
-#define SMMU_TLB_FLUSH_ASID_SHIFT 29
+#define SMMU_TLB_FLUSH_ASID_SHIFT_BASE 31
#define SMMU_TLB_FLUSH_ASID_MATCH_DISABLE 0
#define SMMU_TLB_FLUSH_ASID_MATCH_ENABLE 1
#define SMMU_TLB_FLUSH_ASID_MATCH_SHIFT 31
+#define SMMU_TLB_FLUSH_ASID_SHIFT(as) \
+ (SMMU_TLB_FLUSH_ASID_SHIFT_BASE - __ffs((as)->smmu->num_as))
+
#define SMMU_PTC_FLUSH 0x34
#define SMMU_PTC_FLUSH_TYPE_ALL 0
#define SMMU_PTC_FLUSH_TYPE_ADR 1
@@ -562,7 +565,7 @@ static void flush_ptc_and_tlb(struct smmu_device *smmu,
val = tlb_flush_va |
SMMU_TLB_FLUSH_ASID_MATCH__ENABLE |
- (as->asid << SMMU_TLB_FLUSH_ASID_SHIFT);
+ (as->asid << SMMU_TLB_FLUSH_ASID_SHIFT(as));
smmu_write(smmu, val, SMMU_TLB_FLUSH);
FLUSH_SMMU_REGS(smmu);
}
@@ -729,7 +732,7 @@ static int alloc_pdir(struct smmu_as *as)
val = SMMU_TLB_FLUSH_VA_MATCH_ALL |
SMMU_TLB_FLUSH_ASID_MATCH__ENABLE |
- (as->asid << SMMU_TLB_FLUSH_ASID_SHIFT);
+ (as->asid << SMMU_TLB_FLUSH_ASID_SHIFT(as));
smmu_write(smmu, val, SMMU_TLB_FLUSH);
FLUSH_SMMU_REGS(as->smmu);
--
2.0.0.rc1.15.g7e76a2f
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCHv8 19/21] iommu/tegra124: smmu: add multiple asid_security support
[not found] ` <1401448834-32659-1-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
` (17 preceding siblings ...)
2014-05-30 11:20 ` [PATCHv8 18/21] iommu/tegra124: smmu: adjust TLB_FLUSH_ASID bit range Hiroshi Doyu
@ 2014-05-30 11:20 ` Hiroshi Doyu
2014-05-30 11:20 ` [PATCHv8 20/21] ARM: dt: tegra124: add tegra,smmu entry Hiroshi Doyu
2014-05-30 11:20 ` [PATCHv8 21/21] ARM: dt: tegra124: add sdhci iommus bindings Hiroshi Doyu
20 siblings, 0 replies; 31+ messages in thread
From: Hiroshi Doyu @ 2014-05-30 11:20 UTC (permalink / raw)
To: linux-tegra-u79uwXL29TY76Z2rM5mHXA
In Tegra124 the number of MC_SMMU_ASID_SECURITY_# registers
increased. Now this info is provided as platfrom data. If no platfrom
data the default valude(1) is used.
Signed-off-by: Hiroshi Doyu <hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
drivers/iommu/tegra-smmu.c | 38 ++++++++++++++++++++++++++++++++------
1 file changed, 32 insertions(+), 6 deletions(-)
diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c
index f499ca1f8498..53a64a1ac24d 100644
--- a/drivers/iommu/tegra-smmu.c
+++ b/drivers/iommu/tegra-smmu.c
@@ -108,6 +108,13 @@ enum {
#define SMMU_PTC_FLUSH_1 0x9b8
#define SMMU_ASID_SECURITY 0x38
+#define SMMU_ASID_SECURITY_1 0x3c
+#define SMMU_ASID_SECURITY_2 0x9e0
+#define SMMU_ASID_SECURITY_3 0x9e4
+#define SMMU_ASID_SECURITY_4 0x9e8
+#define SMMU_ASID_SECURITY_5 0x9ec
+#define SMMU_ASID_SECURITY_6 0x9f0
+#define SMMU_ASID_SECURITY_7 0x9f4
#define SMMU_STATS_CACHE_COUNT_BASE 0x1f0
@@ -243,6 +250,7 @@ struct smmu_device {
struct page *avp_vector_page; /* dummy page shared by all AS's */
int nr_xlats; /* number of translation_enable registers */
+ int nr_asid_secs; /* number of asid_security registers */
u32 tlb_reset; /* TLB config reset value */
u32 ptc_reset; /* PTC config reset value */
@@ -250,7 +258,7 @@ struct smmu_device {
* Register image savers for suspend/resume
*/
u32 *xlat;
- unsigned long asid_security;
+ u32 *asid_sec;
struct dentry *debugfs_root;
struct smmu_debugfs_info *debugfs_info;
@@ -267,6 +275,7 @@ struct smmu_platform_data {
int asids; /* number of asids */
int nr_xlats; /* number of translation_enable registers */
bool lpae; /* PA > 32 bit */
+ int nr_asid_secs; /* number of asid_security registers */
u32 tlb_reset; /* TLB config reset value */
u32 ptc_reset; /* PTC config reset value */
};
@@ -329,6 +338,17 @@ static inline void smmu_write(struct smmu_device *smmu, u32 val, size_t offs)
*/
#define FLUSH_SMMU_REGS(smmu) smmu_read(smmu, SMMU_CONFIG)
+static const u32 smmu_asid_sec_ofs[] = {
+ SMMU_ASID_SECURITY,
+ SMMU_ASID_SECURITY_1,
+ SMMU_ASID_SECURITY_2,
+ SMMU_ASID_SECURITY_3,
+ SMMU_ASID_SECURITY_4,
+ SMMU_ASID_SECURITY_5,
+ SMMU_ASID_SECURITY_6,
+ SMMU_ASID_SECURITY_7,
+};
+
static size_t smmu_get_asid_offset(int id)
{
switch (id) {
@@ -526,7 +546,9 @@ static int smmu_setup_regs(struct smmu_device *smmu)
smmu_write(smmu, smmu->xlat[i],
SMMU_TRANSLATION_ENABLE_0 + i * sizeof(u32));
- smmu_write(smmu, smmu->asid_security, SMMU_ASID_SECURITY);
+ for (i = 0; i < smmu->nr_asid_secs; i++)
+ smmu_write(smmu, smmu->asid_sec[i], smmu_asid_sec_ofs[i]);
+
smmu_write(smmu, smmu->ptc_reset, SMMU_CACHE_CONFIG(_PTC));
smmu_write(smmu, smmu->tlb_reset, SMMU_CACHE_CONFIG(_TLB));
@@ -1242,7 +1264,9 @@ static int tegra_smmu_suspend(struct device *dev)
smmu->xlat[i] = smmu_read(smmu,
SMMU_TRANSLATION_ENABLE_0 + i * sizeof(u32));
- smmu->asid_security = smmu_read(smmu, SMMU_ASID_SECURITY);
+ for (i = 0; i < smmu->nr_asid_secs; i++)
+ smmu->asid_sec[i] =
+ smmu_read(smmu, smmu_asid_sec_ofs[i]);
return 0;
}
@@ -1300,7 +1324,7 @@ static int tegra_smmu_probe(struct platform_device *pdev)
size_t bytes, uninitialized_var(size);
const struct of_device_id *match;
const struct smmu_platform_data *pdata;
- int nr_xlats;
+ int nr_xlats, nr_asid_secs;
if (smmu_handle)
return -EIO;
@@ -1312,6 +1336,7 @@ static int tegra_smmu_probe(struct platform_device *pdev)
return -EINVAL;
pdata = match->data;
nr_xlats = (pdata && pdata->nr_xlats) ? pdata->nr_xlats : 3;
+ nr_asid_secs = (pdata && pdata->nr_asid_secs) ? pdata->nr_asid_secs : 1;
if (of_property_read_u32(dev->of_node, "nvidia,#asids", &asids))
asids = (pdata && pdata->asids) ? pdata->asids : 4;
@@ -1320,7 +1345,7 @@ static int tegra_smmu_probe(struct platform_device *pdev)
bytes = sizeof(*smmu) + asids * (sizeof(*smmu->as) +
sizeof(struct dma_iommu_mapping *));
- bytes += sizeof(u32) * nr_xlats;
+ bytes += sizeof(u32) * (nr_asid_secs + nr_xlats);
smmu = devm_kzalloc(dev, bytes, GFP_KERNEL);
if (!smmu) {
dev_err(dev, "failed to allocate smmu_device\n");
@@ -1330,6 +1355,7 @@ static int tegra_smmu_probe(struct platform_device *pdev)
smmu->clients = RB_ROOT;
smmu->map = (struct dma_iommu_mapping **)(smmu->as + asids);
smmu->xlat = (u32 *)(smmu->map + smmu->num_as);
+ smmu->asid_sec = smmu->xlat + smmu->nr_xlats;
smmu->nregs = pdev->num_resources;
smmu->tlb_reset = (pdata && pdata->tlb_reset) ? pdata->tlb_reset :
(SMMU_TLB_CONFIG_RESET_VAL | 0x10);
@@ -1369,7 +1395,7 @@ static int tegra_smmu_probe(struct platform_device *pdev)
smmu->nr_xlats = nr_xlats;
smmu->iovmm_base = base;
smmu->page_count = size;
- smmu->asid_security = 0;
+ smmu->nr_asid_secs = nr_asid_secs;
for (i = 0; i < smmu->nr_xlats; i++)
smmu->xlat[i] = ~0;
--
2.0.0.rc1.15.g7e76a2f
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCHv8 20/21] ARM: dt: tegra124: add tegra,smmu entry
[not found] ` <1401448834-32659-1-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
` (18 preceding siblings ...)
2014-05-30 11:20 ` [PATCHv8 19/21] iommu/tegra124: smmu: add multiple asid_security support Hiroshi Doyu
@ 2014-05-30 11:20 ` Hiroshi Doyu
[not found] ` <1401448834-32659-21-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2014-05-30 11:20 ` [PATCHv8 21/21] ARM: dt: tegra124: add sdhci iommus bindings Hiroshi Doyu
20 siblings, 1 reply; 31+ messages in thread
From: Hiroshi Doyu @ 2014-05-30 11:20 UTC (permalink / raw)
To: linux-tegra-u79uwXL29TY76Z2rM5mHXA
Add Tegra SMMU DT entry.
Signed-off-by: Hiroshi Doyu <hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
arch/arm/boot/dts/tegra124.dtsi | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/arch/arm/boot/dts/tegra124.dtsi b/arch/arm/boot/dts/tegra124.dtsi
index 6e6bc4e8185c..5b339ca8a1ab 100644
--- a/arch/arm/boot/dts/tegra124.dtsi
+++ b/arch/arm/boot/dts/tegra124.dtsi
@@ -1,5 +1,6 @@
#include <dt-bindings/clock/tegra124-car.h>
#include <dt-bindings/gpio/tegra-gpio.h>
+#include <dt-bindings/memory/tegra-swgroup.h>
#include <dt-bindings/pinctrl/pinctrl-tegra.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
@@ -449,6 +450,20 @@
clock-names = "pclk", "clk32k_in";
};
+ smmu: iommu {
+ compatible = "nvidia,tegra124-smmu";
+ reg = <0x0 0x70019010 0x0 0x34
+ 0x0 0x700191f0 0x0 0x10
+ 0x0 0x70019228 0x0 0x58
+ 0x0 0x70019600 0x0 0x4
+ 0x0 0x700199b8 0x0 0x4
+ 0x0 0x700199e0 0x0 0x18
+ 0x0 0x70019a88 0x0 0x24>;
+ nvidia,#asids = <128>;
+ dma-window = <0x0 0x0 0x0 0x40000000>;
+ iommu-cells = <2>;
+ };
+
sdhci@0,700b0000 {
compatible = "nvidia,tegra124-sdhci";
reg = <0x0 0x700b0000 0x0 0x200>;
--
2.0.0.rc1.15.g7e76a2f
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCHv8 21/21] ARM: dt: tegra124: add sdhci iommus bindings
[not found] ` <1401448834-32659-1-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
` (19 preceding siblings ...)
2014-05-30 11:20 ` [PATCHv8 20/21] ARM: dt: tegra124: add tegra,smmu entry Hiroshi Doyu
@ 2014-05-30 11:20 ` Hiroshi Doyu
[not found] ` <1401448834-32659-22-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
20 siblings, 1 reply; 31+ messages in thread
From: Hiroshi Doyu @ 2014-05-30 11:20 UTC (permalink / raw)
To: linux-tegra-u79uwXL29TY76Z2rM5mHXA
Add sdhci iommus bindings.
Signed-off-by: Hiroshi Doyu <hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
arch/arm/boot/dts/tegra124.dtsi | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/arch/arm/boot/dts/tegra124.dtsi b/arch/arm/boot/dts/tegra124.dtsi
index 5b339ca8a1ab..011831ffd390 100644
--- a/arch/arm/boot/dts/tegra124.dtsi
+++ b/arch/arm/boot/dts/tegra124.dtsi
@@ -472,6 +472,7 @@
resets = <&tegra_car 14>;
reset-names = "sdhci";
status = "disabled";
+ iommus=<&smmu TEGRA_SWGROUP_CELLS(SDMMC1A)>;
};
sdhci@0,700b0200 {
@@ -482,6 +483,7 @@
resets = <&tegra_car 9>;
reset-names = "sdhci";
status = "disabled";
+ iommus=<&smmu TEGRA_SWGROUP_CELLS(SDMMC2A)>;
};
sdhci@0,700b0400 {
@@ -492,6 +494,7 @@
resets = <&tegra_car 69>;
reset-names = "sdhci";
status = "disabled";
+ iommus=<&smmu TEGRA_SWGROUP_CELLS(SDMMC3A)>;
};
sdhci@0,700b0600 {
@@ -502,6 +505,7 @@
resets = <&tegra_car 15>;
reset-names = "sdhci";
status = "disabled";
+ iommus=<&smmu TEGRA_SWGROUP_CELLS(SDMMC4A)>;
};
ahub@0,70300000 {
--
2.0.0.rc1.15.g7e76a2f
^ permalink raw reply related [flat|nested] 31+ messages in thread
* Re: [PATCHv8 20/21] ARM: dt: tegra124: add tegra,smmu entry
[not found] ` <1401448834-32659-21-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
@ 2014-05-30 16:30 ` Stephen Warren
0 siblings, 0 replies; 31+ messages in thread
From: Stephen Warren @ 2014-05-30 16:30 UTC (permalink / raw)
To: Hiroshi Doyu, linux-tegra-u79uwXL29TY76Z2rM5mHXA
On 05/30/2014 05:20 AM, Hiroshi Doyu wrote:
> Add Tegra SMMU DT entry.
>
> diff --git a/arch/arm/boot/dts/tegra124.dtsi b/arch/arm/boot/dts/tegra124.dtsi
> + smmu: iommu {
> + compatible = "nvidia,tegra124-smmu";
> + reg = <0x0 0x70019010 0x0 0x34
> + 0x0 0x700191f0 0x0 0x10
> + 0x0 0x70019228 0x0 0x58
> + 0x0 0x70019600 0x0 0x4
> + 0x0 0x700199b8 0x0 0x4
> + 0x0 0x700199e0 0x0 0x18
> + 0x0 0x70019a88 0x0 0x24>;
> + nvidia,#asids = <128>;
> + dma-window = <0x0 0x0 0x0 0x40000000>;
> + iommu-cells = <2>;
> + };
The indentation is inconsistent here; mix of TABs/spaces perhaps?
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCHv8 15/21] iommu/tegra124: smmu: add support platform data
[not found] ` <1401448834-32659-16-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
@ 2014-05-30 16:31 ` Stephen Warren
[not found] ` <5388B260.5000403-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org>
0 siblings, 1 reply; 31+ messages in thread
From: Stephen Warren @ 2014-05-30 16:31 UTC (permalink / raw)
To: Hiroshi Doyu, linux-tegra-u79uwXL29TY76Z2rM5mHXA
On 05/30/2014 05:20 AM, Hiroshi Doyu wrote:
> The later Tegra SoC(>= T124) has more registers for
> MC_SMMU_TRANSLATION_ENABLE_*. Now those info is provided as platfrom
> data. If those varies a lot on SoCs in the future, we can consider
> putting them into DT later.
> diff --git a/Documentation/devicetree/bindings/iommu/nvidia,tegra30-smmu.txt b/Documentation/devicetree/bindings/iommu/nvidia,tegra30-smmu.txt
> Required properties:
> -- compatible : "nvidia,tegra30-smmu"
> -- reg : Should contain 3 register banks(address and length) for each
> +- compatible : "nvidia,tegra124-smmu", "nvidia,tegra30-smmu"
> +- reg : Can contain multiple register banks(address and length) for each
> of the SMMU register blocks.
How many is "multiple"? This seems like rather a weak definition of how
many entries are expected. What are the different register banks?
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCHv8 21/21] ARM: dt: tegra124: add sdhci iommus bindings
[not found] ` <1401448834-32659-22-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
@ 2014-05-30 16:34 ` Stephen Warren
[not found] ` <5388B2FD.7040307-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org>
0 siblings, 1 reply; 31+ messages in thread
From: Stephen Warren @ 2014-05-30 16:34 UTC (permalink / raw)
To: Hiroshi Doyu, linux-tegra-u79uwXL29TY76Z2rM5mHXA
On 05/30/2014 05:20 AM, Hiroshi Doyu wrote:
> Add sdhci iommus bindings.
This isn't adding bindings, it's adding DT properties. A binding is the
documentation of the schema, not the actual data in the DT.
> diff --git a/arch/arm/boot/dts/tegra124.dtsi b/arch/arm/boot/dts/tegra124.dtsi
> index 5b339ca8a1ab..011831ffd390 100644
> --- a/arch/arm/boot/dts/tegra124.dtsi
> +++ b/arch/arm/boot/dts/tegra124.dtsi
> @@ -472,6 +472,7 @@
> resets = <&tegra_car 14>;
> reset-names = "sdhci";
> status = "disabled";
> + iommus=<&smmu TEGRA_SWGROUP_CELLS(SDMMC1A)>;
Is the "iommus" property documented anywhere? I suspect not, since
there's an active ongoing discussion about how IOMMU bindings should be
structured. I suspect this series needs to wait until that discussion
completes, and the "iommus" property is documented somewhere.
There should be spaces around the = i.e. iommus = <...>;
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCHv8 15/21] iommu/tegra124: smmu: add support platform data
[not found] ` <5388B260.5000403-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org>
@ 2014-05-30 16:39 ` Hiroshi Doyu
[not found] ` <87zjhzrzkq.fsf-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
0 siblings, 1 reply; 31+ messages in thread
From: Hiroshi Doyu @ 2014-05-30 16:39 UTC (permalink / raw)
To: Stephen Warren
Cc: Hiroshi Doyu, linux-tegra-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
Stephen Warren <swarren-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org> writes:
> On 05/30/2014 05:20 AM, Hiroshi Doyu wrote:
>> The later Tegra SoC(>= T124) has more registers for
>> MC_SMMU_TRANSLATION_ENABLE_*. Now those info is provided as platfrom
>> data. If those varies a lot on SoCs in the future, we can consider
>> putting them into DT later.
>
>> diff --git a/Documentation/devicetree/bindings/iommu/nvidia,tegra30-smmu.txt b/Documentation/devicetree/bindings/iommu/nvidia,tegra30-smmu.txt
>
>> Required properties:
>> -- compatible : "nvidia,tegra30-smmu"
>> -- reg : Should contain 3 register banks(address and length) for each
>> +- compatible : "nvidia,tegra124-smmu", "nvidia,tegra30-smmu"
>> +- reg : Can contain multiple register banks(address and length) for each
>> of the SMMU register blocks.
>
> How many is "multiple"? This seems like rather a weak definition of how
> many entries are expected. What are the different register banks?
SMMU registers are part of MC registers. SMMU registeres are interleaved
by MC(non-SMMU) registeres, most likely it's about ~10 banks.
We concluded to not have SMMU as a child of MC since their features are
so independent long time ago. This interleaved register locations are
not so good. I requested H/W team to have them completely separated, but
itt was too late to change.
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCHv8 15/21] iommu/tegra124: smmu: add support platform data
[not found] ` <87zjhzrzkq.fsf-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
@ 2014-05-30 16:40 ` Stephen Warren
2014-06-04 21:37 ` Thierry Reding
1 sibling, 0 replies; 31+ messages in thread
From: Stephen Warren @ 2014-05-30 16:40 UTC (permalink / raw)
To: Hiroshi Doyu; +Cc: linux-tegra-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
On 05/30/2014 10:39 AM, Hiroshi Doyu wrote:
>
> Stephen Warren <swarren-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org> writes:
>
>> On 05/30/2014 05:20 AM, Hiroshi Doyu wrote:
>>> The later Tegra SoC(>= T124) has more registers for
>>> MC_SMMU_TRANSLATION_ENABLE_*. Now those info is provided as platfrom
>>> data. If those varies a lot on SoCs in the future, we can consider
>>> putting them into DT later.
>>
>>> diff --git a/Documentation/devicetree/bindings/iommu/nvidia,tegra30-smmu.txt b/Documentation/devicetree/bindings/iommu/nvidia,tegra30-smmu.txt
>>
>>> Required properties:
>>> -- compatible : "nvidia,tegra30-smmu"
>>> -- reg : Should contain 3 register banks(address and length) for each
>>> +- compatible : "nvidia,tegra124-smmu", "nvidia,tegra30-smmu"
>>> +- reg : Can contain multiple register banks(address and length) for each
>>> of the SMMU register blocks.
>>
>> How many is "multiple"? This seems like rather a weak definition of how
>> many entries are expected. What are the different register banks?
>
> SMMU registers are part of MC registers. SMMU registeres are interleaved
> by MC(non-SMMU) registeres, most likely it's about ~10 banks.
>
> We concluded to not have SMMU as a child of MC since their features are
> so independent long time ago. This interleaved register locations are
> not so good. I requested H/W team to have them completely separated, but
> itt was too late to change.
The point of my comment was that the DT binding documentation needs to
explicitly state exactly what entries are required.
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCHv8 21/21] ARM: dt: tegra124: add sdhci iommus bindings
[not found] ` <5388B2FD.7040307-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org>
@ 2014-05-30 16:44 ` Hiroshi Doyu
[not found] ` <87y4xjrzc9.fsf-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
0 siblings, 1 reply; 31+ messages in thread
From: Hiroshi Doyu @ 2014-05-30 16:44 UTC (permalink / raw)
To: Stephen Warren
Cc: Hiroshi Doyu, linux-tegra-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
Stephen Warren <swarren-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org> writes:
> On 05/30/2014 05:20 AM, Hiroshi Doyu wrote:
>> Add sdhci iommus bindings.
>
> This isn't adding bindings, it's adding DT properties. A binding is the
> documentation of the schema, not the actual data in the DT.
>
>> diff --git a/arch/arm/boot/dts/tegra124.dtsi b/arch/arm/boot/dts/tegra124.dtsi
>> index 5b339ca8a1ab..011831ffd390 100644
>> --- a/arch/arm/boot/dts/tegra124.dtsi
>> +++ b/arch/arm/boot/dts/tegra124.dtsi
>> @@ -472,6 +472,7 @@
>> resets = <&tegra_car 14>;
>> reset-names = "sdhci";
>> status = "disabled";
>> + iommus=<&smmu TEGRA_SWGROUP_CELLS(SDMMC1A)>;
>
> Is the "iommus" property documented anywhere? I suspect not, since
> there's an active ongoing discussion about how IOMMU bindings should be
> structured. I suspect this series needs to wait until that discussion
> completes, and the "iommus" property is documented somewhere.
Yes, I'm catching up that thread now. That's why I drop document part.
If Thierry's patch(v2 or v3) is accpeted, this patch won't need any
further doc since it will use the IOMMU standard bindings("iommus = ").
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCHv8 15/21] iommu/tegra124: smmu: add support platform data
[not found] ` <87zjhzrzkq.fsf-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2014-05-30 16:40 ` Stephen Warren
@ 2014-06-04 21:37 ` Thierry Reding
1 sibling, 0 replies; 31+ messages in thread
From: Thierry Reding @ 2014-06-04 21:37 UTC (permalink / raw)
To: Hiroshi Doyu
Cc: Stephen Warren,
linux-tegra-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
[-- Attachment #1: Type: text/plain, Size: 1817 bytes --]
On Fri, May 30, 2014 at 07:39:01PM +0300, Hiroshi Doyu wrote:
>
> Stephen Warren <swarren-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org> writes:
>
> > On 05/30/2014 05:20 AM, Hiroshi Doyu wrote:
> >> The later Tegra SoC(>= T124) has more registers for
> >> MC_SMMU_TRANSLATION_ENABLE_*. Now those info is provided as platfrom
> >> data. If those varies a lot on SoCs in the future, we can consider
> >> putting them into DT later.
> >
> >> diff --git a/Documentation/devicetree/bindings/iommu/nvidia,tegra30-smmu.txt b/Documentation/devicetree/bindings/iommu/nvidia,tegra30-smmu.txt
> >
> >> Required properties:
> >> -- compatible : "nvidia,tegra30-smmu"
> >> -- reg : Should contain 3 register banks(address and length) for each
> >> +- compatible : "nvidia,tegra124-smmu", "nvidia,tegra30-smmu"
> >> +- reg : Can contain multiple register banks(address and length) for each
> >> of the SMMU register blocks.
> >
> > How many is "multiple"? This seems like rather a weak definition of how
> > many entries are expected. What are the different register banks?
>
> SMMU registers are part of MC registers. SMMU registeres are interleaved
> by MC(non-SMMU) registeres, most likely it's about ~10 banks.
>
> We concluded to not have SMMU as a child of MC since their features are
> so independent long time ago. This interleaved register locations are
> not so good. I requested H/W team to have them completely separated, but
> itt was too late to change.
This situation is really messy. In my opinion we should break DT
compatibility and expose this through a single memory-controller driver
rather than split it up into different subdevices.
That reflects the hardware more accurately and gets rid of a number of
quirks currently required just to make things work.
Thierry
[-- Attachment #2: Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCHv8 21/21] ARM: dt: tegra124: add sdhci iommus bindings
[not found] ` <87y4xjrzc9.fsf-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
@ 2014-06-04 21:39 ` Thierry Reding
0 siblings, 0 replies; 31+ messages in thread
From: Thierry Reding @ 2014-06-04 21:39 UTC (permalink / raw)
To: Hiroshi Doyu
Cc: Stephen Warren,
linux-tegra-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
[-- Attachment #1: Type: text/plain, Size: 1600 bytes --]
On Fri, May 30, 2014 at 07:44:06PM +0300, Hiroshi Doyu wrote:
>
> Stephen Warren <swarren-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org> writes:
>
> > On 05/30/2014 05:20 AM, Hiroshi Doyu wrote:
> >> Add sdhci iommus bindings.
> >
> > This isn't adding bindings, it's adding DT properties. A binding is the
> > documentation of the schema, not the actual data in the DT.
> >
> >> diff --git a/arch/arm/boot/dts/tegra124.dtsi b/arch/arm/boot/dts/tegra124.dtsi
> >> index 5b339ca8a1ab..011831ffd390 100644
> >> --- a/arch/arm/boot/dts/tegra124.dtsi
> >> +++ b/arch/arm/boot/dts/tegra124.dtsi
> >> @@ -472,6 +472,7 @@
> >> resets = <&tegra_car 14>;
> >> reset-names = "sdhci";
> >> status = "disabled";
> >> + iommus=<&smmu TEGRA_SWGROUP_CELLS(SDMMC1A)>;
> >
> > Is the "iommus" property documented anywhere? I suspect not, since
> > there's an active ongoing discussion about how IOMMU bindings should be
> > structured. I suspect this series needs to wait until that discussion
> > completes, and the "iommus" property is documented somewhere.
>
> Yes, I'm catching up that thread now. That's why I drop document part.
>
> If Thierry's patch(v2 or v3) is accpeted, this patch won't need any
> further doc since it will use the IOMMU standard bindings("iommus = ").
The binding for the Tegra SMMU would still need to document what the
specifier means. Also I think we should change the current meaning of a
two-cell bitmask to the more explicit one cell per SWGROUP binding, that
is something like this:
iommus = <&smmu TEGRA_SWGROUP_SDMMC1A>;
Thierry
[-- Attachment #2: Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCHv8 05/21] iommu/core: add ops->{bound,unbind}_driver()
[not found] ` <1401448834-32659-6-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
@ 2014-06-16 11:02 ` Hiroshi Doyu
0 siblings, 0 replies; 31+ messages in thread
From: Hiroshi Doyu @ 2014-06-16 11:02 UTC (permalink / raw)
To: linux-tegra-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
Hiroshi Doyu <hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org> writes:
> ops->{bound,unbind}_driver() functions are called at
> BUS_NOTIFY_{BOUND,UNBIND}_DRIVER respectively.
>
> This is necessary to control the device population order. IOMMU master
> devices depend on an IOMMU device instanciation. IOMMU master devices
> can be registered to an IOMMU only after it's successfully
> populated. This IOMMU registration is done via
> ops->bound_driver(). Currently this population can be deferred if
> depending IOMMU device hasn't yet been populated in driver core. This
> cannot be done via ops->add_device() since after add_device() device's
> population/instanciation can be still deferred via probe().
>
> Signed-off-by: Hiroshi Doyu <hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
> ---
> drivers/iommu/iommu.c | 13 +++++++++++--
> include/linux/iommu.h | 4 ++++
> 2 files changed, 15 insertions(+), 2 deletions(-)
I have just noticed that we could make use of IOMMU group for this
purpose so that we could avoid this iommu core part modification but
just tegra-smmu part modification which would be easier to merge.
> diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
> index e5555fcfe703..5469d361e7bc 100644
> --- a/drivers/iommu/iommu.c
> +++ b/drivers/iommu/iommu.c
> @@ -540,14 +540,23 @@ static int iommu_bus_notifier(struct notifier_block *nb,
> * ADD/DEL call into iommu driver ops if provided, which may
> * result in ADD/DEL notifiers to group->notifier
> */
> - if (action == BUS_NOTIFY_ADD_DEVICE) {
> + switch (action) {
> + case BUS_NOTIFY_ADD_DEVICE:
> if (ops->add_device)
> return ops->add_device(dev);
> - } else if (action == BUS_NOTIFY_DEL_DEVICE) {
> + case BUS_NOTIFY_DEL_DEVICE:
> if (ops->remove_device && dev->iommu_group) {
> ops->remove_device(dev);
> return 0;
> }
> + case BUS_NOTIFY_BOUND_DRIVER:
> + if (ops->bound_driver)
> + ops->bound_driver(dev);
> + break;
> + case BUS_NOTIFY_UNBIND_DRIVER:
> + if (ops->unbind_driver)
> + ops->unbind_driver(dev);
> + break;
> }
>
> /*
> diff --git a/include/linux/iommu.h b/include/linux/iommu.h
> index b96a5b2136e4..141eea25bdea 100644
> --- a/include/linux/iommu.h
> +++ b/include/linux/iommu.h
> @@ -97,6 +97,8 @@ enum iommu_attr {
> * @domain_has_cap: domain capabilities query
> * @add_device: add device to iommu grouping
> * @remove_device: remove device from iommu grouping
> + * @bound_driver: called at BUS_NOTIFY_BOUND_DRIVER
> + * @unbind_driver: called at BUS_NOTIFY_UNBIND_DRIVER
> * @domain_get_attr: Query domain attributes
> * @domain_set_attr: Change domain attributes
> * @pgsize_bitmap: bitmap of supported page sizes
> @@ -115,6 +117,8 @@ struct iommu_ops {
> unsigned long cap);
> int (*add_device)(struct device *dev);
> void (*remove_device)(struct device *dev);
> + int (*bound_driver)(struct device *dev);
> + void (*unbind_driver)(struct device *dev);
> int (*device_group)(struct device *dev, unsigned int *groupid);
> int (*domain_get_attr)(struct iommu_domain *domain,
> enum iommu_attr attr, void *data);
> --
> 2.0.0.rc1.15.g7e76a2f
^ permalink raw reply [flat|nested] 31+ messages in thread
end of thread, other threads:[~2014-06-16 11:02 UTC | newest]
Thread overview: 31+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-05-30 11:20 [PATCHv8 00/21] Tegra,SMMU update V8 Hiroshi Doyu
[not found] ` <1401448834-32659-1-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2014-05-30 11:20 ` [PATCHv8 01/21] of: introduce of_property_for_each_phandle_with_args() Hiroshi Doyu
2014-05-30 11:20 ` [PATCHv8 02/21] iommu/of: introduce a global iommu device list Hiroshi Doyu
2014-05-30 11:20 ` [PATCHv8 03/21] iommu/of: check if dependee iommu is ready or not Hiroshi Doyu
2014-05-30 11:20 ` [PATCHv8 04/21] driver/core: populate devices in order for IOMMUs Hiroshi Doyu
2014-05-30 11:20 ` [PATCHv8 05/21] iommu/core: add ops->{bound,unbind}_driver() Hiroshi Doyu
[not found] ` <1401448834-32659-6-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2014-06-16 11:02 ` Hiroshi Doyu
2014-05-30 11:20 ` [PATCHv8 06/21] ARM: tegra: create a DT header defining SWGROUP ID Hiroshi Doyu
2014-05-30 11:20 ` [PATCHv8 07/21] iommu/tegra: smmu: register device to iommu dynamically Hiroshi Doyu
2014-05-30 11:20 ` [PATCHv8 08/21] iommu/tegra: smmu: calculate ASID register offset by ID Hiroshi Doyu
2014-05-30 11:20 ` [PATCHv8 09/21] iommu/tegra: smmu: get swgroups from DT "iommus=" Hiroshi Doyu
2014-05-30 11:20 ` [PATCHv8 10/21] iommu/tegra: smmu: allow duplicate ASID wirte Hiroshi Doyu
2014-05-30 11:20 ` [PATCHv8 11/21] iommu/tegra: smmu: Rename hwgrp -> swgroups Hiroshi Doyu
2014-05-30 11:20 ` [PATCHv8 12/21] iommu/tegra: smmu: add SMMU to an global iommu list Hiroshi Doyu
2014-05-30 11:20 ` [PATCHv8 13/21] iommu/tegra124: smmu: optionaly AHB enables SMMU Hiroshi Doyu
2014-05-30 11:20 ` [PATCHv8 14/21] iommu/tegra124: smmu: convert swgroup ID to asid offset Hiroshi Doyu
2014-05-30 11:20 ` [PATCHv8 15/21] iommu/tegra124: smmu: add support platform data Hiroshi Doyu
[not found] ` <1401448834-32659-16-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2014-05-30 16:31 ` Stephen Warren
[not found] ` <5388B260.5000403-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org>
2014-05-30 16:39 ` Hiroshi Doyu
[not found] ` <87zjhzrzkq.fsf-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2014-05-30 16:40 ` Stephen Warren
2014-06-04 21:37 ` Thierry Reding
2014-05-30 11:20 ` [PATCHv8 16/21] iommu/tegra124: smmu: support more than 32 bit pa Hiroshi Doyu
2014-05-30 11:20 ` [PATCHv8 17/21] iommu/tegra124: smmu: {TLB,PTC} reset value per SoC Hiroshi Doyu
2014-05-30 11:20 ` [PATCHv8 18/21] iommu/tegra124: smmu: adjust TLB_FLUSH_ASID bit range Hiroshi Doyu
2014-05-30 11:20 ` [PATCHv8 19/21] iommu/tegra124: smmu: add multiple asid_security support Hiroshi Doyu
2014-05-30 11:20 ` [PATCHv8 20/21] ARM: dt: tegra124: add tegra,smmu entry Hiroshi Doyu
[not found] ` <1401448834-32659-21-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2014-05-30 16:30 ` Stephen Warren
2014-05-30 11:20 ` [PATCHv8 21/21] ARM: dt: tegra124: add sdhci iommus bindings Hiroshi Doyu
[not found] ` <1401448834-32659-22-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2014-05-30 16:34 ` Stephen Warren
[not found] ` <5388B2FD.7040307-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org>
2014-05-30 16:44 ` Hiroshi Doyu
[not found] ` <87y4xjrzc9.fsf-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2014-06-04 21:39 ` Thierry Reding
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).