Unifying SMMU driver among Tegra SoCs
Subsystems (7)
v6 cover Unifying SMMU driver among Tegra SoCs
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 at nv-tegra.nvidia.com/user/hdoyu/linux.git smmu-upstreaming at 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
Signature · 1 line
1.8.1.5
PATCH v6 1/13 of: introduce of_property_for_earch_phandle_with_args()
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">;---
v5:
New patch for v5.
--- include/linux/of.h | 3 +++ 1 file changed, 3 insertions(+)
include/linux/of.h +3 -0
@@ -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);
Signature · 1 line
1.8.1.5
PATCH v6 1/13 of: introduce of_property_for_earch_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.
---
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(+)
include/linux/of.h +3 -0
@@ -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);
Signature · 1 line
1.8.1.5
Re: [PATCHv6+ 01/13] of: introduce of_property_for_earch_phandle_with_args()
Quoted 11 lines · Hiroshi Doyu
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 <[email protected]>---
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.
include/linux/of.h static inline int of_property_read_u32(const struct device_node *np, · line 618
Quoted 5 lines
include/linux/of.h +3
-0+#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.
RFC v6 1/13 of: introduce of_property_for_earch_phandle_with_args()
Stephen Warren <[email protected]> wrote @ Thu, 21 Nov 2013 19:57:00 +0100:
Quoted 50 lines · Hiroshi Doyu
Quoted 11 lines
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 <[email protected]>---
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.htmlThis new version only addresses one of the concerns that Grant had, namely the commit message.
include/linux/of.h
Quoted 5 lines
include/linux/of.h +3
-0+#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+specifierThat'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 resultThat'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))
Quoted 4 lines
... so you'd need functions like
of_prop_first_specifier()andof_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 <[email protected]>
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.
---
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.
--- drivers/of/base.c | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ include/linux/of.h | 52 ++++++++++++++++++++++++++++++++++ 2 files changed, 134 insertions(+)
drivers/of/base.c +82 -0
@@ -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,
include/linux/of.h +52 -0
70 lines not on this page · raw message
Signature · 1 line
1.8.1.5
RFC v6 1/13 of: introduce of_property_for_earch_phandle_with_args()
Hiroshi Doyu <[email protected]> wrote @ Thu, 28 Nov 2013 14:58:18 +0200 (EET):
....
Quoted 9 lines
Quoted 9 lines
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))
Quoted 7 lines
Quoted 4 lines
... so you'd need functions like
of_prop_first_specifier()andof_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 <[email protected]>
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.
---
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.
--- drivers/of/base.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ include/linux/of.h | 45 ++++++++++++++++++++++++++++++++++ 2 files changed, 116 insertions(+)
drivers/of/base.c +71 -0
@@ -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,
include/linux/of.h +45 -0
69 lines not on this page · raw message
Signature · 1 line
1.8.1.5
Re: [RFC][PATCHv6+++ 01/13] of: introduce of_property_for_earch_phandle_with_args()
On 11/29/2013 04:46 AM, Hiroshi Doyu wrote:
...
Quoted 11 lines
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 <[email protected]>---
v6+++:
Surely that's v9; "+++" is rather unusual.
drivers/of/base.c void of_print_phandle_args(const char *msg, const struct of_phandle_args *args) · line 1213
Quoted 12 lines
drivers/of/base.c +10
-0+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?
Quoted 1 line
+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.
drivers/of/base.c void of_print_phandle_args(const char *msg, const struct of_phandle_args *args) · line 1266
Quoted 4 lines
drivers/of/base.c +3
-0+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.
include/linux/of.h struct of_phandle_args { · line 84
Quoted 10 lines
include/linux/of.h +8
-0+/* +* 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:
include/linux/of.h struct of_phandle_args { · line 86
Quoted 2 lines
include/linux/of.h +2
-0+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.
Re: [RFC][PATCHv6+++ 01/13] of: introduce of_property_for_earch_phandle_with_args()
Stephen Warren <[email protected]> wrote @ Sun, 1 Dec 2013 20:00:09 +0100:
Quoted 7 lines · Hiroshi Doyu
...
Quoted 5 lines
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.
Quoted 8 lines
Quoted 6 lines
Introduced a new struct "
of_phandle_iter" to keep the state when iterating over the list.Signed-off-by Hiroshi Doyu <[email protected]>---
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.
...
Quoted 8 lines
Together with removing:
Review
Quoted 2 lines
(quoted diff) +2
-0+ 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 <[email protected]>
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.
---
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.
--- drivers/of/base.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++ include/linux/of.h | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 87 insertions(+)
drivers/of/base.c +53 -0
@@ -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,
include/linux/of.h +34 -0
@@ -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);
Signature · 8 lines
1.8.1.5 *1: http://lists.linuxfoundation.org/pipermail/iommu/2013-November/007086.html
Re: [RFC][PATCHv6+++ 01/13] of: introduce of_property_for_earch_phandle_with_args()
Quoted 83 lines · Hiroshi Doyu
Stephen Warren <[email protected]> wrote @ Sun, 1 Dec 2013 20:00:09 +0100:
Quoted 7 lines · Hiroshi Doyu
...
Quoted 5 lines
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.Quoted 8 lines
Quoted 6 lines
Introduced a new struct "
of_phandle_iter" to keep the state when iterating over the list.Signed-off-by Hiroshi Doyu <[email protected]>---
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.
...Quoted 8 lines
Together with removing:
Review
Quoted 2 lines
(quoted diff) +2
-0+ 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 <[email protected]>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 <[email protected]>---
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.htmlI 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 <[email protected]>--- drivers/of/base.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++ include/linux/of.h | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 87 insertions(+)drivers/of/base.c +5
-0@@ -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;
drivers/of/base.c void of_print_phandle_args(const char *msg, const struct of_phandle_args *args) · line 1218
Quoted 10 lines
drivers/of/base.c +10
-0+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))
drivers/of/base.c void of_print_phandle_args(const char *msg, const struct of_phandle_args *args) · line 1223
Quoted 5 lines
drivers/of/base.c +5
-0+return NULL ; + + phandle =be32_to_cpup (cur++); +if (!phandle) +return NULL ;
Won't of_find_node_by_phandle do this check?
Quoted 56 lines
drivers/of/base.c +33
-0+ + 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,include/linux/of.h +8
-0@@ -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);
include/linux/of.h static inline int of_count_phandle_with_args(struct device_node *np, · line 542
Quoted 8 lines
include/linux/of.h +5
-0@@ -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.
Quoted 17 lines
include/linux/of.h +13
-0+{ +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 ;
include/linux/of.h static inline int of_property_read_u32(const struct device_node *np, · line 642
Quoted 4 lines
include/linux/of.h +1
-0@@ -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.
Quoted 19 lines
include/linux/of.h +7
-1+ 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
Re: [RFC][PATCHv6+++ 01/13] of: introduce of_property_for_earch_phandle_with_args()
Quoted 10 lines · On Mon, 2 Dec 2013 15:39:25 +0100 Rob Herring <[email protected]> wrote:
Quoted 9 lines · Hiroshi Doyu
Stephen Warren <[email protected]> wrote @ Sun, 1 Dec 2013 20:00:09 +0100:
Quoted 7 lines · Hiroshi Doyu
...
Quoted 5 lines
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.
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Introduced a new struct "
of_phandle_iter" to keep the state when iterating over the list.Signed-off-by Hiroshi Doyu <[email protected]>
....
Rob, thank you for review.
I'll fix them and put this one into the next v7 series.
Re: [RFC][PATCHv6+++ 01/13] of: introduce of_property_for_earch_phandle_with_args()
In reply to Hiroshi DoyuOn 12/02/2013 04:02 AM, Hiroshi Doyu wrote:
...
Quoted 10 lines
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.drivers/of/base.c +3
-0+const __be32 *of_phandle_iter_init (const struct device_node *np, +const char *list_name, +const __be32 **end)
drivers/of/base.c void of_print_phandle_args(const char *msg, const struct of_phandle_args *args) · line 1254
Quoted 10 lines
drivers/of/base.c +10
-0+{ +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).
Quoted 3 lines
drivers/of/base.c +3
-0+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)
...
drivers/of/base.c void of_print_phandle_args(const char *msg, const struct of_phandle_args *args) · line 1219
Quoted 5 lines
drivers/of/base.c +5
-0+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?
Re: [PATCHv6+ 01/13] of: introduce of_property_for_earch_phandle_with_args()
In reply to Stephen WarrenQuoted 50 lines · Stephen Warren
Quoted 11 lines · Hiroshi Doyu
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 <[email protected]>---
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.htmlThis new version only addresses one of the concerns that Grant had, namely the commit message.
include/linux/of.h static inline int of_property_read_u32(const struct device_node *np, · line 618
Quoted 5 lines
include/linux/of.h +3
-0+#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+specifierThat'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 resultThat'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))
Quoted 4 lines
... so you'd need functions like
of_prop_first_specifier()andof_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.
Re: [PATCHv6+ 01/13] of: introduce of_property_for_earch_phandle_with_args()
Hi Grant,
Grant Likely <[email protected]> wrote @ Wed, 11 Dec 2013 14:28:45 +0100:
Quoted 13 lines · Stephen Warren
Quoted 12 lines · Hiroshi Doyu
Quoted 11 lines
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 <[email protected]>---
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
...
Quoted 1 line
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<----
Quoted 1 line
From
8f7c0404aa68f0e8dbe0babc240590f6528ecc1fMon Sep 17 00:00:00 2001
From: Hiroshi Doyu <[email protected]>
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.
---
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.
--- drivers/of/base.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ include/linux/of.h | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+)
drivers/of/base.c +46 -0
@@ -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,
include/linux/of.h +32 -0
@@ -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);
Signature · 1 line
1.8.1.5
Re: [PATCHv6+ 01/13] of: introduce of_property_for_earch_phandle_with_args()
Quoted 74 lines · Hiroshi Doyu
Hi Grant,
Grant Likely <[email protected]> wrote @ Wed, 11 Dec 2013 14:28:45 +0100:
Quoted 13 lines · Stephen Warren
Quoted 12 lines · Hiroshi Doyu
Quoted 11 lines
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 <[email protected]>---
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...
Quoted 1 line
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
8f7c0404aa68f0e8dbe0babc240590f6528ecc1fMon Sep 17 00:00:00 2001
From: Hiroshi Doyu <[email protected]>
Date: Fri, 15 Nov 2013 10:52:53 +0200
Subject: [PATCH] of: introduceof_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 <[email protected]>Cc Rob Herring <[email protected]>---
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.htmlI 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 <[email protected]>--- drivers/of/base.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ include/linux/of.h | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+)drivers/of/base.c +0
-0
drivers/of/base.c void of_print_phandle_args(const char *msg, const struct of_phandle_args *args) · line 1206
Quoted 6 lines
drivers/of/base.c +3
-0@@ -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.
Quoted 89 lines
drivers/of/base.c +43
-0+{ +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,include/linux/of.h +24
-0@@ -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 ;
include/linux/of.h static inline int of_property_read_u32(const struct device_node *np, · line 644
Quoted 8 lines
include/linux/of.h +5
-0@@ -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.
Quoted 8 lines
include/linux/of.h +3
-0+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);Signature · 1 line
1.8.1.5
Re: [PATCHv6+ 01/13] of: introduce of_property_for_earch_phandle_with_args()
Grant Likely <[email protected]> wrote @ Thu, 12 Dec 2013 12:34:17 +0100:
Quoted 93 lines · Hiroshi Doyu
Quoted 74 lines
Hi Grant,
Grant Likely <[email protected]> wrote @ Wed, 11 Dec 2013 14:28:45 +0100:
Quoted 13 lines · Stephen Warren
Quoted 12 lines · Hiroshi Doyu
Quoted 11 lines
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 <[email protected]>---
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...
Quoted 1 line
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
8f7c0404aa68f0e8dbe0babc240590f6528ecc1fMon Sep 17 00:00:00 2001
From: Hiroshi Doyu <[email protected]>
Date: Fri, 15 Nov 2013 10:52:53 +0200
Subject: [PATCH] of: introduceof_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 <[email protected]>Cc Rob Herring <[email protected]>---
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.htmlI 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 <[email protected]>--- drivers/of/base.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ include/linux/of.h | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+)drivers/of/base.c +0
-0drivers/of/base.c void of_print_phandle_args(const char *msg, const struct of_phandle_args *args) · line 1206
Quoted 6 lines
drivers/of/base.c +3
-0@@ -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; }
Quoted 2 lines
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:
Quoted 3 lines
Quoted 3 lines
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.
Re: [PATCHv6+ 01/13] of: introduce of_property_for_earch_phandle_with_args()
Hiroshi Doyu <[email protected]> wrote @ Thu, 12 Dec 2013 14:14:04 +0200 (EET):
Quoted 12 lines
Quoted 12 lines
Quoted 12 lines
From
8f7c0404aa68f0e8dbe0babc240590f6528ecc1fMon Sep 17 00:00:00 2001
From: Hiroshi Doyu <[email protected]>
Date: Fri, 15 Nov 2013 10:52:53 +0200
Subject: [PATCH] of: introduceof_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 <[email protected]>Cc Rob Herring <[email protected]>
....
Quoted 42 lines
Quoted 28 lines
Quoted 10 lines
--- drivers/of/base.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ include/linux/of.h | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+)drivers/of/base.c +0
-0drivers/of/base.c void of_print_phandle_args(const char *msg, const struct of_phandle_args *args) · line 1206
Quoted 6 lines
drivers/of/base.c +3
-0@@ -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; }Quoted 2 lines
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:
Quoted 3 lines
Quoted 3 lines
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()
Quoted 8 lines
http://lists.linuxfoundation.org/pipermail/iommu/2013-November/007087.htmlStephen 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.
Re: [PATCHv6+ 01/13] of: introduce of_property_for_earch_phandle_with_args()
Quoted 59 lines · Hiroshi Doyu
Hiroshi Doyu <[email protected]> wrote @ Thu, 12 Dec 2013 14:14:04 +0200 (EET):
Quoted 12 lines
Quoted 12 lines
Quoted 12 lines
From
8f7c0404aa68f0e8dbe0babc240590f6528ecc1fMon Sep 17 00:00:00 2001
From: Hiroshi Doyu <[email protected]>
Date: Fri, 15 Nov 2013 10:52:53 +0200
Subject: [PATCH] of: introduceof_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 <[email protected]>Cc Rob Herring <[email protected]>....
Quoted 44 lines
Quoted 28 lines
Quoted 10 lines
--- drivers/of/base.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ include/linux/of.h | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+)drivers/of/base.c +0
-0drivers/of/base.c void of_print_phandle_args(const char *msg, const struct of_phandle_args *args) · line 1206
Quoted 6 lines
drivers/of/base.c +3
-0@@ -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; }Quoted 2 lines
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:
Quoted 3 lines
Quoted 3 lines
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
Quoted 8 lines
Quoted 6 lines
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!
Re: [PATCHv6+ 01/13] of: introduce of_property_for_earch_phandle_with_args()
In reply to Hiroshi DoyuQuoted 6 lines · Hiroshi Doyu
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 <[email protected]>
This patch can be merged with the rest of the series.
g.
Quoted 28 lines
---
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.htmlv5:
New patch for v5.--- include/linux/of.h | 3 +++ 1 file changed, 3 insertions(+)include/linux/of.h +3
-0@@ -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);Signature · 1 line
1.8.1.5
PATCH v6 2/13 iommu/of: introduce a global iommu device list
In reply to Hiroshi DoyuThis 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.
---
v6:
New for v6.
--- drivers/iommu/of_iommu.c | 37 +++++++++++++++++++++++++++++++++++++ include/linux/of_iommu.h | 16 ++++++++++++++++ 2 files changed, 53 insertions(+)
drivers/iommu/of_iommu.c +37 -0
@@ -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.
include/linux/of_iommu.h +16 -0
@@ -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 */
Signature · 1 line
1.8.1.5
PATCH v6 3/13 iommu/of: check if dependee iommu is ready or not
In reply to Hiroshi DoyuIOMMU 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.
---
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(+)
drivers/iommu/of_iommu.c +16 -0
@@ -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 ; +}
include/linux/of_iommu.h +6 -0
@@ -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 */
Signature · 1 line
1.8.1.5
PATCH v6 4/13 driver/core: populate devices in order for IOMMUs
In reply to Hiroshi DoyuIOMMU 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.
---
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(+)
drivers/base/dd.c +5 -0
@@ -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)
Signature · 1 line
1.8.1.5
PATCH v6 5/13 iommu/core: add ops->{bound,unbind}_driver()
In reply to Hiroshi Doyuops->{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().
---
v6:
New for v6.
--- drivers/iommu/iommu.c | 13 +++++++++++-- include/linux/iommu.h | 4 ++++ 2 files changed, 15 insertions(+), 2 deletions(-)
drivers/iommu/iommu.c +11 -2
@@ -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 ; }/*
include/linux/iommu.h +4 -0
@@ -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);
Signature · 1 line
1.8.1.5
Re: [PATCHv6 05/13] iommu/core: add ops->{bound,unbind}_driver()
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.
Quoted 76 lines · On Thu, 21 Nov 2013 14:40:41 +0100 Hiroshi Doyu <[email protected]> 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 viaops->add_device()since afteradd_device()device's population/instanciation can be still deferred viaprobe().Signed-off-by Hiroshi Doyu <[email protected]>---
v6:
New for v6.--- drivers/iommu/iommu.c | 13 +++++++++++-- include/linux/iommu.h | 4 ++++ 2 files changed, 15 insertions(+), 2 deletions(-)drivers/iommu/iommu.c +11
-2@@ -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 ; }/* include/linux/iommu.h +4
-0@@ -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);Signature · 1 line
1.8.1.5
Re: [PATCHv6 05/13] iommu/core: add ops->{bound,unbind}_driver()
Quoted 9 lines · On Mon, 25 Nov 2013 14:49:37 +0100 Hiroshi Doyu <[email protected]> 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?
Quoted 93 lines
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 afteradd_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.
Quoted 76 lines · On Thu, 21 Nov 2013 14:40:41 +0100 Hiroshi Doyu <[email protected]> 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 viaops->add_device()since afteradd_device()device's population/instanciation can be still deferred viaprobe().Signed-off-by Hiroshi Doyu <[email protected]>---
v6:
New for v6.--- drivers/iommu/iommu.c | 13 +++++++++++-- include/linux/iommu.h | 4 ++++ 2 files changed, 15 insertions(+), 2 deletions(-)drivers/iommu/iommu.c +11
-2@@ -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 ; }/* include/linux/iommu.h +4
-0@@ -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);Signature · 1 line
1.8.1.5_______________________________________________
iommu mailing list
iommu at lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCHv6 05/13] iommu/core: add ops->{bound,unbind}_driver()
Hi Hiroshi,
Quoted 7 lines · Hiroshi Doyu
Quoted 4 lines · On Mon, 25 Nov 2013 14:49:37 +0100 Hiroshi Doyu <[email protected]> wrote:
Hi Joerg,
Do you have some time to review this patch along with the following ones?
Quoted 7 lines
Quoted 5 lines
[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.htmlAny 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
PATCH v6 6/13 ARM: tegra: create a DT header defining SWGROUP ID
In reply to Hiroshi DoyuCreate 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.
---
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
include/dt-bindings/memory/tegra-swgroup.h new file +50 -0
@@ -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 */
Signature · 1 line
1.8.1.5
PATCH v6 7/13 iommu/tegra: smmu: register device to iommu dynamically
In reply to Hiroshi Doyuplatform_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.
---
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(-)
drivers/iommu/Kconfig +1 -0
@@ -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
drivers/iommu/tegra-smmu.c +69 -1
118 lines not on this page · raw message
Signature · 1 line
1.8.1.5
PATCH v6 8/13 iommu/tegra: smmu: calculate ASID register offset by ID
In reply to Hiroshi DoyuASID 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.
---
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(-)
drivers/iommu/tegra-smmu.c +17 -94
@@ -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;
Signature · 1 line
1.8.1.5
PATCH v6 9/13 iommu/tegra: smmu: get swgroups from DT "iommus="
In reply to Hiroshi DoyuThis 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.
---
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(-)
Documentation/devicetree/bindings/iommu/nvidia,tegra30-smmu.txt +28 -2
@@ -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)>; + .... + };
drivers/iommu/tegra-smmu.c +116 -17
201 lines not on this page · raw message
Signature · 1 line
1.8.1.5
PATCH v6 10/13 iommu/tegra: smmu: allow duplicate ASID wirte
In reply to Hiroshi DoyuThe 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.
---
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(-)
drivers/iommu/tegra-smmu.c +8 -12
@@ -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,
Signature · 1 line
1.8.1.5
PATCH v6 11/13 iommu/tegra: smmu: Rename hwgrp -> swgroups
In reply to Hiroshi DoyuUse 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.
---
v4:
New for v4
--- drivers/iommu/tegra-smmu.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-)
drivers/iommu/tegra-smmu.c +18 -18
@@ -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,
Signature · 1 line
1.8.1.5
PATCH v6 12/13 iommu/tegra: smmu: add SMMU to an global iommu list
In reply to Hiroshi DoyuThis allows to inquire if SMMU is populated or not.
Suggested by Thierry Reding and copied his example code.
---
v6:
New for v6.
--- drivers/iommu/tegra-smmu.c | 55 +++++++++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 25 deletions(-)
drivers/iommu/tegra-smmu.c +30 -25
@@ -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 ; }
Signature · 1 line
1.8.1.5
PATCH v6 13/13 ARM: dt: tegra30: add "iommus" binding
In reply to Hiroshi Doyu"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.
---
v5:
Use "iommus=" instead of "mmu-masters".
--- arch/arm/boot/dts/tegra30.dtsi | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-)
arch/arm/boot/dts/tegra30.dtsi +22 -1
@@ -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 at 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"; };
Signature · 1 line
1.8.1.5