* [PATCHv6 00/13] Unifying SMMU driver among Tegra SoCs
@ 2013-11-21 13:40 Hiroshi Doyu
[not found] ` < 1385041249-7705-2-git-send-email-hdoyu@nvidia.com>
` (13 more replies)
0 siblings, 14 replies; 33+ messages in thread
From: Hiroshi Doyu @ 2013-11-21 13:40 UTC (permalink / raw)
To: swarren, will.deacon, grant.likely, thierry.reding, swarren,
robherring2, joro
Cc: Hiroshi Doyu, mark.rutland, devicetree, iommu, linux-tegra,
linux-arm-kernel, lorenzo.pieralisi, galak, linux-kernel
Hi,
This series provide:
(0) IOMMU standard DT binding("iommus")
(1) Unified IOMMU(SMMU) driver among Tegra SoCs
(2) Multiple Address Space support(MASID) in IOMMU(SMMMU)
(3) Tegra IOMMU'able devices, most of platform devices are IOMMU'able.
There's been some discussion[1] about device population order, and for
the solution I implemented an IOMMU hook in driver core:
[PATCHv6 04/13] driver/core: populate devices in order for IOMMUs
which is based on:
http://lists.linuxfoundation.org/pipermail/iommu/2013-November/006933.html
The main problem here is,
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 defered iommu master devices are populated and configured with
help of the already populated iommu device via a new IOMMU API
iommu_ops->driver_bound().
This "iommus=" binding is expected used as the global/standard binding.
Tested IOMMU functionality with T30 SD/MMC. Any further testing with
T114 and/or other devices would be really appreciated.
v5:
Use "iommus=" DT bindings as a standard IOMMU binding.
v4:
Add a hook in driver core to control device populatin order.
Introduced arm,smmu "mmu-master" binding instead of tegra own.
Removed DT patches from this series.
http://lists.linuxfoundation.org/pipermail/iommu/2013-November/006931.html
v3:
Updated based on Stephen Warren's feedback
http://lists.linuxfoundation.org/pipermail/iommu/2013-October/006724.html
v2:
Updated based on Thierry Reding's and Stephen Warren's feedback
http://lists.infradead.org/pipermail/linux-arm-kernel/2013-July/181888.html
v1:
http://lists.infradead.org/pipermail/linux-arm-kernel/2013-June/180267.html
Available in the git repository at:
git://git@nv-tegra.nvidia.com/user/hdoyu/linux.git smmu-upstreaming@20131121
Hiroshi Doyu (13):
of: introduce of_property_for_earch_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
[FOR TEST] ARM: dt: tegra30: add "iommus" binding
.../bindings/iommu/nvidia,tegra30-smmu.txt | 30 +-
arch/arm/boot/dts/tegra30.dtsi | 23 +-
drivers/base/dd.c | 5 +
drivers/iommu/Kconfig | 1 +
drivers/iommu/iommu.c | 13 +-
drivers/iommu/of_iommu.c | 53 +++
drivers/iommu/tegra-smmu.c | 383 +++++++++++++--------
include/dt-bindings/memory/tegra-swgroup.h | 50 +++
include/linux/iommu.h | 4 +
include/linux/of.h | 3 +
include/linux/of_iommu.h | 22 ++
11 files changed, 436 insertions(+), 151 deletions(-)
create mode 100644 include/dt-bindings/memory/tegra-swgroup.h
--
1.8.1.5
^ permalink raw reply [flat|nested] 33+ messages in thread
* [PATCHv6 01/13] of: introduce of_property_for_earch_phandle_with_args()
2013-11-21 13:40 [PATCHv6 00/13] Unifying SMMU driver among Tegra SoCs Hiroshi Doyu
[not found] ` < 1385041249-7705-2-git-send-email-hdoyu@nvidia.com>
@ 2013-11-21 13:40 ` Hiroshi Doyu
2013-11-21 17:17 ` [PATCHv6+ " Hiroshi Doyu
2013-11-21 13:40 ` [PATCHv6 02/13] iommu/of: introduce a global iommu device list Hiroshi Doyu
` (11 subsequent siblings)
13 siblings, 1 reply; 33+ messages in thread
From: Hiroshi Doyu @ 2013-11-21 13:40 UTC (permalink / raw)
To: swarren, will.deacon, grant.likely, thierry.reding, swarren,
robherring2, joro
Cc: Hiroshi Doyu, mark.rutland, devicetree, iommu, linux-tegra,
linux-arm-kernel, lorenzo.pieralisi, galak, linux-kernel
The following pattern of code is tempting to add a new member for
of_property_for_each_*() family as an idiom.
for (i = 0;
!of_parse_phandle_with_args(np, list, cells, i, args); i++)
<do something with "args">;
Signed-off-by: Hiroshi Doyu <hdoyu@nvidia.com>
---
v5:
New patch for v5.
---
include/linux/of.h | 3 +++
1 file changed, 3 insertions(+)
diff --git a/include/linux/of.h b/include/linux/of.h
index 276c546..131fef5 100644
--- a/include/linux/of.h
+++ b/include/linux/of.h
@@ -613,6 +613,9 @@ static inline int of_property_read_u32(const struct device_node *np,
s; \
s = of_prop_next_string(prop, s))
+#define of_property_for_each_phandle_with_args(np, list, cells, i, args) \
+ for (i = 0; !of_parse_phandle_with_args(np, list, cells, i, args); i++)
+
#if defined(CONFIG_PROC_FS) && defined(CONFIG_PROC_DEVICETREE)
extern void proc_device_tree_add_node(struct device_node *, struct proc_dir_entry *);
extern void proc_device_tree_add_prop(struct proc_dir_entry *pde, struct property *prop);
--
1.8.1.5
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCHv6 02/13] iommu/of: introduce a global iommu device list
2013-11-21 13:40 [PATCHv6 00/13] Unifying SMMU driver among Tegra SoCs Hiroshi Doyu
[not found] ` < 1385041249-7705-2-git-send-email-hdoyu@nvidia.com>
2013-11-21 13:40 ` [PATCHv6 01/13] of: introduce of_property_for_earch_phandle_with_args() Hiroshi Doyu
@ 2013-11-21 13:40 ` Hiroshi Doyu
2013-11-21 13:40 ` [PATCHv6 03/13] iommu/of: check if dependee iommu is ready or not Hiroshi Doyu
` (10 subsequent siblings)
13 siblings, 0 replies; 33+ messages in thread
From: Hiroshi Doyu @ 2013-11-21 13:40 UTC (permalink / raw)
To: swarren, will.deacon, grant.likely, thierry.reding, swarren,
robherring2, joro
Cc: Hiroshi Doyu, mark.rutland, devicetree, iommu, linux-tegra,
linux-arm-kernel, lorenzo.pieralisi, galak, linux-kernel
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@nvidia.com>
Cc: Thierry Reding <thierry.reding@gmail.com>
---
v6:
New for v6.
---
drivers/iommu/of_iommu.c | 37 +++++++++++++++++++++++++++++++++++++
include/linux/of_iommu.h | 16 ++++++++++++++++
2 files changed, 53 insertions(+)
diff --git a/drivers/iommu/of_iommu.c b/drivers/iommu/of_iommu.c
index ee249bc..5d1aeb9 100644
--- a/drivers/iommu/of_iommu.c
+++ b/drivers/iommu/of_iommu.c
@@ -20,6 +20,43 @@
#include <linux/export.h>
#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 51a560f..a0aa9d4 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);
+extern void iommu_add(struct iommu *iommu);
+extern 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 */
--
1.8.1.5
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCHv6 03/13] iommu/of: check if dependee iommu is ready or not
2013-11-21 13:40 [PATCHv6 00/13] Unifying SMMU driver among Tegra SoCs Hiroshi Doyu
` (2 preceding siblings ...)
2013-11-21 13:40 ` [PATCHv6 02/13] iommu/of: introduce a global iommu device list Hiroshi Doyu
@ 2013-11-21 13:40 ` Hiroshi Doyu
2013-11-21 13:40 ` [PATCHv6 04/13] driver/core: populate devices in order for IOMMUs Hiroshi Doyu
` (9 subsequent siblings)
13 siblings, 0 replies; 33+ messages in thread
From: Hiroshi Doyu @ 2013-11-21 13:40 UTC (permalink / raw)
To: swarren, will.deacon, grant.likely, thierry.reding, swarren,
robherring2, joro
Cc: Hiroshi Doyu, mark.rutland, devicetree, iommu, linux-tegra,
linux-arm-kernel, lorenzo.pieralisi, galak, linux-kernel
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@nvidia.com>
---
v6:
Spinned off only of_iommu part from:
[PATCHv5 2/9] driver/core: populate devices in order for IOMMUs
v5:
Use "iommus=" binding instread of arm,smmu's "#stream-id-cells".
v4:
This is newly added, and the successor of the following RFC:
[RFC][PATCHv3+ 1/2] driver/core: Add of_iommu_attach()
http://lists.linuxfoundation.org/pipermail/iommu/2013-November/006914.html
---
drivers/iommu/of_iommu.c | 16 ++++++++++++++++
include/linux/of_iommu.h | 6 ++++++
2 files changed, 22 insertions(+)
diff --git a/drivers/iommu/of_iommu.c b/drivers/iommu/of_iommu.c
index 5d1aeb9..6ad4997e 100644
--- a/drivers/iommu/of_iommu.c
+++ b/drivers/iommu/of_iommu.c
@@ -125,3 +125,19 @@ 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)
+{
+ int i;
+ struct of_phandle_args args;
+
+ of_property_for_each_phandle_with_args(dev->of_node, "iommus",
+ "#iommu-cells", i, &args) {
+ pr_debug("%s(i=%d) %s\n", __func__, i, dev_name(dev));
+
+ if (!of_find_iommu_by_node(args.np))
+ return -EPROBE_DEFER;
+ }
+
+ return 0;
+}
diff --git a/include/linux/of_iommu.h b/include/linux/of_iommu.h
index a0aa9d4..14c9a5c 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,
extern void iommu_add(struct iommu *iommu);
extern void iommu_del(struct iommu *iommu);
+extern 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 */
--
1.8.1.5
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCHv6 04/13] driver/core: populate devices in order for IOMMUs
2013-11-21 13:40 [PATCHv6 00/13] Unifying SMMU driver among Tegra SoCs Hiroshi Doyu
` (3 preceding siblings ...)
2013-11-21 13:40 ` [PATCHv6 03/13] iommu/of: check if dependee iommu is ready or not Hiroshi Doyu
@ 2013-11-21 13:40 ` Hiroshi Doyu
2013-11-21 13:40 ` [PATCHv6 05/13] iommu/core: add ops->{bound,unbind}_driver() Hiroshi Doyu
` (8 subsequent siblings)
13 siblings, 0 replies; 33+ messages in thread
From: Hiroshi Doyu @ 2013-11-21 13:40 UTC (permalink / raw)
To: swarren, will.deacon, grant.likely, thierry.reding, swarren,
robherring2, joro
Cc: Hiroshi Doyu, mark.rutland, devicetree, iommu, linux-tegra,
linux-arm-kernel, lorenzo.pieralisi, galak, linux-kernel
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@nvidia.com>
---
v6:
Spinned off only driver core part from:
[PATCHv5 2/9] driver/core: populate devices in order for IOMMUs
v5:
Use "iommus=" binding instread of arm,smmu's "#stream-id-cells".
v4:
This is newly added, and the successor of the following RFC:
[RFC][PATCHv3+ 1/2] driver/core: Add of_iommu_attach()
http://lists.linuxfoundation.org/pipermail/iommu/2013-November/006914.html
---
drivers/base/dd.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index 0605176..0605f52 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"
@@ -273,6 +274,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)
--
1.8.1.5
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCHv6 05/13] iommu/core: add ops->{bound,unbind}_driver()
2013-11-21 13:40 [PATCHv6 00/13] Unifying SMMU driver among Tegra SoCs Hiroshi Doyu
` (4 preceding siblings ...)
2013-11-21 13:40 ` [PATCHv6 04/13] driver/core: populate devices in order for IOMMUs Hiroshi Doyu
@ 2013-11-21 13:40 ` Hiroshi Doyu
2013-11-25 13:49 ` Hiroshi Doyu
2013-11-21 13:40 ` [PATCHv6 06/13] ARM: tegra: create a DT header defining SWGROUP ID Hiroshi Doyu
` (7 subsequent siblings)
13 siblings, 1 reply; 33+ messages in thread
From: Hiroshi Doyu @ 2013-11-21 13:40 UTC (permalink / raw)
To: swarren, will.deacon, grant.likely, thierry.reding, swarren,
robherring2, joro
Cc: Hiroshi Doyu, mark.rutland, devicetree, iommu, linux-tegra,
linux-arm-kernel, lorenzo.pieralisi, galak, linux-kernel
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@nvidia.com>
---
v6:
New for v6.
---
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 e5555fc..5469d36 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 a444c79..a0e92be 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -96,6 +96,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
@@ -114,6 +116,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);
--
1.8.1.5
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCHv6 06/13] ARM: tegra: create a DT header defining SWGROUP ID
2013-11-21 13:40 [PATCHv6 00/13] Unifying SMMU driver among Tegra SoCs Hiroshi Doyu
` (5 preceding siblings ...)
2013-11-21 13:40 ` [PATCHv6 05/13] iommu/core: add ops->{bound,unbind}_driver() Hiroshi Doyu
@ 2013-11-21 13:40 ` Hiroshi Doyu
2013-11-21 13:40 ` [PATCHv6 07/13] iommu/tegra: smmu: register device to iommu dynamically Hiroshi Doyu
` (6 subsequent siblings)
13 siblings, 0 replies; 33+ messages in thread
From: Hiroshi Doyu @ 2013-11-21 13:40 UTC (permalink / raw)
To: swarren, will.deacon, grant.likely, thierry.reding, swarren,
robherring2, joro
Cc: Hiroshi Doyu, mark.rutland, devicetree, iommu, linux-tegra,
linux-arm-kernel, lorenzo.pieralisi, galak, linux-kernel
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@nvidia.com>
---
v6:
Use 0xffffffff instead of ~0UL since dtc expand this to ~0ULL.
v5:
Added new macro TEGRA_SWGROUP_CELLS() and WO_U32_OF_U64().
v4:
This is almost same as the previous v3. Just TEGRA_SWGROUP_MAX is
added.
[PATCHv3 15/19] ARM: tegra: Create a DT header defining SWGROUP ID
---
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 0000000..9c279f1
--- /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 SWGROUP_ISP
+#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 SWGROUP_MPE
+#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 */
--
1.8.1.5
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCHv6 07/13] iommu/tegra: smmu: register device to iommu dynamically
2013-11-21 13:40 [PATCHv6 00/13] Unifying SMMU driver among Tegra SoCs Hiroshi Doyu
` (6 preceding siblings ...)
2013-11-21 13:40 ` [PATCHv6 06/13] ARM: tegra: create a DT header defining SWGROUP ID Hiroshi Doyu
@ 2013-11-21 13:40 ` Hiroshi Doyu
2013-11-21 13:40 ` [PATCHv6 08/13] iommu/tegra: smmu: calculate ASID register offset by ID Hiroshi Doyu
` (5 subsequent siblings)
13 siblings, 0 replies; 33+ messages in thread
From: Hiroshi Doyu @ 2013-11-21 13:40 UTC (permalink / raw)
To: swarren, will.deacon, grant.likely, thierry.reding, swarren,
robherring2, joro
Cc: Hiroshi Doyu, mark.rutland, devicetree, iommu, linux-tegra,
linux-arm-kernel, lorenzo.pieralisi, galak, linux-kernel
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@nvidia.com>
---
v6:
Use smmu_iommu_{bound,unbind}_driver() instead of
smmu_iommu_{add,del}_device() to register devices to SMMU.
v5:
Add check NUM_OF_STATIC_MAPS < #asids.
v4:
Combined the following from v3. This makes more sense what they do.
[PATCHv3 06/19] iommu/tegra: smmu: Select ARM_DMA_USE_IOMMU in Kconfig
[PATCHv3 07/19] iommu/tegra: smmu: Create default IOVA maps
[PATCHv3 08/19] iommu/tegra: smmu: Register platform_device to IOMMU dynamically
[PATCHv3 19/19] iommu/tegra: smmu: Support Multiple ASID
---
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 3e7fdbb..0a86d63 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 3c772c9..99b4bd4 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, 0);
+ 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;
}
--
1.8.1.5
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCHv6 08/13] iommu/tegra: smmu: calculate ASID register offset by ID
2013-11-21 13:40 [PATCHv6 00/13] Unifying SMMU driver among Tegra SoCs Hiroshi Doyu
` (7 preceding siblings ...)
2013-11-21 13:40 ` [PATCHv6 07/13] iommu/tegra: smmu: register device to iommu dynamically Hiroshi Doyu
@ 2013-11-21 13:40 ` Hiroshi Doyu
2013-11-21 13:40 ` [PATCHv6 09/13] iommu/tegra: smmu: get swgroups from DT "iommus=" Hiroshi Doyu
` (4 subsequent siblings)
13 siblings, 0 replies; 33+ messages in thread
From: Hiroshi Doyu @ 2013-11-21 13:40 UTC (permalink / raw)
To: swarren, will.deacon, grant.likely, thierry.reding, swarren,
robherring2, joro
Cc: Hiroshi Doyu, mark.rutland, devicetree, iommu, linux-tegra,
linux-arm-kernel, lorenzo.pieralisi, galak, linux-kernel
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@nvidia.com>
---
v5:
Added SMMU_ASID_BASE(== SMMU_AFI_ASID).
Removed unused ASID offset definitions.
Use 'unsigned long *' instead of u64 for swgroups bitmap.
v4:
Combined the following patches from v3:
[PATCHv3 09/19] iommu/tegra: smmu: Calculate ASID register offset by ID
[PATCHv3 16/19] iommu/tegra: smmu: Use dt-bindings MACRO
---
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 99b4bd4..6ab977a 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;
--
1.8.1.5
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCHv6 09/13] iommu/tegra: smmu: get swgroups from DT "iommus="
2013-11-21 13:40 [PATCHv6 00/13] Unifying SMMU driver among Tegra SoCs Hiroshi Doyu
` (8 preceding siblings ...)
2013-11-21 13:40 ` [PATCHv6 08/13] iommu/tegra: smmu: calculate ASID register offset by ID Hiroshi Doyu
@ 2013-11-21 13:40 ` Hiroshi Doyu
2013-11-21 13:40 ` [PATCHv6 10/13] iommu/tegra: smmu: allow duplicate ASID wirte Hiroshi Doyu
` (3 subsequent siblings)
13 siblings, 0 replies; 33+ messages in thread
From: Hiroshi Doyu @ 2013-11-21 13:40 UTC (permalink / raw)
To: swarren, will.deacon, grant.likely, thierry.reding, swarren,
robherring2, joro
Cc: Hiroshi Doyu, mark.rutland, devicetree, iommu, linux-tegra,
linux-arm-kernel, lorenzo.pieralisi, galak, linux-kernel
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@nvidia.com>
---
v6:
- Explained "#iommu-cells" in the binding document.
- Fixed old "nvidia,memory-clients" with 'iommus" in the binding
document.
- Move smmu_of_get_swgroups() here from the previous patch not to break
git bisecting.
v5:
"iommu=" in a device DT is used instead of "mmu-masters" in an iommu
DT. This is "iommu=" version of:
[PATCHv4 5/7] iommu/tegra: smmu: Support "mmu-masters" binding
---
.../bindings/iommu/nvidia,tegra30-smmu.txt | 30 ++++-
drivers/iommu/tegra-smmu.c | 133 ++++++++++++++++++---
2 files changed, 144 insertions(+), 19 deletions(-)
diff --git a/Documentation/devicetree/bindings/iommu/nvidia,tegra30-smmu.txt b/Documentation/devicetree/bindings/iommu/nvidia,tegra30-smmu.txt
index 89fb543..fd53f54 100644
--- a/Documentation/devicetree/bindings/iommu/nvidia,tegra30-smmu.txt
+++ b/Documentation/devicetree/bindings/iommu/nvidia,tegra30-smmu.txt
@@ -1,6 +1,6 @@
NVIDIA Tegra 30 IOMMU H/W, SMMU (System Memory Management Unit)
-Required properties:
+Required properties in the IOMMU node:
- compatible : "nvidia,tegra30-smmu"
- reg : Should contain 3 register banks(address and length) for each
of the SMMU register blocks.
@@ -8,9 +8,23 @@ Required properties:
- nvidia,#asids : # of ASIDs
- dma-window : IOVA start address and length.
- nvidia,ahb : phandle to the ahb bus connected to SMMU.
+- iommus: phandle to an iommu device which a device is
+ attached to and indicates which swgroups a device belongs to(SWGROUP ID).
+ SWGROUP ID is from 0 to 63, and a device can belong to multiple SWGROUPS.
+- #iommu-cells. Should be 2. In client IOMMU specifiers, the two cells
+ represent a 64-bit bitmask of SWGROUP IDs under which the device
+ initiates transactions. The least significant word is first. See
+ <dt-bindings/memory/tegra-swgroup.h> for a list of valid values.
+
+Required properties in device nodes affected by the IOMMU:
+- iommus: A list of phandle plus specifier pairs for each IOMMU that
+ affects master transactions initiated by the device. The number of
+ cells in each specifier is defined by the #iommu-cells property in
+ the IOMMU node referred to by the phandle. The meaning of the
+ specifier cells is defined by the referenced IOMMU's binding.
Example:
- smmu {
+ smmu: iommu {
compatible = "nvidia,tegra30-smmu";
reg = <0x7000f010 0x02c
0x7000f1f0 0x010
@@ -18,4 +32,16 @@ Example:
nvidia,#asids = <4>; /* # of ASIDs */
dma-window = <0 0x40000000>; /* IOVA start & length */
nvidia,ahb = <&ahb>;
+ #iommu-cells = <2>;
};
+
+ host1x {
+ compatible = "nvidia,tegra30-host1x", "simple-bus";
+ iommus = <&smmu TEGRA_SWGROUP_CELLS(HC)>;
+ ....
+ gr3d {
+ compatible = "nvidia,tegra30-gr3d";
+ iommus = <&smmu TEGRA_SWGROUP_CELLS(NV)
+ TEGRA_SWGROUP_CELLS(NV2)>;
+ ....
+ };
diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c
index 6ab977a..1a1bcdf 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,96 @@ 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)
+{
+ int i;
+ struct of_phandle_args args;
+
+ of_property_for_each_phandle_with_args(dev->of_node, "iommus",
+ "#iommu-cells", i, &args) {
+ if (args.np != smmu_handle->dev->of_node)
+ continue;
+
+ BUG_ON(args.args_count != 2);
+
+ memcpy(swgroups, 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 +812,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 +839,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 +854,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 +870,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 +973,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
@@ -902,8 +1000,8 @@ static int smmu_iommu_bound_driver(struct device *dev)
else
return -EPROBE_DEFER;
- 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 +1254,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),
--
1.8.1.5
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCHv6 10/13] iommu/tegra: smmu: allow duplicate ASID wirte
2013-11-21 13:40 [PATCHv6 00/13] Unifying SMMU driver among Tegra SoCs Hiroshi Doyu
` (9 preceding siblings ...)
2013-11-21 13:40 ` [PATCHv6 09/13] iommu/tegra: smmu: get swgroups from DT "iommus=" Hiroshi Doyu
@ 2013-11-21 13:40 ` Hiroshi Doyu
2013-11-21 13:40 ` [PATCHv6 11/13] iommu/tegra: smmu: Rename hwgrp -> swgroups Hiroshi Doyu
` (2 subsequent siblings)
13 siblings, 0 replies; 33+ messages in thread
From: Hiroshi Doyu @ 2013-11-21 13:40 UTC (permalink / raw)
To: swarren, will.deacon, grant.likely, thierry.reding, swarren,
robherring2, joro
Cc: Hiroshi Doyu, mark.rutland, devicetree, iommu, linux-tegra,
linux-arm-kernel, lorenzo.pieralisi, galak, linux-kernel
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@nvidia.com>
---
v4:
This was the part of v3, which isn't used any more.
[PATCHv3 10/19] iommu/tegra: smmu: Get "nvidia,swgroups" from DT
---
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 1a1bcdf..76356db 100644
--- a/drivers/iommu/tegra-smmu.c
+++ b/drivers/iommu/tegra-smmu.c
@@ -418,9 +418,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);
@@ -430,16 +434,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,
--
1.8.1.5
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCHv6 11/13] iommu/tegra: smmu: Rename hwgrp -> swgroups
2013-11-21 13:40 [PATCHv6 00/13] Unifying SMMU driver among Tegra SoCs Hiroshi Doyu
` (10 preceding siblings ...)
2013-11-21 13:40 ` [PATCHv6 10/13] iommu/tegra: smmu: allow duplicate ASID wirte Hiroshi Doyu
@ 2013-11-21 13:40 ` Hiroshi Doyu
2013-11-21 13:40 ` [PATCHv6 12/13] iommu/tegra: smmu: add SMMU to an global iommu list Hiroshi Doyu
2013-11-21 13:40 ` [PATCHv6 13/13] [FOR TEST] ARM: dt: tegra30: add "iommus" binding Hiroshi Doyu
13 siblings, 0 replies; 33+ messages in thread
From: Hiroshi Doyu @ 2013-11-21 13:40 UTC (permalink / raw)
To: swarren, will.deacon, grant.likely, thierry.reding, swarren,
robherring2, joro
Cc: Hiroshi Doyu, mark.rutland, devicetree, iommu, linux-tegra,
linux-arm-kernel, lorenzo.pieralisi, galak, linux-kernel
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@nvidia.com>
---
v4:
New for v4
---
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 76356db..1544f7c 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);
}
@@ -403,7 +403,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;
@@ -412,10 +412,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) {
@@ -425,7 +425,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;
@@ -438,7 +438,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;
@@ -447,7 +447,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;
}
@@ -487,7 +487,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);
@@ -815,7 +815,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;
@@ -835,7 +835,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;
@@ -848,7 +848,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;
}
@@ -864,7 +864,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,
--
1.8.1.5
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCHv6 12/13] iommu/tegra: smmu: add SMMU to an global iommu list
2013-11-21 13:40 [PATCHv6 00/13] Unifying SMMU driver among Tegra SoCs Hiroshi Doyu
` (11 preceding siblings ...)
2013-11-21 13:40 ` [PATCHv6 11/13] iommu/tegra: smmu: Rename hwgrp -> swgroups Hiroshi Doyu
@ 2013-11-21 13:40 ` Hiroshi Doyu
2013-11-21 13:40 ` [PATCHv6 13/13] [FOR TEST] ARM: dt: tegra30: add "iommus" binding Hiroshi Doyu
13 siblings, 0 replies; 33+ messages in thread
From: Hiroshi Doyu @ 2013-11-21 13:40 UTC (permalink / raw)
To: swarren, will.deacon, grant.likely, thierry.reding, swarren,
robherring2, joro
Cc: Hiroshi Doyu, mark.rutland, devicetree, iommu, linux-tegra,
linux-arm-kernel, lorenzo.pieralisi, galak, linux-kernel
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@nvidia.com>
Cc: Thierry Reding <thierry.reding@gmail.com>
---
v6:
New for v6.
---
drivers/iommu/tegra-smmu.c | 55 +++++++++++++++++++++++++---------------------
1 file changed, 30 insertions(+), 25 deletions(-)
diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c
index 1544f7c..590c9fe 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;
@@ -388,7 +389,7 @@ static int smmu_of_get_swgroups(struct device *dev, unsigned long *swgroups)
of_property_for_each_phandle_with_args(dev->of_node, "iommus",
"#iommu-cells", i, &args) {
- if (args.np != smmu_handle->dev->of_node)
+ if (args.np != smmu_handle->iommu.dev->of_node)
continue;
BUG_ON(args.args_count != 2);
@@ -527,7 +528,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]));
@@ -542,7 +543,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;
@@ -585,11 +586,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;
}
@@ -649,7 +650,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);
@@ -663,7 +664,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;
}
@@ -693,7 +695,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;
@@ -748,7 +750,7 @@ static int smmu_iommu_map(struct iommu_domain *domain, unsigned long iova,
unsigned long pfn = __phys_to_pfn(pa);
unsigned long flags;
- dev_info(as->smmu->dev, "[%d] %08lx:%pa\n", as->asid, iova, &pa);
+ dev_info(as->smmu->iommu.dev, "[%d] %08lx:%pa\n", as->asid, iova, &pa);
if (!pfn_valid(pfn))
return -ENOMEM;
@@ -765,7 +767,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);
@@ -788,7 +790,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);
@@ -822,7 +824,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;
@@ -844,7 +846,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:
@@ -867,12 +869,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);
}
@@ -899,7 +901,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:
@@ -920,7 +922,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;
}
@@ -953,7 +955,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);
}
/*
@@ -1085,7 +1087,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;
@@ -1107,7 +1109,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");
@@ -1145,7 +1147,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;
@@ -1217,7 +1219,7 @@ static void tegra_smmu_create_default_map(struct smmu_device *smmu)
smmu->map[i] = arm_iommu_create_mapping(&platform_bus_type,
base, size, 0);
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);
}
@@ -1285,7 +1287,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;
@@ -1322,6 +1324,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;
}
@@ -1337,6 +1341,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;
}
--
1.8.1.5
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCHv6 13/13] [FOR TEST] ARM: dt: tegra30: add "iommus" binding
2013-11-21 13:40 [PATCHv6 00/13] Unifying SMMU driver among Tegra SoCs Hiroshi Doyu
` (12 preceding siblings ...)
2013-11-21 13:40 ` [PATCHv6 12/13] iommu/tegra: smmu: add SMMU to an global iommu list Hiroshi Doyu
@ 2013-11-21 13:40 ` Hiroshi Doyu
13 siblings, 0 replies; 33+ messages in thread
From: Hiroshi Doyu @ 2013-11-21 13:40 UTC (permalink / raw)
To: swarren, will.deacon, grant.likely, thierry.reding, swarren,
robherring2, joro
Cc: Hiroshi Doyu, mark.rutland, devicetree, iommu, linux-tegra,
linux-arm-kernel, lorenzo.pieralisi, galak, linux-kernel
"iommus" binding implies that a device can be attached to IOMMU
devices. An iommu device needs to set #iommus-cells in it. "iommus"
can have multiple iommu device phandles as below if needed.
iommus = <&smmu arg1 arg2>,
<&gart arg1 arg2>;
Not yet ready for merge. Need to add iommus for other devices.
Signed-off-by: Hiroshi Doyu <hdoyu@nvidia.com>
---
v5:
Use "iommus=" instead of "mmu-masters".
Signed-off-by: Hiroshi Doyu <hdoyu@nvidia.com>
---
arch/arm/boot/dts/tegra30.dtsi | 23 ++++++++++++++++++++++-
1 file changed, 22 insertions(+), 1 deletion(-)
diff --git a/arch/arm/boot/dts/tegra30.dtsi b/arch/arm/boot/dts/tegra30.dtsi
index 2bd55cf..03b7887 100644
--- a/arch/arm/boot/dts/tegra30.dtsi
+++ b/arch/arm/boot/dts/tegra30.dtsi
@@ -1,6 +1,7 @@
#include <dt-bindings/clock/tegra30-car.h>
#include <dt-bindings/gpio/tegra-gpio.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/memory/tegra-swgroup.h>
#include "skeleton.dtsi"
@@ -92,6 +93,7 @@
interrupts = <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>, /* syncpt */
<GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>; /* general */
clocks = <&tegra_car TEGRA30_CLK_HOST1X>;
+ iommus = <&smmu TEGRA_SWGROUP_CELLS(HC)>;
#address-cells = <1>;
#size-cells = <1>;
@@ -103,6 +105,7 @@
reg = <0x54040000 0x00040000>;
interrupts = <GIC_SPI 68 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&tegra_car TEGRA30_CLK_MPE>;
+ iommus = <&smmu TEGRA_SWGROUP_CELLS(MPE)>;
};
vi {
@@ -110,6 +113,7 @@
reg = <0x54080000 0x00040000>;
interrupts = <GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&tegra_car TEGRA30_CLK_VI>;
+ iommus = <&smmu TEGRA_SWGROUP_CELLS(VI)>;
};
epp {
@@ -117,6 +121,7 @@
reg = <0x540c0000 0x00040000>;
interrupts = <GIC_SPI 70 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&tegra_car TEGRA30_CLK_EPP>;
+ iommus = <&smmu TEGRA_SWGROUP_CELLS(EPP)>;
};
isp {
@@ -124,6 +129,7 @@
reg = <0x54100000 0x00040000>;
interrupts = <GIC_SPI 71 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&tegra_car TEGRA30_CLK_ISP>;
+ iommus = <&smmu TEGRA_SWGROUP_CELLS(ISP)>;
};
gr2d {
@@ -131,6 +137,7 @@
reg = <0x54140000 0x00040000>;
interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&tegra_car TEGRA30_CLK_GR2D>;
+ iommus = <&smmu TEGRA_SWGROUP_CELLS(G2)>;
};
gr3d {
@@ -139,6 +146,8 @@
clocks = <&tegra_car TEGRA30_CLK_GR3D
&tegra_car TEGRA30_CLK_GR3D2>;
clock-names = "3d", "3d2";
+ iommus = <&smmu TEGRA_SWGROUP_CELLS(NV)
+ TEGRA_SWGROUP_CELLS(NV2)>;
};
dc@54200000 {
@@ -148,6 +157,7 @@
clocks = <&tegra_car TEGRA30_CLK_DISP1>,
<&tegra_car TEGRA30_CLK_PLL_P>;
clock-names = "disp1", "parent";
+ iommus = <&smmu TEGRA_SWGROUP_CELLS(DC)>;
rgb {
status = "disabled";
@@ -161,6 +171,7 @@
clocks = <&tegra_car TEGRA30_CLK_DISP2>,
<&tegra_car TEGRA30_CLK_PLL_P>;
clock-names = "disp2", "parent";
+ iommus = <&smmu TEGRA_SWGROUP_CELLS(DCB)>;
rgb {
status = "disabled";
@@ -317,6 +328,7 @@
interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
nvidia,dma-request-selector = <&apbdma 8>;
clocks = <&tegra_car TEGRA30_CLK_UARTA>;
+ iommus = <&smmu TEGRA_SWGROUP_CELLS(PPCS)>;
status = "disabled";
};
@@ -327,6 +339,7 @@
interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
nvidia,dma-request-selector = <&apbdma 9>;
clocks = <&tegra_car TEGRA30_CLK_UARTB>;
+ iommus = <&smmu TEGRA_SWGROUP_CELLS(PPCS)>;
status = "disabled";
};
@@ -337,6 +350,7 @@
interrupts = <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>;
nvidia,dma-request-selector = <&apbdma 10>;
clocks = <&tegra_car TEGRA30_CLK_UARTC>;
+ iommus = <&smmu TEGRA_SWGROUP_CELLS(PPCS)>;
status = "disabled";
};
@@ -347,6 +361,7 @@
interrupts = <GIC_SPI 90 IRQ_TYPE_LEVEL_HIGH>;
nvidia,dma-request-selector = <&apbdma 19>;
clocks = <&tegra_car TEGRA30_CLK_UARTD>;
+ iommus = <&smmu TEGRA_SWGROUP_CELLS(PPCS)>;
status = "disabled";
};
@@ -357,6 +372,7 @@
interrupts = <GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH>;
nvidia,dma-request-selector = <&apbdma 20>;
clocks = <&tegra_car TEGRA30_CLK_UARTE>;
+ iommus = <&smmu TEGRA_SWGROUP_CELLS(PPCS)>;
status = "disabled";
};
@@ -525,7 +541,7 @@
interrupts = <GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>;
};
- iommu {
+ smmu: iommu {
compatible = "nvidia,tegra30-smmu";
reg = <0x7000f010 0x02c
0x7000f1f0 0x010
@@ -533,6 +549,7 @@
nvidia,#asids = <4>; /* # of ASIDs */
dma-window = <0 0x40000000>; /* IOVA start & length */
nvidia,ahb = <&ahb>;
+ #iommu-cells = <2>;
};
ahub {
@@ -605,6 +622,7 @@
reg = <0x78000000 0x200>;
interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&tegra_car TEGRA30_CLK_SDMMC1>;
+ iommus = <&smmu TEGRA_SWGROUP_CELLS(PPCS)>;
status = "disabled";
};
@@ -613,6 +631,7 @@
reg = <0x78000200 0x200>;
interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&tegra_car TEGRA30_CLK_SDMMC2>;
+ iommus = <&smmu TEGRA_SWGROUP_CELLS(PPCS)>;
status = "disabled";
};
@@ -621,6 +640,7 @@
reg = <0x78000400 0x200>;
interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&tegra_car TEGRA30_CLK_SDMMC3>;
+ iommus = <&smmu TEGRA_SWGROUP_CELLS(PPCS)>;
status = "disabled";
};
@@ -629,6 +649,7 @@
reg = <0x78000600 0x200>;
interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&tegra_car TEGRA30_CLK_SDMMC4>;
+ iommus = <&smmu TEGRA_SWGROUP_CELLS(PPCS)>;
status = "disabled";
};
--
1.8.1.5
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCHv6+ 01/13] of: introduce of_property_for_earch_phandle_with_args()
2013-11-21 13:40 ` [PATCHv6 01/13] of: introduce of_property_for_earch_phandle_with_args() Hiroshi Doyu
@ 2013-11-21 17:17 ` Hiroshi Doyu
2013-11-21 18:57 ` Stephen Warren
2013-12-11 13:27 ` Grant Likely
0 siblings, 2 replies; 33+ messages in thread
From: Hiroshi Doyu @ 2013-11-21 17:17 UTC (permalink / raw)
To: grant.likely
Cc: thierry.reding, swarren, robherring2, joro, Stephen Warren,
will.deacon, Hiroshi Doyu, mark.rutland, devicetree, iommu,
linux-tegra, linux-arm-kernel, lorenzo.pieralisi, galak,
linux-kernel
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@nvidia.com>
---
v6+:
Use the description, which Grant Likely proposed, to be full enough
that a future reader can figure out why a patch was written.
http://lists.linuxfoundation.org/pipermail/iommu/2013-November/007062.html
v5:
New patch for v5.
---
include/linux/of.h | 3 +++
1 file changed, 3 insertions(+)
diff --git a/include/linux/of.h b/include/linux/of.h
index 276c546..131fef5 100644
--- a/include/linux/of.h
+++ b/include/linux/of.h
@@ -613,6 +613,9 @@ static inline int of_property_read_u32(const struct device_node *np,
s; \
s = of_prop_next_string(prop, s))
+#define of_property_for_each_phandle_with_args(np, list, cells, i, args) \
+ for (i = 0; !of_parse_phandle_with_args(np, list, cells, i, args); i++)
+
#if defined(CONFIG_PROC_FS) && defined(CONFIG_PROC_DEVICETREE)
extern void proc_device_tree_add_node(struct device_node *, struct proc_dir_entry *);
extern void proc_device_tree_add_prop(struct proc_dir_entry *pde, struct property *prop);
--
1.8.1.5
^ permalink raw reply related [flat|nested] 33+ messages in thread
* Re: [PATCHv6+ 01/13] of: introduce of_property_for_earch_phandle_with_args()
2013-11-21 17:17 ` [PATCHv6+ " Hiroshi Doyu
@ 2013-11-21 18:57 ` Stephen Warren
2013-11-28 12:58 ` [RFC][PATCHv6++ " Hiroshi Doyu
2013-12-11 13:28 ` [PATCHv6+ " Grant Likely
2013-12-11 13:27 ` Grant Likely
1 sibling, 2 replies; 33+ messages in thread
From: Stephen Warren @ 2013-11-21 18:57 UTC (permalink / raw)
To: Hiroshi Doyu, grant.likely
Cc: thierry.reding, robherring2, joro, Stephen Warren, will.deacon,
mark.rutland, devicetree, iommu, linux-tegra, linux-arm-kernel,
lorenzo.pieralisi, galak, linux-kernel
On 11/21/2013 10:17 AM, Hiroshi Doyu wrote:
> 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@nvidia.com>
> ---
> v6+:
> Use the description, which Grant Likely proposed, to be full enough
> that a future reader can figure out why a patch was written.
> http://lists.linuxfoundation.org/pipermail/iommu/2013-November/007062.html
This new version only addresses one of the concerns that Grant had,
namely the commit message.
> diff --git a/include/linux/of.h b/include/linux/of.h
> +#define of_property_for_each_phandle_with_args(np, list, cells, i, args) \
> + for (i = 0; !of_parse_phandle_with_args(np, list, cells, i, args); i++)
> +
Grant also wanted the actual implementation fixed so that it wasn't so
inefficient.
What this current patch does is basically:
for every entry in the property:
for every entry in the property before the current index:
parse the phandle+specifier
That's roughly O(n^2). (n is # entries in the property)
Instead, what should happen is:
for every entry in the property:
parse the phandle+specifier
yield the result
That's roughly O(n).
In other words, an implementation more along the lines of
include/linux/of.h's:
#define of_property_for_each_u32(np, propname, prop, p, u) \
for (prop = of_find_property(np, propname, NULL), \
p = of_prop_next_u32(prop, NULL, &u); \
p; \
p = of_prop_next_u32(prop, p, &u))
... so you'd need functions like of_prop_first_specifier() and
of_prop_next_specifier(), and perhaps some associated set of state
variables, perhaps with all the state wrapped into a single struct for
simplicity.
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCHv6 05/13] iommu/core: add ops->{bound,unbind}_driver()
2013-11-21 13:40 ` [PATCHv6 05/13] iommu/core: add ops->{bound,unbind}_driver() Hiroshi Doyu
@ 2013-11-25 13:49 ` Hiroshi Doyu
2013-12-04 7:40 ` Hiroshi Doyu
0 siblings, 1 reply; 33+ messages in thread
From: Hiroshi Doyu @ 2013-11-25 13:49 UTC (permalink / raw)
To: joro
Cc: Stephen Warren, will.deacon, grant.likely, thierry.reding,
swarren, robherring2, mark.rutland, devicetree, iommu,
linux-tegra, linux-arm-kernel, lorenzo.pieralisi, galak,
linux-kernel
Hi Joerg,
Do you have some time to review this patch along with the following ones?
[PATCHv6 02/13] iommu/of: introduce a global iommu device list
http://lists.linuxfoundation.org/pipermail/iommu/2013-November/007050.html
[PATCHv6 03/13] iommu/of: check if dependee iommu is ready or not
http://lists.linuxfoundation.org/pipermail/iommu/2013-November/007051.html
With those patches, now I'm trying to populate iommu master devices
after an IOMMU device is populated. Originally [PATCHv6 02/13] was
proposed by Thierry. I'm a bit afraid of adding new IOMMU API as
this, but I think that this new {bound,unbind}_driver() is the right
timiing that depeding devices are populated instead of add_device()
since, even after add_device, a device won't be populated. I'm not so
sure how this affects on the existing IOMMUs.
It would be nice if you give some feedback on this.
On Thu, 21 Nov 2013 14:40:41 +0100
Hiroshi Doyu <hdoyu@nvidia.com> wrote:
> 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@nvidia.com>
> ---
> v6:
> New for v6.
> ---
> 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 e5555fc..5469d36 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 a444c79..a0e92be 100644
> --- a/include/linux/iommu.h
> +++ b/include/linux/iommu.h
> @@ -96,6 +96,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
> @@ -114,6 +116,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);
> --
> 1.8.1.5
>
^ permalink raw reply [flat|nested] 33+ messages in thread
* [RFC][PATCHv6++ 01/13] of: introduce of_property_for_earch_phandle_with_args()
2013-11-21 18:57 ` Stephen Warren
@ 2013-11-28 12:58 ` Hiroshi Doyu
2013-11-29 11:46 ` [RFC][PATCHv6+++ " Hiroshi Doyu
2013-12-11 13:28 ` [PATCHv6+ " Grant Likely
1 sibling, 1 reply; 33+ messages in thread
From: Hiroshi Doyu @ 2013-11-28 12:58 UTC (permalink / raw)
To: swarren
Cc: grant.likely, thierry.reding, robherring2, joro, Stephen Warren,
will.deacon, mark.rutland, devicetree, iommu, linux-tegra,
linux-arm-kernel, lorenzo.pieralisi, galak, linux-kernel
Stephen Warren <swarren@wwwdotorg.org> wrote @ Thu, 21 Nov 2013 19:57:00 +0100:
> On 11/21/2013 10:17 AM, Hiroshi Doyu wrote:
> > 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@nvidia.com>
> > ---
> > v6+:
> > Use the description, which Grant Likely proposed, to be full enough
> > that a future reader can figure out why a patch was written.
> > http://lists.linuxfoundation.org/pipermail/iommu/2013-November/007062.html
>
> This new version only addresses one of the concerns that Grant had,
> namely the commit message.
>
> > diff --git a/include/linux/of.h b/include/linux/of.h
>
> > +#define of_property_for_each_phandle_with_args(np, list, cells, i, args) \
> > + for (i = 0; !of_parse_phandle_with_args(np, list, cells, i, args); i++)
> > +
>
> Grant also wanted the actual implementation fixed so that it wasn't so
> inefficient.
>
> What this current patch does is basically:
>
> for every entry in the property:
> for every entry in the property before the current index:
> parse the phandle+specifier
>
> That's roughly O(n^2). (n is # entries in the property)
>
> Instead, what should happen is:
>
> for every entry in the property:
> parse the phandle+specifier
> yield the result
>
> That's roughly O(n).
>
> In other words, an implementation more along the lines of
> include/linux/of.h's:
>
> #define of_property_for_each_u32(np, propname, prop, p, u) \
> for (prop = of_find_property(np, propname, NULL), \
> p = of_prop_next_u32(prop, NULL, &u); \
> p; \
> p = of_prop_next_u32(prop, p, &u))
>
> ... so you'd need functions like of_prop_first_specifier() and
> of_prop_next_specifier(), and perhaps some associated set of state
> variables, perhaps with all the state wrapped into a single struct for
> simplicity.
Although I couldn't invent any struct to hold params and state here,
I'd like you to review the following interface is ok or not.
At first, I thought to refactor __of_parse_phandle_with_args() but
it's a bit highly optimized by Stephen and it looked a bit hard to
refactor without perf regressions. Instread, I introduced 2 new
functions "of_parse_{first,next}_phandle_with_args()" to parse
phandles.
If this interface is ok, I'll include this into the next v7 series.
-----8<-----8<-----8<-----8<-----8<-----8<-----8<-----8<-----8<-----
From: Hiroshi Doyu <hdoyu@nvidia.com>
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.
Introduced "of_parse_{first,next}_phandle_with_args()", where "const
__be32 **list" is used to hold the next list to be processed as a
state pramameter, and both "of_parse_{first,next}_phandle_with_args()"
returns the remaining list in the number of cell(4 byte). If any error
happens, "list" is set NULL not to proceed the rest.
Signed-off-by: Hiroshi Doyu <hdoyu@nvidia.com>
---
v6++:
Optimized to avoid O(n^2), suggested by Stephen Warren.
http://lists.linuxfoundation.org/pipermail/iommu/2013-November/007066.html
v6+:
Use the description, which Grant Likely proposed, to be full enough
that a future reader can figure out why a patch was written.
v5:
New patch for v5.
Signed-off-by: Hiroshi Doyu <hdoyu@nvidia.com>
---
drivers/of/base.c | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
include/linux/of.h | 52 ++++++++++++++++++++++++++++++++++
2 files changed, 134 insertions(+)
diff --git a/drivers/of/base.c b/drivers/of/base.c
index f807d0e..3e29b10 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -1201,6 +1201,88 @@ void of_print_phandle_args(const char *msg, const struct of_phandle_args *args)
printk("\n");
}
+int __of_parse_next_phandle_with_args(const __be32 **plist,
+ const char *cells_name, int cell_count,
+ struct of_phandle_args *out_args)
+{
+ phandle phandle;
+ int i, count = 0, err;
+ struct device_node *dn;
+ const __be32 *list;
+
+ BUG_ON(!out_args);
+ BUG_ON(!cells_name && !cell_count);
+
+ /*
+ * "*plist" should hold phandle, and it's updated to the next
+ * phandle at return if no error.
+ */
+ list = *plist;
+ out_args->np = NULL;
+
+ phandle = be32_to_cpup(list);
+ if (!phandle)
+ goto err_out;
+
+ dn = of_find_node_by_phandle(phandle);
+ if (!dn)
+ goto err_out;
+
+ if (cells_name) {
+ err = of_property_read_u32(dn, cells_name, &count);
+ if (err)
+ goto err_out;
+ } else {
+ count = cell_count;
+ }
+
+ out_args->np = dn;
+ out_args->args_count = count;
+ for (i = 0; i < count; i++)
+ out_args->args[i] = be32_to_cpup(list + 1 + i);
+
+ *plist = list + count + 1; /* update to the next list */
+ return count + 1;
+
+err_out:
+ *plist = NULL;
+ return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(__of_parse_next_phandle_with_args);
+
+int __of_parse_first_phandle_with_args(const struct device_node *np,
+ const __be32 **out_list,
+ const char *list_name,
+ const char *cells_name,
+ int cell_count,
+ struct of_phandle_args *out_args)
+{
+ int rem, count;
+ const __be32 *list;
+
+ list = of_get_property(np, list_name, &rem);
+ if (!list)
+ goto err_out;
+
+ rem /= sizeof(*list);
+ if (!rem)
+ goto err_out;
+
+ count = __of_parse_next_phandle_with_args(&list, cells_name,
+ cell_count, out_args);
+ if (!list)
+ goto err_out;
+
+ rem -= count;
+ *out_list = list; /* update to the next list */
+ return rem;
+
+err_out:
+ *out_list = NULL;
+ return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(__of_parse_first_phandle_with_args);
+
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 276c546..9f15622 100644
--- a/include/linux/of.h
+++ b/include/linux/of.h
@@ -303,6 +303,35 @@ 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 int __of_parse_first_phandle_with_args(const struct device_node *np,
+ const __be32 **out_list,
+ const char *list_name,
+ const char *cells_name,
+ int cell_count,
+ struct of_phandle_args *out_args);
+
+extern int __of_parse_next_phandle_with_args(const __be32 **plist,
+ const char *cells_name,
+ int cell_count,
+ struct of_phandle_args *out_args);
+
+static inline int of_parse_first_phandle_with_args(const struct device_node *np,
+ const __be32 **out_list,
+ const char *list_name,
+ const char *cells_name,
+ struct of_phandle_args *out_args)
+{
+ return __of_parse_first_phandle_with_args(np, out_list, list_name,
+ cells_name, 0, out_args);
+}
+
+static inline int of_parse_next_phandle_with_args(const __be32 **plist,
+ const char *cells_name,
+ struct of_phandle_args *out_args)
+{
+ return __of_parse_next_phandle_with_args(plist, cells_name, 0, out_args);
+}
+
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);
@@ -527,6 +556,24 @@ static inline int of_count_phandle_with_args(struct device_node *np,
return -ENOSYS;
}
+static inline int __of_parse_first_phandle_with_args(
+ const struct device_node *np, const __be32 **out_list,
+ const char *list_name, const char *cells_name, int cell_count,
+ struct of_phandle_args *out_args)
+{
+ *out_list = NULL;
+ return -ENOSYS;
+}
+
+
+static inline int __of_parse_next_phandle_with_args(
+ const __be32 **plist, const char *cells_name, int cell_count,
+ struct of_phandle_args *out_args)
+{
+ *plist = NULL;
+ return -ENOSYS;
+}
+
static inline int of_alias_get_id(struct device_node *np, const char *stem)
{
return -ENOSYS;
@@ -613,6 +660,11 @@ static inline int of_property_read_u32(const struct device_node *np,
s; \
s = of_prop_next_string(prop, s))
+#define of_property_for_each_phandle_with_args(node, list, list_name, cells_name, rem, args) \
+ for (rem = of_parse_first_phandle_with_args(node, &list, list_name, cells_name, &args); \
+ list && rem >= 0; \
+ rem -= of_parse_next_phandle_with_args(&list, cells_name, &args))
+
#if defined(CONFIG_PROC_FS) && defined(CONFIG_PROC_DEVICETREE)
extern void proc_device_tree_add_node(struct device_node *, struct proc_dir_entry *);
extern void proc_device_tree_add_prop(struct proc_dir_entry *pde, struct property *prop);
--
1.8.1.5
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [RFC][PATCHv6+++ 01/13] of: introduce of_property_for_earch_phandle_with_args()
2013-11-28 12:58 ` [RFC][PATCHv6++ " Hiroshi Doyu
@ 2013-11-29 11:46 ` Hiroshi Doyu
2013-12-01 19:00 ` Stephen Warren
0 siblings, 1 reply; 33+ messages in thread
From: Hiroshi Doyu @ 2013-11-29 11:46 UTC (permalink / raw)
To: swarren
Cc: grant.likely, thierry.reding, robherring2, joro, Stephen Warren,
will.deacon, mark.rutland, devicetree, iommu, linux-tegra,
linux-arm-kernel, lorenzo.pieralisi, galak, linux-kernel
Hiroshi Doyu <hdoyu@nvidia.com> wrote @ Thu, 28 Nov 2013 14:58:18 +0200 (EET):
....
> > In other words, an implementation more along the lines of
> > include/linux/of.h's:
> >
> > #define of_property_for_each_u32(np, propname, prop, p, u) \
> > for (prop = of_find_property(np, propname, NULL), \
> > p = of_prop_next_u32(prop, NULL, &u); \
> > p; \
> > p = of_prop_next_u32(prop, p, &u))
> >
> > ... so you'd need functions like of_prop_first_specifier() and
> > of_prop_next_specifier(), and perhaps some associated set of state
> > variables, perhaps with all the state wrapped into a single struct for
> > simplicity.
>
> Although I couldn't invent any struct to hold params and state here,
> I'd like you to review the following interface is ok or not.
Tried again to introduce a new struct to keep track of iteration state
as below:
----8<---------8<---------8<---------8<---------8<---------8<--
From: Hiroshi Doyu <hdoyu@nvidia.com>
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.
Introduced a new struct "of_phandle_iter" to keep the state when
iterating over the list.
Signed-off-by: Hiroshi Doyu <hdoyu@nvidia.com>
---
v6+++:
Introduced a new struct "of_phandle_iter" to keep the state when
iterating over the list.
v6++:
Optimized to avoid O(n^2), suggested by Stephen Warren.
http://lists.linuxfoundation.org/pipermail/iommu/2013-November/007066.html
I didn't introduce any struct to hold params and state here.
v6+:
Use the description, which Grant Likely proposed, to be full enough
that a future reader can figure out why a patch was written.
v5:
New patch for v5.
Signed-off-by: Hiroshi Doyu <hdoyu@nvidia.com>
---
drivers/of/base.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
include/linux/of.h | 45 ++++++++++++++++++++++++++++++++++
2 files changed, 116 insertions(+)
diff --git a/drivers/of/base.c b/drivers/of/base.c
index f807d0e..16fb2d9 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -1201,6 +1201,77 @@ 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 of_phandle_args *out_args)
+{
+ phandle phandle;
+ struct device_node *dn;
+ int i, count = iter->cell_count;
+
+ iter->err = -EINVAL;
+ if (!iter->cells_name && !iter->cell_count)
+ return;
+
+ phandle = be32_to_cpup(iter->cur++);
+ if (!phandle)
+ return;
+
+ dn = of_find_node_by_phandle(phandle);
+ if (!dn)
+ return;
+
+ if (iter->cells_name)
+ if (of_property_read_u32(dn, iter->cells_name, &count))
+ return;
+
+ out_args->np = dn;
+ out_args->args_count = count;
+ for (i = 0; i < count; i++)
+ out_args->args[i] = be32_to_cpup(iter->cur++);
+
+ iter->err = 0;
+}
+EXPORT_SYMBOL_GPL(of_phandle_iter_next);
+
+static void __of_phandle_iter_set(struct of_phandle_iter *iter,
+ const struct device_node *np,
+ const char *list_name)
+{
+ size_t bytes;
+ const __be32 *prop;
+
+ prop = of_get_property(np, list_name, &bytes);
+ if (!prop) {
+ iter->err = -EINVAL;
+ return;
+ }
+
+ iter->cur = prop;
+ iter->end = prop + bytes / sizeof(*prop);
+ iter->err = 0;
+}
+
+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,
+ struct of_phandle_args *out_args)
+{
+ iter->err = -EINVAL;
+ if (!cells_name && !cell_count)
+ return;
+
+ iter->cells_name = cells_name;
+ iter->cell_count = cell_count;
+ __of_phandle_iter_set(iter, np, list_name);
+ if (iter->err)
+ return;
+
+ of_phandle_iter_next(iter, out_args);
+}
+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 276c546..1132b49 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 {
+ int err;
+ const __be32 *cur; /* current phandle */
+ const __be32 *end; /* end of the last phandle */
+ const char *cells_name;
+ int cell_count;
+};
+
#ifdef CONFIG_OF_DYNAMIC
extern struct device_node *of_node_get(struct device_node *node);
extern void of_node_put(struct device_node *node);
@@ -303,6 +315,16 @@ 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,
+ struct of_phandle_args *out_args);
+
+extern void of_phandle_iter_next(struct of_phandle_iter *iter,
+ struct of_phandle_args *out_args);
+
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);
@@ -527,6 +549,22 @@ 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,
+ const int cell_count,
+ struct of_phandle_args *out_args)
+{
+ iter->err = -ENOSYS;
+}
+
+static inline void of_phandle_iter_next(struct of_phandle_iter *iter,
+ struct of_phandle_args *out_args)
+{
+ iter->err = -ENOSYS;
+}
+
static inline int of_alias_get_id(struct device_node *np, const char *stem)
{
return -ENOSYS;
@@ -613,6 +651,13 @@ static inline int of_property_read_u32(const struct device_node *np,
s; \
s = of_prop_next_string(prop, s))
+#define of_property_for_each_phandle_with_args(iter, node, list_name, \
+ cells_name, cell_count, out_args) \
+ for (of_phandle_iter_start(&iter, node, list_name, \
+ cells_name, cell_count, &out_args); \
+ !iter.err && iter.end - iter.cur >= 0 ; \
+ of_phandle_iter_next(&iter, &out_args))
+
#if defined(CONFIG_PROC_FS) && defined(CONFIG_PROC_DEVICETREE)
extern void proc_device_tree_add_node(struct device_node *, struct proc_dir_entry *);
extern void proc_device_tree_add_prop(struct proc_dir_entry *pde, struct property *prop);
--
1.8.1.5
^ permalink raw reply related [flat|nested] 33+ messages in thread
* Re: [RFC][PATCHv6+++ 01/13] of: introduce of_property_for_earch_phandle_with_args()
2013-11-29 11:46 ` [RFC][PATCHv6+++ " Hiroshi Doyu
@ 2013-12-01 19:00 ` Stephen Warren
2013-12-02 11:02 ` Hiroshi Doyu
0 siblings, 1 reply; 33+ messages in thread
From: Stephen Warren @ 2013-12-01 19:00 UTC (permalink / raw)
To: Hiroshi Doyu
Cc: grant.likely, thierry.reding, robherring2, joro, Stephen Warren,
will.deacon, mark.rutland, devicetree, iommu, linux-tegra,
linux-arm-kernel, lorenzo.pieralisi, galak, linux-kernel
On 11/29/2013 04:46 AM, Hiroshi Doyu wrote:
...
> 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.
>
> Introduced a new struct "of_phandle_iter" to keep the state when
> iterating over the list.
>
> Signed-off-by: Hiroshi Doyu <hdoyu@nvidia.com>
> ---
> v6+++:
Surely that's v9; "+++" is rather unusual.
> diff --git a/drivers/of/base.c b/drivers/of/base.c
> +void of_phandle_iter_next(struct of_phandle_iter *iter,
> + struct of_phandle_args *out_args)
> +{
> + phandle phandle;
> + struct device_node *dn;
> + int i, count = iter->cell_count;
> +
> + iter->err = -EINVAL;
> + if (!iter->cells_name && !iter->cell_count)
> + return;
Wasn't that already checked in _start()?
Why not set err = -EINVAL inside the if, rather than setting it to an
error value here by default, then having to over-write it at the end of
the function?
> +static void __of_phandle_iter_set(struct of_phandle_iter *iter,
This is only used in one place; why not simply inline this into
of_phandle_iter_start()? It would make the code simpler.
> +void of_phandle_iter_start(struct of_phandle_iter *iter,
> + iter->cells_name = cells_name;
> + iter->cell_count = cell_count;
Why not pass these values into of_phandle_iter_next() instead? There's
no need to pass them just to _start() so they can be read by _next()
instead.
> diff --git a/include/linux/of.h b/include/linux/of.h
> +/*
> + * keep the state at iterating a list of phandles with variable number
> + * of args
> + */
> +struct of_phandle_iter {
> + int err;
> + const __be32 *cur; /* current phandle */
> + const __be32 *end; /* end of the last phandle */
Can't you detect an error case by e.g. (cur == NULL) and thus avoid
requiring an explicit err field?
Together with removing:
> + const char *cells_name;
> + int cell_count;
... then you'd only be left with cur/end, so I think you could get away
without a struct at all, but simply "cur" as the iterator variable, plus
"end" as the one temp variable.
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [RFC][PATCHv6+++ 01/13] of: introduce of_property_for_earch_phandle_with_args()
2013-12-01 19:00 ` Stephen Warren
@ 2013-12-02 11:02 ` Hiroshi Doyu
2013-12-02 14:39 ` Rob Herring
2013-12-03 20:14 ` Stephen Warren
0 siblings, 2 replies; 33+ messages in thread
From: Hiroshi Doyu @ 2013-12-02 11:02 UTC (permalink / raw)
To: swarren
Cc: grant.likely, thierry.reding, robherring2, joro, Stephen Warren,
will.deacon, mark.rutland, devicetree, iommu, linux-tegra,
linux-arm-kernel, lorenzo.pieralisi, galak, linux-kernel
Stephen Warren <swarren@wwwdotorg.org> wrote @ Sun, 1 Dec 2013 20:00:09 +0100:
> On 11/29/2013 04:46 AM, Hiroshi Doyu wrote:
> ...
> > 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.
> >
> > Introduced a new struct "of_phandle_iter" to keep the state when
> > iterating over the list.
> >
> > Signed-off-by: Hiroshi Doyu <hdoyu@nvidia.com>
> > ---
> > v6+++:
>
> Surely that's v9; "+++" is rather unusual.
My intention was to put this into the next v7 series after I get this
reviewed as RFC.
...
> Together with removing:
>
> > + const char *cells_name;
> > + int cell_count;
>
> ... then you'd only be left with cur/end, so I think you could get away
> without a struct at all, but simply "cur" as the iterator variable, plus
> "end" as the one temp variable.
Although the above proposal would be alsmot same as "[RFC][PATCHv6++
01/13]"(*1) where I use *list(cur) and rem as remaining count, here's
the update. I'll put this into v7 series.
---8<------8<------8<------8<------8<------8<------8<------8<------8<---
From: Hiroshi Doyu <hdoyu@nvidia.com>
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@nvidia.com>
---
v6++++:
Iterate without intrducing a new struct.
v6+++:
Introduced a new struct "of_phandle_iter" to keep the state when
iterating over the list.
v6++:
Optimized to avoid O(n^2), suggested by Stephen Warren.
http://lists.linuxfoundation.org/pipermail/iommu/2013-November/007066.html
I didn't introduce any struct to hold params and state here.
v6+:
Use the description, which Grant Likely proposed, to be full enough
that a future reader can figure out why a patch was written.
v5:
New patch for v5.
Signed-off-by: Hiroshi Doyu <hdoyu@nvidia.com>
---
drivers/of/base.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++
include/linux/of.h | 34 ++++++++++++++++++++++++++++++++++
2 files changed, 87 insertions(+)
diff --git a/drivers/of/base.c b/drivers/of/base.c
index f807d0e..7501f24 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -1201,6 +1201,59 @@ void of_print_phandle_args(const char *msg, const struct of_phandle_args *args)
printk("\n");
}
+const __be32 *of_phandle_iter_next(const char *cells_name, int cell_count,
+ const __be32 *cur, const __be32 *end,
+ struct of_phandle_args *out_args)
+{
+ phandle phandle;
+ struct device_node *dn;
+ int i;
+
+ if (!cells_name && !cell_count)
+ return NULL;
+
+ if (!cur)
+ return NULL;
+
+ if (end - cur <= 0)
+ return NULL;
+
+ phandle = be32_to_cpup(cur++);
+ if (!phandle)
+ return NULL;
+
+ dn = of_find_node_by_phandle(phandle);
+ if (!dn)
+ return NULL;
+
+ if (cells_name)
+ if (of_property_read_u32(dn, cells_name, &cell_count))
+ return NULL;
+
+ out_args->np = dn;
+ out_args->args_count = cell_count;
+ for (i = 0; i < cell_count; i++)
+ out_args->args[i] = be32_to_cpup(cur++);
+
+ return cur;
+}
+EXPORT_SYMBOL_GPL(of_phandle_iter_next);
+
+const __be32 *of_phandle_iter_init(const struct device_node *np,
+ const char *list_name,
+ const __be32 **end)
+{
+ size_t bytes;
+ const __be32 *cur;
+
+ cur = of_get_property(np, list_name, &bytes);
+ if (bytes)
+ *end = cur + bytes / sizeof(*cur);
+
+ return cur;
+}
+EXPORT_SYMBOL_GPL(of_phandle_iter_init);
+
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 276c546..c23710b 100644
--- a/include/linux/of.h
+++ b/include/linux/of.h
@@ -303,6 +303,14 @@ 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 const __be32 *of_phandle_iter_init(const struct device_node *np,
+ const char *list_name,
+ const __be32 **end);
+extern const __be32 *of_phandle_iter_next(const char *cells_name,
+ int cell_count,
+ const __be32 *cur, const __be32 *end,
+ struct of_phandle_args *out_args);
+
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);
@@ -527,6 +535,24 @@ static inline int of_count_phandle_with_args(struct device_node *np,
return -ENOSYS;
}
+static inline const __be32 *of_phandle_iter_init(const struct device_node *np,
+ const char *list_name,
+ const char *cells_name,
+ const int cell_count,
+ struct of_phandle_args *out_args)
+{
+ return NULL;
+}
+
+static inline const __be32 *of_phandle_iter_next(const char *cells_name,
+ int cell_count,
+ const __be32 *cur,
+ const __be32 *end,
+ struct of_phandle_args *out_args);
+{
+ return NULL;
+}
+
static inline int of_alias_get_id(struct device_node *np, const char *stem)
{
return -ENOSYS;
@@ -613,6 +639,14 @@ static inline int of_property_read_u32(const struct device_node *np,
s; \
s = of_prop_next_string(prop, s))
+#define of_property_for_each_phandle_with_args(node, list_name, cells_name, \
+ cell_count, out_args, cur, end) \
+ for (cur = of_phandle_iter_init(node, list_name, &end), \
+ cur = of_phandle_iter_next(cells_name, cell_count, \
+ cur, end, &out_args); \
+ cur; \
+ cur = of_phandle_iter_next(cells_name, cell_count, cur, end, &out_args))
+
#if defined(CONFIG_PROC_FS) && defined(CONFIG_PROC_DEVICETREE)
extern void proc_device_tree_add_node(struct device_node *, struct proc_dir_entry *);
extern void proc_device_tree_add_prop(struct proc_dir_entry *pde, struct property *prop);
--
1.8.1.5
*1:
http://lists.linuxfoundation.org/pipermail/iommu/2013-November/007086.html
^ permalink raw reply related [flat|nested] 33+ messages in thread
* Re: [RFC][PATCHv6+++ 01/13] of: introduce of_property_for_earch_phandle_with_args()
2013-12-02 11:02 ` Hiroshi Doyu
@ 2013-12-02 14:39 ` Rob Herring
2013-12-03 6:46 ` Hiroshi Doyu
2013-12-03 20:14 ` Stephen Warren
1 sibling, 1 reply; 33+ messages in thread
From: Rob Herring @ 2013-12-02 14:39 UTC (permalink / raw)
To: Hiroshi Doyu
Cc: swarren, grant.likely, thierry.reding, joro, Stephen Warren,
will.deacon, mark.rutland, devicetree, iommu, linux-tegra,
linux-arm-kernel, lorenzo.pieralisi, galak, linux-kernel
On Mon, Dec 2, 2013 at 5:02 AM, Hiroshi Doyu <hdoyu@nvidia.com> wrote:
> Stephen Warren <swarren@wwwdotorg.org> wrote @ Sun, 1 Dec 2013 20:00:09 +0100:
>
>> On 11/29/2013 04:46 AM, Hiroshi Doyu wrote:
>> ...
>> > 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.
>> >
>> > Introduced a new struct "of_phandle_iter" to keep the state when
>> > iterating over the list.
>> >
>> > Signed-off-by: Hiroshi Doyu <hdoyu@nvidia.com>
>> > ---
>> > v6+++:
>>
>> Surely that's v9; "+++" is rather unusual.
>
> My intention was to put this into the next v7 series after I get this
> reviewed as RFC.
> ...
>> Together with removing:
>>
>> > + const char *cells_name;
>> > + int cell_count;
>>
>> ... then you'd only be left with cur/end, so I think you could get away
>> without a struct at all, but simply "cur" as the iterator variable, plus
>> "end" as the one temp variable.
>
> Although the above proposal would be alsmot same as "[RFC][PATCHv6++
> 01/13]"(*1) where I use *list(cur) and rem as remaining count, here's
> the update. I'll put this into v7 series.
>
> ---8<------8<------8<------8<------8<------8<------8<------8<------8<---
> From: Hiroshi Doyu <hdoyu@nvidia.com>
>
> 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@nvidia.com>
> ---
> v6++++:
> Iterate without intrducing a new struct.
>
> v6+++:
> Introduced a new struct "of_phandle_iter" to keep the state when
> iterating over the list.
>
> v6++:
> Optimized to avoid O(n^2), suggested by Stephen Warren.
> http://lists.linuxfoundation.org/pipermail/iommu/2013-November/007066.html
>
> I didn't introduce any struct to hold params and state here.
>
> v6+:
> Use the description, which Grant Likely proposed, to be full enough
> that a future reader can figure out why a patch was written.
>
> v5:
> New patch for v5.
>
> Signed-off-by: Hiroshi Doyu <hdoyu@nvidia.com>
> ---
> drivers/of/base.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++
> include/linux/of.h | 34 ++++++++++++++++++++++++++++++++++
> 2 files changed, 87 insertions(+)
>
> diff --git a/drivers/of/base.c b/drivers/of/base.c
> index f807d0e..7501f24 100644
> --- a/drivers/of/base.c
> +++ b/drivers/of/base.c
> @@ -1201,6 +1201,59 @@ void of_print_phandle_args(const char *msg, const struct of_phandle_args *args)
> printk("\n");
> }
>
> +const __be32 *of_phandle_iter_next(const char *cells_name, int cell_count,
> + const __be32 *cur, const __be32 *end,
> + struct of_phandle_args *out_args)
> +{
> + phandle phandle;
> + struct device_node *dn;
> + int i;
> +
> + if (!cells_name && !cell_count)
> + return NULL;
> +
> + if (!cur)
> + return NULL;
> +
> + if (end - cur <= 0)
These 2 if's can be combined: if (!cur || (end - cur <= 0))
> + return NULL;
> +
> + phandle = be32_to_cpup(cur++);
> + if (!phandle)
> + return NULL;
Won't of_find_node_by_phandle do this check?
> +
> + dn = of_find_node_by_phandle(phandle);
> + if (!dn)
> + return NULL;
> +
> + if (cells_name)
> + if (of_property_read_u32(dn, cells_name, &cell_count))
> + return NULL;
> +
> + out_args->np = dn;
> + out_args->args_count = cell_count;
> + for (i = 0; i < cell_count; i++)
> + out_args->args[i] = be32_to_cpup(cur++);
> +
> + return cur;
> +}
> +EXPORT_SYMBOL_GPL(of_phandle_iter_next);
> +
> +const __be32 *of_phandle_iter_init(const struct device_node *np,
> + const char *list_name,
> + const __be32 **end)
> +{
> + size_t bytes;
> + const __be32 *cur;
> +
> + cur = of_get_property(np, list_name, &bytes);
> + if (bytes)
> + *end = cur + bytes / sizeof(*cur);
> +
> + return cur;
> +}
> +EXPORT_SYMBOL_GPL(of_phandle_iter_init);
> +
> 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 276c546..c23710b 100644
> --- a/include/linux/of.h
> +++ b/include/linux/of.h
> @@ -303,6 +303,14 @@ 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 const __be32 *of_phandle_iter_init(const struct device_node *np,
> + const char *list_name,
> + const __be32 **end);
> +extern const __be32 *of_phandle_iter_next(const char *cells_name,
> + int cell_count,
> + const __be32 *cur, const __be32 *end,
> + struct of_phandle_args *out_args);
> +
> 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);
>
> @@ -527,6 +535,24 @@ static inline int of_count_phandle_with_args(struct device_node *np,
> return -ENOSYS;
> }
>
> +static inline const __be32 *of_phandle_iter_init(const struct device_node *np,
> + const char *list_name,
> + const char *cells_name,
> + const int cell_count,
> + struct of_phandle_args *out_args)
Need to update the arguments.
> +{
> + return NULL;
> +}
> +
> +static inline const __be32 *of_phandle_iter_next(const char *cells_name,
> + int cell_count,
> + const __be32 *cur,
> + const __be32 *end,
> + struct of_phandle_args *out_args);
> +{
> + return NULL;
> +}
> +
> static inline int of_alias_get_id(struct device_node *np, const char *stem)
> {
> return -ENOSYS;
> @@ -613,6 +639,14 @@ static inline int of_property_read_u32(const struct device_node *np,
> s; \
> s = of_prop_next_string(prop, s))
>
> +#define of_property_for_each_phandle_with_args(node, list_name, cells_name, \
Some extra whitespace here.
> + cell_count, out_args, cur, end) \
> + for (cur = of_phandle_iter_init(node, list_name, &end), \
> + cur = of_phandle_iter_next(cells_name, cell_count, \
> + cur, end, &out_args); \
> + cur; \
> + cur = of_phandle_iter_next(cells_name, cell_count, cur, end, &out_args))
> +
> #if defined(CONFIG_PROC_FS) && defined(CONFIG_PROC_DEVICETREE)
> extern void proc_device_tree_add_node(struct device_node *, struct proc_dir_entry *);
> extern void proc_device_tree_add_prop(struct proc_dir_entry *pde, struct property *prop);
> --
> 1.8.1.5
>
>
>
>
>
> *1:
> http://lists.linuxfoundation.org/pipermail/iommu/2013-November/007086.html
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [RFC][PATCHv6+++ 01/13] of: introduce of_property_for_earch_phandle_with_args()
2013-12-02 14:39 ` Rob Herring
@ 2013-12-03 6:46 ` Hiroshi Doyu
0 siblings, 0 replies; 33+ messages in thread
From: Hiroshi Doyu @ 2013-12-03 6:46 UTC (permalink / raw)
To: swarren, grant.likely, Rob Herring
Cc: thierry.reding, joro, Stephen Warren, will.deacon, mark.rutland,
devicetree, iommu, linux-tegra, linux-arm-kernel,
lorenzo.pieralisi, galak, linux-kernel
On Mon, 2 Dec 2013 15:39:25 +0100
Rob Herring <robherring2@gmail.com> wrote:
> On Mon, Dec 2, 2013 at 5:02 AM, Hiroshi Doyu <hdoyu@nvidia.com> wrote:
> > Stephen Warren <swarren@wwwdotorg.org> wrote @ Sun, 1 Dec 2013 20:00:09 +0100:
> >
> >> On 11/29/2013 04:46 AM, Hiroshi Doyu wrote:
> >> ...
> >> > 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.
> >> >
> >> > Introduced a new struct "of_phandle_iter" to keep the state when
> >> > iterating over the list.
> >> >
> >> > Signed-off-by: Hiroshi Doyu <hdoyu@nvidia.com>
....
Rob, thank you for review.
I'll fix them and put this one into the next v7 series.
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [RFC][PATCHv6+++ 01/13] of: introduce of_property_for_earch_phandle_with_args()
2013-12-02 11:02 ` Hiroshi Doyu
2013-12-02 14:39 ` Rob Herring
@ 2013-12-03 20:14 ` Stephen Warren
1 sibling, 0 replies; 33+ messages in thread
From: Stephen Warren @ 2013-12-03 20:14 UTC (permalink / raw)
To: Hiroshi Doyu
Cc: grant.likely, thierry.reding, robherring2, joro, Stephen Warren,
will.deacon, mark.rutland, devicetree, iommu, linux-tegra,
linux-arm-kernel, lorenzo.pieralisi, galak, linux-kernel
On 12/02/2013 04:02 AM, Hiroshi Doyu wrote:
...
> 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.
> diff --git a/drivers/of/base.c b/drivers/of/base.c
> +const __be32 *of_phandle_iter_init(const struct device_node *np,
> + const char *list_name,
> + const __be32 **end)
> +{
> + size_t bytes;
> + const __be32 *cur;
> +
> + cur = of_get_property(np, list_name, &bytes);
> + if (bytes)
> + *end = cur + bytes / sizeof(*cur);
> +
> + return cur;
> +}
"bytes" doesn't seem like the correct thing to check in that if
statement. The property might exist but be zero length. Perhaps if (cur)
would be better, or just initializing *end in all cases (the value won't
be used if (!cur), so setting *end to a bogus value in that case won't
matter).
> +const __be32 *of_phandle_iter_next(const char *cells_name, int cell_count,
> + const __be32 *cur, const __be32 *end,
> + struct of_phandle_args *out_args)
...
> + if (!cur)
> + return NULL;
> +
> + if (end - cur <= 0)
> + return NULL;
Related, don't you want if (cur >= end) there; just compare the pointers
directly rather than explicitly calculating and testing the difference?
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCHv6 05/13] iommu/core: add ops->{bound,unbind}_driver()
2013-11-25 13:49 ` Hiroshi Doyu
@ 2013-12-04 7:40 ` Hiroshi Doyu
2013-12-04 10:01 ` Will Deacon
0 siblings, 1 reply; 33+ messages in thread
From: Hiroshi Doyu @ 2013-12-04 7:40 UTC (permalink / raw)
To: joro
Cc: mark.rutland, devicetree, lorenzo.pieralisi, Stephen Warren,
swarren, will.deacon, linux-kernel, linux-tegra, iommu,
thierry.reding, robherring2, galak, grant.likely,
linux-arm-kernel
On Mon, 25 Nov 2013 14:49:37 +0100
Hiroshi Doyu <hdoyu@nvidia.com> wrote:
> Hi Joerg,
>
> Do you have some time to review this patch along with the following ones?
>
> [PATCHv6 02/13] iommu/of: introduce a global iommu device list
> http://lists.linuxfoundation.org/pipermail/iommu/2013-November/007050.html
>
> [PATCHv6 03/13] iommu/of: check if dependee iommu is ready or not
> http://lists.linuxfoundation.org/pipermail/iommu/2013-November/007051.html
Any chance to get some feedback on them?
> With those patches, now I'm trying to populate iommu master devices
> after an IOMMU device is populated. Originally [PATCHv6 02/13] was
> proposed by Thierry. I'm a bit afraid of adding new IOMMU API as
> this, but I think that this new {bound,unbind}_driver() is the right
> timiing that depeding devices are populated instead of add_device()
> since, even after add_device, a device won't be populated. I'm not so
> sure how this affects on the existing IOMMUs.
>
> It would be nice if you give some feedback on this.
>
> On Thu, 21 Nov 2013 14:40:41 +0100
> Hiroshi Doyu <hdoyu@nvidia.com> wrote:
>
> > 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@nvidia.com>
> > ---
> > v6:
> > New for v6.
> > ---
> > 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 e5555fc..5469d36 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 a444c79..a0e92be 100644
> > --- a/include/linux/iommu.h
> > +++ b/include/linux/iommu.h
> > @@ -96,6 +96,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
> > @@ -114,6 +116,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);
> > --
> > 1.8.1.5
> >
> _______________________________________________
> iommu mailing list
> iommu@lists.linux-foundation.org
> https://lists.linuxfoundation.org/mailman/listinfo/iommu
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCHv6 05/13] iommu/core: add ops->{bound,unbind}_driver()
2013-12-04 7:40 ` Hiroshi Doyu
@ 2013-12-04 10:01 ` Will Deacon
0 siblings, 0 replies; 33+ messages in thread
From: Will Deacon @ 2013-12-04 10:01 UTC (permalink / raw)
To: Hiroshi Doyu
Cc: joro, Mark Rutland, devicetree, Lorenzo Pieralisi,
Stephen Warren, swarren, linux-kernel, linux-tegra, iommu,
thierry.reding, robherring2, galak, grant.likely,
linux-arm-kernel, alex.williamson
Hi Hiroshi,
On Wed, Dec 04, 2013 at 07:40:27AM +0000, Hiroshi Doyu wrote:
> On Mon, 25 Nov 2013 14:49:37 +0100
> Hiroshi Doyu <hdoyu@nvidia.com> wrote:
>
> > Hi Joerg,
> >
> > Do you have some time to review this patch along with the following ones?
> >
> > [PATCHv6 02/13] iommu/of: introduce a global iommu device list
> > http://lists.linuxfoundation.org/pipermail/iommu/2013-November/007050.html
> >
> > [PATCHv6 03/13] iommu/of: check if dependee iommu is ready or not
> > http://lists.linuxfoundation.org/pipermail/iommu/2013-November/007051.html
>
> Any chance to get some feedback on them?
Joerg is on holiday at the moment, but Alex Williamson is serving as interim
IOMMU maintainer at the moment. Adding him to CC, but this probably needs an
Ack from Joerg regardless, so you will need to wait for him to come back.
Will
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCHv6+ 01/13] of: introduce of_property_for_earch_phandle_with_args()
2013-11-21 17:17 ` [PATCHv6+ " Hiroshi Doyu
2013-11-21 18:57 ` Stephen Warren
@ 2013-12-11 13:27 ` Grant Likely
1 sibling, 0 replies; 33+ messages in thread
From: Grant Likely @ 2013-12-11 13:27 UTC (permalink / raw)
To: Hiroshi Doyu
Cc: thierry.reding, swarren, robherring2, joro, Stephen Warren,
will.deacon, Hiroshi Doyu, mark.rutland, devicetree, iommu,
linux-tegra, linux-arm-kernel, lorenzo.pieralisi, galak,
linux-kernel
On Thu, 21 Nov 2013 18:17:20 +0100, Hiroshi Doyu <hdoyu@nvidia.com> wrote:
> 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@nvidia.com>
Acked-by: Grant Likely <grant.likely@linaro.org>
This patch can be merged with the rest of the series.
g.
> ---
> v6+:
> Use the description, which Grant Likely proposed, to be full enough
> that a future reader can figure out why a patch was written.
> http://lists.linuxfoundation.org/pipermail/iommu/2013-November/007062.html
>
> v5:
> New patch for v5.
> ---
> include/linux/of.h | 3 +++
> 1 file changed, 3 insertions(+)
>
> diff --git a/include/linux/of.h b/include/linux/of.h
> index 276c546..131fef5 100644
> --- a/include/linux/of.h
> +++ b/include/linux/of.h
> @@ -613,6 +613,9 @@ static inline int of_property_read_u32(const struct device_node *np,
> s; \
> s = of_prop_next_string(prop, s))
>
> +#define of_property_for_each_phandle_with_args(np, list, cells, i, args) \
> + for (i = 0; !of_parse_phandle_with_args(np, list, cells, i, args); i++)
> +
> #if defined(CONFIG_PROC_FS) && defined(CONFIG_PROC_DEVICETREE)
> extern void proc_device_tree_add_node(struct device_node *, struct proc_dir_entry *);
> extern void proc_device_tree_add_prop(struct proc_dir_entry *pde, struct property *prop);
> --
> 1.8.1.5
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCHv6+ 01/13] of: introduce of_property_for_earch_phandle_with_args()
2013-11-21 18:57 ` Stephen Warren
2013-11-28 12:58 ` [RFC][PATCHv6++ " Hiroshi Doyu
@ 2013-12-11 13:28 ` Grant Likely
2013-12-11 13:33 ` Hiroshi Doyu
1 sibling, 1 reply; 33+ messages in thread
From: Grant Likely @ 2013-12-11 13:28 UTC (permalink / raw)
To: Stephen Warren, Hiroshi Doyu
Cc: thierry.reding, robherring2, joro, Stephen Warren, will.deacon,
mark.rutland, devicetree, iommu, linux-tegra, linux-arm-kernel,
lorenzo.pieralisi, galak, linux-kernel
On Thu, 21 Nov 2013 11:57:00 -0700, Stephen Warren <swarren@wwwdotorg.org> wrote:
> On 11/21/2013 10:17 AM, Hiroshi Doyu wrote:
> > 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@nvidia.com>
> > ---
> > v6+:
> > Use the description, which Grant Likely proposed, to be full enough
> > that a future reader can figure out why a patch was written.
> > http://lists.linuxfoundation.org/pipermail/iommu/2013-November/007062.html
>
> This new version only addresses one of the concerns that Grant had,
> namely the commit message.
>
> > diff --git a/include/linux/of.h b/include/linux/of.h
>
> > +#define of_property_for_each_phandle_with_args(np, list, cells, i, args) \
> > + for (i = 0; !of_parse_phandle_with_args(np, list, cells, i, args); i++)
> > +
>
> Grant also wanted the actual implementation fixed so that it wasn't so
> inefficient.
>
> What this current patch does is basically:
>
> for every entry in the property:
> for every entry in the property before the current index:
> parse the phandle+specifier
>
> That's roughly O(n^2). (n is # entries in the property)
>
> Instead, what should happen is:
>
> for every entry in the property:
> parse the phandle+specifier
> yield the result
>
> That's roughly O(n).
>
> In other words, an implementation more along the lines of
> include/linux/of.h's:
>
> #define of_property_for_each_u32(np, propname, prop, p, u) \
> for (prop = of_find_property(np, propname, NULL), \
> p = of_prop_next_u32(prop, NULL, &u); \
> p; \
> p = of_prop_next_u32(prop, p, &u))
>
> ... so you'd need functions like of_prop_first_specifier() and
> of_prop_next_specifier(), and perhaps some associated set of state
> variables, perhaps with all the state wrapped into a single struct for
> simplicity.
That's right, I forgot I said that. Yes please fix the implementation.
g.
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCHv6+ 01/13] of: introduce of_property_for_earch_phandle_with_args()
2013-12-11 13:28 ` [PATCHv6+ " Grant Likely
@ 2013-12-11 13:33 ` Hiroshi Doyu
2013-12-12 11:34 ` Grant Likely
0 siblings, 1 reply; 33+ messages in thread
From: Hiroshi Doyu @ 2013-12-11 13:33 UTC (permalink / raw)
To: grant.likely
Cc: swarren, thierry.reding, robherring2, joro, Stephen Warren,
will.deacon, mark.rutland, devicetree, iommu, linux-tegra,
linux-arm-kernel, lorenzo.pieralisi, galak, linux-kernel
Hi Grant,
Grant Likely <grant.likely@linaro.org> wrote @ Wed, 11 Dec 2013 14:28:45 +0100:
> On Thu, 21 Nov 2013 11:57:00 -0700, Stephen Warren <swarren@wwwdotorg.org> wrote:
> > On 11/21/2013 10:17 AM, Hiroshi Doyu wrote:
> > > 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@nvidia.com>
> > > ---
> > > v6+:
> > > Use the description, which Grant Likely proposed, to be full enough
> > > that a future reader can figure out why a patch was written.
> > > http://lists.linuxfoundation.org/pipermail/iommu/2013-November/007062.html
...
> That's right, I forgot I said that. Yes please fix the implementation.
Here's the latest. I'll include this with the next v7 series.
Can I get your Acked-by with this?
--8<----
>From 8f7c0404aa68f0e8dbe0babc240590f6528ecc1f Mon Sep 17 00:00:00 2001
From: Hiroshi Doyu <hdoyu@nvidia.com>
Date: Fri, 15 Nov 2013 10:52:53 +0200
Subject: [PATCH] of: introduce of_property_for_each_phandle_with_args()
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@nvidia.com>
Cc: Rob Herring <robherring2@gmail.com>
---
v7:
Fixed some minors pointed by Rob and Stephen.
v6++++:
Iterate without intrducing a new struct.
v6+++:
Introduced a new struct "of_phandle_iter" to keep the state when
iterating over the list.
v6++:
Optimized to avoid O(n^2), suggested by Stephen Warren.
http://lists.linuxfoundation.org/pipermail/iommu/2013-November/007066.html
I didn't introduce any struct to hold params and state here.
v6+:
Use the description, which Grant Likely proposed, to be full enough
that a future reader can figure out why a patch was written.
v5:
New patch for v5.
Signed-off-by: Hiroshi Doyu <hdoyu@nvidia.com>
---
drivers/of/base.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++
include/linux/of.h | 32 ++++++++++++++++++++++++++++++++
2 files changed, 78 insertions(+)
diff --git a/drivers/of/base.c b/drivers/of/base.c
index f807d0e..cd4ab05 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -1201,6 +1201,52 @@ void of_print_phandle_args(const char *msg, const struct of_phandle_args *args)
printk("\n");
}
+const __be32 *of_phandle_iter_next(const char *cells_name, int cell_count,
+ const __be32 *cur, const __be32 *end,
+ struct of_phandle_args *out_args)
+{
+ struct device_node *dn;
+ int i;
+
+ if (!cells_name && !cell_count)
+ return NULL;
+
+ if (!cur || (cur >= end))
+ return NULL;
+
+ dn = of_find_node_by_phandle(be32_to_cpup(cur++));
+ if (!dn)
+ return NULL;
+
+ if (cells_name)
+ if (of_property_read_u32(dn, cells_name, &cell_count))
+ return NULL;
+
+ out_args->np = dn;
+ out_args->args_count = cell_count;
+ for (i = 0; i < cell_count; i++)
+ out_args->args[i] = be32_to_cpup(cur++);
+
+ return cur;
+}
+EXPORT_SYMBOL_GPL(of_phandle_iter_next);
+
+const __be32 *of_phandle_iter_init(const struct device_node *np,
+ const char *list_name,
+ const __be32 **end)
+{
+ size_t bytes;
+ const __be32 *cur;
+
+ cur = of_get_property(np, list_name, &bytes);
+ *end = cur;
+ if (bytes)
+ *end += bytes / sizeof(*cur);
+
+ return cur;
+}
+EXPORT_SYMBOL_GPL(of_phandle_iter_init);
+
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 276c546..4345582 100644
--- a/include/linux/of.h
+++ b/include/linux/of.h
@@ -303,6 +303,14 @@ 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 const __be32 *of_phandle_iter_init(const struct device_node *np,
+ const char *list_name,
+ const __be32 **end);
+extern const __be32 *of_phandle_iter_next(const char *cells_name,
+ int cell_count,
+ const __be32 *cur, const __be32 *end,
+ struct of_phandle_args *out_args);
+
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);
@@ -527,6 +535,22 @@ static inline int of_count_phandle_with_args(struct device_node *np,
return -ENOSYS;
}
+static inline const __be32 *of_phandle_iter_init(const struct device_node *np,
+ const char *list_name,
+ const __be32 **end)
+{
+ return NULL;
+}
+
+static inline const __be32 *of_phandle_iter_next(const char *cells_name,
+ int cell_count,
+ const __be32 *cur,
+ const __be32 *end,
+ struct of_phandle_args *out_args);
+{
+ return NULL;
+}
+
static inline int of_alias_get_id(struct device_node *np, const char *stem)
{
return -ENOSYS;
@@ -613,6 +637,14 @@ static inline int of_property_read_u32(const struct device_node *np,
s; \
s = of_prop_next_string(prop, s))
+#define of_property_for_each_phandle_with_args(node, list_name, cells_name, \
+ cell_count, out_args, cur, end) \
+ for (cur = of_phandle_iter_init(node, list_name, &end), \
+ cur = of_phandle_iter_next(cells_name, cell_count, \
+ cur, end, &out_args); \
+ cur; \
+ cur = of_phandle_iter_next(cells_name, cell_count, cur, end, &out_args))
+
#if defined(CONFIG_PROC_FS) && defined(CONFIG_PROC_DEVICETREE)
extern void proc_device_tree_add_node(struct device_node *, struct proc_dir_entry *);
extern void proc_device_tree_add_prop(struct proc_dir_entry *pde, struct property *prop);
--
1.8.1.5
^ permalink raw reply related [flat|nested] 33+ messages in thread
* Re: [PATCHv6+ 01/13] of: introduce of_property_for_earch_phandle_with_args()
2013-12-11 13:33 ` Hiroshi Doyu
@ 2013-12-12 11:34 ` Grant Likely
2013-12-12 12:14 ` Hiroshi Doyu
0 siblings, 1 reply; 33+ messages in thread
From: Grant Likely @ 2013-12-12 11:34 UTC (permalink / raw)
To: Hiroshi Doyu
Cc: swarren, thierry.reding, robherring2, joro, Stephen Warren,
will.deacon, mark.rutland, devicetree, iommu, linux-tegra,
linux-arm-kernel, lorenzo.pieralisi, galak, linux-kernel
On Wed, 11 Dec 2013 14:33:38 +0100, Hiroshi Doyu <hdoyu@nvidia.com> wrote:
> Hi Grant,
>
> Grant Likely <grant.likely@linaro.org> wrote @ Wed, 11 Dec 2013 14:28:45 +0100:
>
> > On Thu, 21 Nov 2013 11:57:00 -0700, Stephen Warren <swarren@wwwdotorg.org> wrote:
> > > On 11/21/2013 10:17 AM, Hiroshi Doyu wrote:
> > > > 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@nvidia.com>
> > > > ---
> > > > v6+:
> > > > Use the description, which Grant Likely proposed, to be full enough
> > > > that a future reader can figure out why a patch was written.
> > > > http://lists.linuxfoundation.org/pipermail/iommu/2013-November/007062.html
> ...
>
> > That's right, I forgot I said that. Yes please fix the implementation.
>
> Here's the latest. I'll include this with the next v7 series.
>
> Can I get your Acked-by with this?
>
> --8<----
>
> From 8f7c0404aa68f0e8dbe0babc240590f6528ecc1f Mon Sep 17 00:00:00 2001
> From: Hiroshi Doyu <hdoyu@nvidia.com>
> Date: Fri, 15 Nov 2013 10:52:53 +0200
> Subject: [PATCH] of: introduce of_property_for_each_phandle_with_args()
>
> 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@nvidia.com>
> Cc: Rob Herring <robherring2@gmail.com>
> ---
> v7:
> Fixed some minors pointed by Rob and Stephen.
>
> v6++++:
> Iterate without intrducing a new struct.
>
> v6+++:
> Introduced a new struct "of_phandle_iter" to keep the state when
> iterating over the list.
>
> v6++:
> Optimized to avoid O(n^2), suggested by Stephen Warren.
> http://lists.linuxfoundation.org/pipermail/iommu/2013-November/007066.html
>
> I didn't introduce any struct to hold params and state here.
>
> v6+:
> Use the description, which Grant Likely proposed, to be full enough
> that a future reader can figure out why a patch was written.
>
> v5:
> New patch for v5.
>
> Signed-off-by: Hiroshi Doyu <hdoyu@nvidia.com>
> ---
> drivers/of/base.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++
> include/linux/of.h | 32 ++++++++++++++++++++++++++++++++
> 2 files changed, 78 insertions(+)
>
> diff --git a/drivers/of/base.c b/drivers/of/base.c
> index f807d0e..cd4ab05 100644
> --- a/drivers/of/base.c
> +++ b/drivers/of/base.c
> @@ -1201,6 +1201,52 @@ void of_print_phandle_args(const char *msg, const struct of_phandle_args *args)
> printk("\n");
> }
>
> +const __be32 *of_phandle_iter_next(const char *cells_name, int cell_count,
> + const __be32 *cur, const __be32 *end,
> + struct of_phandle_args *out_args)
Having to pass in cells_name, cell_count, cur and end each time seems a
little odd. Can a state structure be used instead?
struct of_phandle_iter_state {
const char *cells_name;
int cells_count;
const __be32 *cur;
const __be32 *end;
struct of_phandle_args out_args;
}
Make the caller provide one of those and fill it in with the init
function.
> +{
> + struct device_node *dn;
> + int i;
> +
> + if (!cells_name && !cell_count)
> + return NULL;
> +
> + if (!cur || (cur >= end))
> + return NULL;
> +
> + dn = of_find_node_by_phandle(be32_to_cpup(cur++));
> + if (!dn)
> + return NULL;
> +
> + if (cells_name)
> + if (of_property_read_u32(dn, cells_name, &cell_count))
> + return NULL;
> +
> + out_args->np = dn;
> + out_args->args_count = cell_count;
> + for (i = 0; i < cell_count; i++)
> + out_args->args[i] = be32_to_cpup(cur++);
> +
> + return cur;
> +}
> +EXPORT_SYMBOL_GPL(of_phandle_iter_next);
> +
> +const __be32 *of_phandle_iter_init(const struct device_node *np,
> + const char *list_name,
> + const __be32 **end)
> +{
> + size_t bytes;
> + const __be32 *cur;
> +
> + cur = of_get_property(np, list_name, &bytes);
> + *end = cur;
> + if (bytes)
> + *end += bytes / sizeof(*cur);
> +
> + return cur;
> +}
> +EXPORT_SYMBOL_GPL(of_phandle_iter_init);
> +
> 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 276c546..4345582 100644
> --- a/include/linux/of.h
> +++ b/include/linux/of.h
> @@ -303,6 +303,14 @@ 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 const __be32 *of_phandle_iter_init(const struct device_node *np,
> + const char *list_name,
> + const __be32 **end);
> +extern const __be32 *of_phandle_iter_next(const char *cells_name,
> + int cell_count,
> + const __be32 *cur, const __be32 *end,
> + struct of_phandle_args *out_args);
> +
> 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);
>
> @@ -527,6 +535,22 @@ static inline int of_count_phandle_with_args(struct device_node *np,
> return -ENOSYS;
> }
>
> +static inline const __be32 *of_phandle_iter_init(const struct device_node *np,
> + const char *list_name,
> + const __be32 **end)
> +{
> + return NULL;
> +}
> +
> +static inline const __be32 *of_phandle_iter_next(const char *cells_name,
> + int cell_count,
> + const __be32 *cur,
> + const __be32 *end,
> + struct of_phandle_args *out_args);
> +{
> + return NULL;
> +}
> +
> static inline int of_alias_get_id(struct device_node *np, const char *stem)
> {
> return -ENOSYS;
> @@ -613,6 +637,14 @@ static inline int of_property_read_u32(const struct device_node *np,
> s; \
> s = of_prop_next_string(prop, s))
>
> +#define of_property_for_each_phandle_with_args(node, list_name, cells_name, \
> + cell_count, out_args, cur, end) \
> + for (cur = of_phandle_iter_init(node, list_name, &end), \
> + cur = of_phandle_iter_next(cells_name, cell_count, \
> + cur, end, &out_args); \
The above construct is a little odd. Why wouldn't the initializer
provide the first element (or NULL if empty) right at the start. That in
combination with the suggestion I made above would change the macro to
be:
#define of_property_for_each_phandle_with_args(node, list_name, cells_name, \
cell_count, &iter_state) \
for (cur = of_phandle_iter_init(node, list_name, cells_name, \
cells_count, &iter_state); \
cur; cur = of_phandle_iter_next(&iter_state)) \
Simpler, right? It also means whatever the user passed in for
cells_name, cell_count won't get evaluated every time through the loop.
g.
> + cur; \
> + cur = of_phandle_iter_next(cells_name, cell_count, cur, end, &out_args))
> +
> #if defined(CONFIG_PROC_FS) && defined(CONFIG_PROC_DEVICETREE)
> extern void proc_device_tree_add_node(struct device_node *, struct proc_dir_entry *);
> extern void proc_device_tree_add_prop(struct proc_dir_entry *pde, struct property *prop);
> --
> 1.8.1.5
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCHv6+ 01/13] of: introduce of_property_for_earch_phandle_with_args()
2013-12-12 11:34 ` Grant Likely
@ 2013-12-12 12:14 ` Hiroshi Doyu
2013-12-14 15:51 ` Hiroshi Doyu
0 siblings, 1 reply; 33+ messages in thread
From: Hiroshi Doyu @ 2013-12-12 12:14 UTC (permalink / raw)
To: swarren, grant.likely
Cc: thierry.reding, robherring2, joro, Stephen Warren, will.deacon,
mark.rutland, devicetree, iommu, linux-tegra, linux-arm-kernel,
lorenzo.pieralisi, galak, linux-kernel
Grant Likely <grant.likely@linaro.org> wrote @ Thu, 12 Dec 2013 12:34:17 +0100:
> On Wed, 11 Dec 2013 14:33:38 +0100, Hiroshi Doyu <hdoyu@nvidia.com> wrote:
> > Hi Grant,
> >
> > Grant Likely <grant.likely@linaro.org> wrote @ Wed, 11 Dec 2013 14:28:45 +0100:
> >
> > > On Thu, 21 Nov 2013 11:57:00 -0700, Stephen Warren <swarren@wwwdotorg.org> wrote:
> > > > On 11/21/2013 10:17 AM, Hiroshi Doyu wrote:
> > > > > 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@nvidia.com>
> > > > > ---
> > > > > v6+:
> > > > > Use the description, which Grant Likely proposed, to be full enough
> > > > > that a future reader can figure out why a patch was written.
> > > > > http://lists.linuxfoundation.org/pipermail/iommu/2013-November/007062.html
> > ...
> >
> > > That's right, I forgot I said that. Yes please fix the implementation.
> >
> > Here's the latest. I'll include this with the next v7 series.
> >
> > Can I get your Acked-by with this?
> >
> > --8<----
> >
> > From 8f7c0404aa68f0e8dbe0babc240590f6528ecc1f Mon Sep 17 00:00:00 2001
> > From: Hiroshi Doyu <hdoyu@nvidia.com>
> > Date: Fri, 15 Nov 2013 10:52:53 +0200
> > Subject: [PATCH] of: introduce of_property_for_each_phandle_with_args()
> >
> > 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@nvidia.com>
> > Cc: Rob Herring <robherring2@gmail.com>
> > ---
> > v7:
> > Fixed some minors pointed by Rob and Stephen.
> >
> > v6++++:
> > Iterate without intrducing a new struct.
> >
> > v6+++:
> > Introduced a new struct "of_phandle_iter" to keep the state when
> > iterating over the list.
> >
> > v6++:
> > Optimized to avoid O(n^2), suggested by Stephen Warren.
> > http://lists.linuxfoundation.org/pipermail/iommu/2013-November/007066.html
> >
> > I didn't introduce any struct to hold params and state here.
> >
> > v6+:
> > Use the description, which Grant Likely proposed, to be full enough
> > that a future reader can figure out why a patch was written.
> >
> > v5:
> > New patch for v5.
> >
> > Signed-off-by: Hiroshi Doyu <hdoyu@nvidia.com>
> > ---
> > drivers/of/base.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++
> > include/linux/of.h | 32 ++++++++++++++++++++++++++++++++
> > 2 files changed, 78 insertions(+)
> >
> > diff --git a/drivers/of/base.c b/drivers/of/base.c
> > index f807d0e..cd4ab05 100644
> > --- a/drivers/of/base.c
> > +++ b/drivers/of/base.c
> > @@ -1201,6 +1201,52 @@ void of_print_phandle_args(const char *msg, const struct of_phandle_args *args)
> > printk("\n");
> > }
> >
> > +const __be32 *of_phandle_iter_next(const char *cells_name, int cell_count,
> > + const __be32 *cur, const __be32 *end,
> > + struct of_phandle_args *out_args)
>
> Having to pass in cells_name, cell_count, cur and end each time seems a
> little odd. Can a state structure be used instead?
>
> struct of_phandle_iter_state {
> const char *cells_name;
> int cells_count;
> const __be32 *cur;
> const __be32 *end;
> struct of_phandle_args out_args;
> }
>
> Make the caller provide one of those and fill it in with the init
> function.
I rewrote this a few times and so now I have a few version of this
implementations :-) The above proposal is similar to the version v6+++
mentioned in the above patch note:
> > v6+++:
> > Introduced a new struct "of_phandle_iter" to keep the state when
> > iterating over the list.
which is:
[RFC][PATCHv6+++ 01/13] of: introduce of_property_for_earch_phandle_with_args()
http://lists.linuxfoundation.org/pipermail/iommu/2013-November/007087.html
Stephen seemed to prefer the version without state struct. I like the
idea to not pass the same arguments repeatly. Instead, wrapping them
in a struct with state may look better.
So if Stephen agrees, I'll rewrite the version with state struct
again.
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCHv6+ 01/13] of: introduce of_property_for_earch_phandle_with_args()
2013-12-12 12:14 ` Hiroshi Doyu
@ 2013-12-14 15:51 ` Hiroshi Doyu
2013-12-16 17:14 ` Stephen Warren
0 siblings, 1 reply; 33+ messages in thread
From: Hiroshi Doyu @ 2013-12-14 15:51 UTC (permalink / raw)
To: Stephen Warren, swarren
Cc: thierry.reding, robherring2, joro, grant.likely, will.deacon,
mark.rutland, devicetree, iommu, linux-tegra, linux-arm-kernel,
lorenzo.pieralisi, galak, linux-kernel
Hiroshi Doyu <hdoyu@nvidia.com> wrote @ Thu, 12 Dec 2013 14:14:04 +0200 (EET):
> > > From 8f7c0404aa68f0e8dbe0babc240590f6528ecc1f Mon Sep 17 00:00:00 2001
> > > From: Hiroshi Doyu <hdoyu@nvidia.com>
> > > Date: Fri, 15 Nov 2013 10:52:53 +0200
> > > Subject: [PATCH] of: introduce of_property_for_each_phandle_with_args()
> > >
> > > 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@nvidia.com>
> > > Cc: Rob Herring <robherring2@gmail.com>
....
> > > ---
> > > drivers/of/base.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++
> > > include/linux/of.h | 32 ++++++++++++++++++++++++++++++++
> > > 2 files changed, 78 insertions(+)
> > >
> > > diff --git a/drivers/of/base.c b/drivers/of/base.c
> > > index f807d0e..cd4ab05 100644
> > > --- a/drivers/of/base.c
> > > +++ b/drivers/of/base.c
> > > @@ -1201,6 +1201,52 @@ void of_print_phandle_args(const char *msg, const struct of_phandle_args *args)
> > > printk("\n");
> > > }
> > >
> > > +const __be32 *of_phandle_iter_next(const char *cells_name, int cell_count,
> > > + const __be32 *cur, const __be32 *end,
> > > + struct of_phandle_args *out_args)
> >
> > Having to pass in cells_name, cell_count, cur and end each time seems a
> > little odd. Can a state structure be used instead?
> >
> > struct of_phandle_iter_state {
> > const char *cells_name;
> > int cells_count;
> > const __be32 *cur;
> > const __be32 *end;
> > struct of_phandle_args out_args;
> > }
> >
> > Make the caller provide one of those and fill it in with the init
> > function.
>
> I rewrote this a few times and so now I have a few version of this
> implementations :-) The above proposal is similar to the version v6+++
> mentioned in the above patch note:
>
> > > v6+++:
> > > Introduced a new struct "of_phandle_iter" to keep the state when
> > > iterating over the list.
>
> which is:
>
> [RFC][PATCHv6+++ 01/13] of: introduce of_property_for_earch_phandle_with_args()
> http://lists.linuxfoundation.org/pipermail/iommu/2013-November/007087.html
>
> Stephen seemed to prefer the version without state struct. I like the
> idea to not pass the same arguments repeatly. Instead, wrapping them
> in a struct with state may look better.
>
> So if Stephen agrees, I'll rewrite the version with state struct
> again.
Stephen, let me know what you think.
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCHv6+ 01/13] of: introduce of_property_for_earch_phandle_with_args()
2013-12-14 15:51 ` Hiroshi Doyu
@ 2013-12-16 17:14 ` Stephen Warren
0 siblings, 0 replies; 33+ messages in thread
From: Stephen Warren @ 2013-12-16 17:14 UTC (permalink / raw)
To: Hiroshi Doyu, Stephen Warren
Cc: thierry.reding, robherring2, joro, grant.likely, will.deacon,
mark.rutland, devicetree, iommu, linux-tegra, linux-arm-kernel,
lorenzo.pieralisi, galak, linux-kernel
On 12/14/2013 08:51 AM, Hiroshi Doyu wrote:
> Hiroshi Doyu <hdoyu@nvidia.com> wrote @ Thu, 12 Dec 2013 14:14:04 +0200 (EET):
>
>>>> From 8f7c0404aa68f0e8dbe0babc240590f6528ecc1f Mon Sep 17 00:00:00 2001
>>>> From: Hiroshi Doyu <hdoyu@nvidia.com>
>>>> Date: Fri, 15 Nov 2013 10:52:53 +0200
>>>> Subject: [PATCH] of: introduce of_property_for_each_phandle_with_args()
>>>>
>>>> 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@nvidia.com>
>>>> Cc: Rob Herring <robherring2@gmail.com>
> ....
>>>> ---
>>>> drivers/of/base.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++
>>>> include/linux/of.h | 32 ++++++++++++++++++++++++++++++++
>>>> 2 files changed, 78 insertions(+)
>>>>
>>>> diff --git a/drivers/of/base.c b/drivers/of/base.c
>>>> index f807d0e..cd4ab05 100644
>>>> --- a/drivers/of/base.c
>>>> +++ b/drivers/of/base.c
>>>> @@ -1201,6 +1201,52 @@ void of_print_phandle_args(const char *msg, const struct of_phandle_args *args)
>>>> printk("\n");
>>>> }
>>>>
>>>> +const __be32 *of_phandle_iter_next(const char *cells_name, int cell_count,
>>>> + const __be32 *cur, const __be32 *end,
>>>> + struct of_phandle_args *out_args)
>>>
>>> Having to pass in cells_name, cell_count, cur and end each time seems a
>>> little odd. Can a state structure be used instead?
>>>
>>> struct of_phandle_iter_state {
>>> const char *cells_name;
>>> int cells_count;
>>> const __be32 *cur;
>>> const __be32 *end;
>>> struct of_phandle_args out_args;
>>> }
>>>
>>> Make the caller provide one of those and fill it in with the init
>>> function.
>>
>> I rewrote this a few times and so now I have a few version of this
>> implementations :-) The above proposal is similar to the version v6+++
>> mentioned in the above patch note:
>>
>>>> v6+++:
>>>> Introduced a new struct "of_phandle_iter" to keep the state when
>>>> iterating over the list.
>>
>> which is:
>>
>> [RFC][PATCHv6+++ 01/13] of: introduce of_property_for_earch_phandle_with_args()
>> http://lists.linuxfoundation.org/pipermail/iommu/2013-November/007087.html
>>
>> Stephen seemed to prefer the version without state struct. I like the
>> idea to not pass the same arguments repeatly. Instead, wrapping them
>> in a struct with state may look better.
>>
>> So if Stephen agrees, I'll rewrite the version with state struct
>> again.
>
> Stephen, let me know what you think.
It's hard to follow there have been so many revisions. As long as the
result is reasonable, I'll be OK with it. IIRC, I objected to using a
state structure for values that weren't needed by both functions, but if
both functions need the values, that's fine. I suppose even if they
don't both need the values, putting them in a state structure is OK too
if it means the patch gets finished!
^ permalink raw reply [flat|nested] 33+ messages in thread
end of thread, other threads:[~2013-12-16 17:14 UTC | newest]
Thread overview: 33+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-11-21 13:40 [PATCHv6 00/13] Unifying SMMU driver among Tegra SoCs Hiroshi Doyu
[not found] ` < 1385041249-7705-2-git-send-email-hdoyu@nvidia.com>
2013-11-21 13:40 ` [PATCHv6 01/13] of: introduce of_property_for_earch_phandle_with_args() Hiroshi Doyu
2013-11-21 17:17 ` [PATCHv6+ " Hiroshi Doyu
2013-11-21 18:57 ` Stephen Warren
2013-11-28 12:58 ` [RFC][PATCHv6++ " Hiroshi Doyu
2013-11-29 11:46 ` [RFC][PATCHv6+++ " Hiroshi Doyu
2013-12-01 19:00 ` Stephen Warren
2013-12-02 11:02 ` Hiroshi Doyu
2013-12-02 14:39 ` Rob Herring
2013-12-03 6:46 ` Hiroshi Doyu
2013-12-03 20:14 ` Stephen Warren
2013-12-11 13:28 ` [PATCHv6+ " Grant Likely
2013-12-11 13:33 ` Hiroshi Doyu
2013-12-12 11:34 ` Grant Likely
2013-12-12 12:14 ` Hiroshi Doyu
2013-12-14 15:51 ` Hiroshi Doyu
2013-12-16 17:14 ` Stephen Warren
2013-12-11 13:27 ` Grant Likely
2013-11-21 13:40 ` [PATCHv6 02/13] iommu/of: introduce a global iommu device list Hiroshi Doyu
2013-11-21 13:40 ` [PATCHv6 03/13] iommu/of: check if dependee iommu is ready or not Hiroshi Doyu
2013-11-21 13:40 ` [PATCHv6 04/13] driver/core: populate devices in order for IOMMUs Hiroshi Doyu
2013-11-21 13:40 ` [PATCHv6 05/13] iommu/core: add ops->{bound,unbind}_driver() Hiroshi Doyu
2013-11-25 13:49 ` Hiroshi Doyu
2013-12-04 7:40 ` Hiroshi Doyu
2013-12-04 10:01 ` Will Deacon
2013-11-21 13:40 ` [PATCHv6 06/13] ARM: tegra: create a DT header defining SWGROUP ID Hiroshi Doyu
2013-11-21 13:40 ` [PATCHv6 07/13] iommu/tegra: smmu: register device to iommu dynamically Hiroshi Doyu
2013-11-21 13:40 ` [PATCHv6 08/13] iommu/tegra: smmu: calculate ASID register offset by ID Hiroshi Doyu
2013-11-21 13:40 ` [PATCHv6 09/13] iommu/tegra: smmu: get swgroups from DT "iommus=" Hiroshi Doyu
2013-11-21 13:40 ` [PATCHv6 10/13] iommu/tegra: smmu: allow duplicate ASID wirte Hiroshi Doyu
2013-11-21 13:40 ` [PATCHv6 11/13] iommu/tegra: smmu: Rename hwgrp -> swgroups Hiroshi Doyu
2013-11-21 13:40 ` [PATCHv6 12/13] iommu/tegra: smmu: add SMMU to an global iommu list Hiroshi Doyu
2013-11-21 13:40 ` [PATCHv6 13/13] [FOR TEST] ARM: dt: tegra30: add "iommus" binding Hiroshi Doyu
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).