Introduce automatic DMA configuration for IOMMU masters
Subsystems (5)
v2 cover Introduce automatic DMA configuration for IOMMU masters
Hello again,
Hot on the heels of my initial RFC, here's a v2 of the posting from here:
RFCv1: http://lists.infradead.org/pipermail/linux-arm-kernel/2014-August/283023.html
The main difference since v1 is that I've introduced some generic structures to represent IOMMUs and their mappings (struct iommu_data and struct iommu_dma_mapping). This allows us to propagate the per-instance data all the way down to the DMA-mapping code, which can then manage a per-instance domain. Note that the ARM dma-mapping implementation does not currently make use of this information.
Since there was a bit of confusion about how this is supposed to work, the way I envisage it hanging together is:
(1) An IOMMU driver uses IOMMU_OF_DECLARE to register an early initialisation callback.
(2) The architecture code calls iommu_init() before kicking off the usual device probing (e.g. of_platform_populate), which executes the IOMMU initialisation callback for each IOMMU node in the device-tree. At this point, the IOMMU driver is expected to allocate iommu_data structure and initialise the priv field before calling of_iommu_set_data on its device_node.
(3) For each master, of_iommu_configure will call of_xlate on the corresponding IOMMU(s), passing of_phandle_args. This allows the IOMMU driver to retrieve the iommu_data with of_iommu_get_data and update its internal data structures with the IDs for the new master. At this point, the per-iommu-instance iommu_data is inserted into a per-device iommu_dma_mapping struct. This allows multiple IOMMU domains to be linked together for devices that master through multiple IOMMUs (but note that iommu_configure currently doesn't not allow this because I'm lazy).
(4) The newly allocated iommu_dma_mapping is passed to arch_setup_dma_ops, which can use it to set the correct dma_ops for the device. If IOMMU-capable ops are in-use, the domain and iova allocator for each iommu_data entry should be initialised (if they haven't been already) and used for managing the per-iommu-instance address space.
There are a bunch of things that could be done on top of this series:
- Port IOMMU driver(s) to it
- Remove the add_device call from iommu_ops
- Add support for devices that master through multiple IOMMUs
- Do something more intelligent with the DMA mask
- Add generic support for device isolation (ie. one domain per device)
- Wire up a different bus (e.g. PCI)
- Move ARM's IOMMU dma-mapping code over to using iommu_dma_mapping instead of the arch-specific dma_iommu_mapping
Anyway, feedback welcome. There are certainly a few different ways of doing this.
Will
--->8
Will Deacon (7):
iommu: provide early initialisation hook for IOMMU drivers
dma-mapping: replace set_arch_dma_coherent_ops with arch_setup_dma_ops
iommu: add new iommu_ops callback for adding an OF device
iommu: provide helper function to configure an IOMMU for an of master
dma-mapping: detect and configure IOMMU in of_dma_configure
arm: call iommu_init before of_platform_populate
arm: dma-mapping: plumb our iommu mapping ops into arch_setup_dma_ops
arch/arm/include/asm/dma-mapping.h | 11 +++--- arch/arm/kernel/setup.c | 5 ++- arch/arm/mm/dma-mapping.c | 72 +++++++++++++++++++++++++++++++++----- drivers/iommu/Kconfig | 2 +- drivers/iommu/of_iommu.c | 66 ++++++++++++++++++++++++++++++++++ drivers/of/platform.c | 54 +++++++++++----------------- include/asm-generic/vmlinux.lds.h | 2 ++ include/linux/dma-mapping.h | 18 +++++++--- include/linux/iommu.h | 11 ++++++ include/linux/of_iommu.h | 31 ++++++++++++++++ 10 files changed, 218 insertions(+), 54 deletions(-)
Signature · 1 line
2.1.0
RFC PATCH v2 1/7 iommu: provide early initialisation hook for IOMMU drivers
IOMMU drivers must be initialised before any of their upstream devices, otherwise the relevant iommu_ops won't be configured for the bus in question. To solve this, a number of IOMMU drivers use initcalls to initialise the driver before anything has a chance to be probed.
Whilst this solves the immediate problem, it leaves the job of probing the IOMMU completely separate from the iommu_ops to configure the IOMMU, which are called on a per-bus basis and require the driver to figure out exactly which instance of the IOMMU is being requested. In particular, the add_device callback simply passes a struct device to the driver, which then has to parse firmware tables or probe buses to identify the relevant IOMMU instance.
This patch takes the first step in addressing this problem by adding an early initialisation pass for IOMMU drivers, giving them the ability to set some per-instance data on their of_node in the form of a new iommu_data structure. This can later be used when parsing OF masters to identify the IOMMU instance in question.
--- drivers/iommu/of_iommu.c | 14 ++++++++++++++ include/asm-generic/vmlinux.lds.h | 2 ++ include/linux/iommu.h | 6 ++++++ include/linux/of_iommu.h | 23 +++++++++++++++++++++++ 4 files changed, 45 insertions(+)
drivers/iommu/of_iommu.c +14 -0
@@ -89,3 +89,17 @@ int of_get_dma_window(struct device_node *dn, const char *prefix, int index,return 0 ; }EXPORT_SYMBOL_GPL (of_get_dma_window); + +void __init of_iommu_init (void ) +{ +struct device_node *np; +const struct of_device_id *match, *matches = &__iommu_of_table; + +for_each_matching_node_and_match (np, matches, &match) { +const int (*init_fn)(struct device_node *) = match->data; + +if (init_fn (np)) +pr_err ("Failed to initialise IOMMU %s\n" , +of_node_full_name (np)); + } +}
include/asm-generic/vmlinux.lds.h +2 -0
@@ -162,6 +162,7 @@#define CLKSRC_OF_TABLES () OF_TABLE(CONFIG_CLKSRC_OF, clksrc)#define IRQCHIP_OF_MATCH_TABLE () OF_TABLE(CONFIG_IRQCHIP, irqchip)#define CLK_OF_TABLES () OF_TABLE(CONFIG_COMMON_CLK, clk) +#define IOMMU_OF_TABLES () OF_TABLE(CONFIG_OF_IOMMU, iommu)#define RESERVEDMEM_OF_TABLES () OF_TABLE(CONFIG_OF_RESERVED_MEM, reservedmem)#define CPU_METHOD_OF_TABLES () OF_TABLE(CONFIG_SMP, cpu_method)#define EARLYCON_OF_TABLES () OF_TABLE(CONFIG_SERIAL_EARLYCON, earlycon)
@@ -495,6 +496,7 @@ CLK_OF_TABLES() \ RESERVEDMEM_OF_TABLES() \ CLKSRC_OF_TABLES() \ + IOMMU_OF_TABLES() \ CPU_METHOD_OF_TABLES() \ KERNEL_DTB() \IRQCHIP_OF_MATCH_TABLE () \
include/linux/iommu.h +6 -0
@@ -57,6 +57,12 @@ struct iommu_domain {struct iommu_domain_geometry geometry; }; +struct iommu_data { +struct iommu_domain *domain; +struct iova_domain *iovad; +void *priv; +}; +#define IOMMU_CAP_CACHE_COHERENCY 0x1#define IOMMU_CAP_INTR_REMAP 0x2/* isolates device intrs */
include/linux/of_iommu.h +23 -0
@@ -1,12 +1,17 @@#ifndef __OF_IOMMU_H#define __OF_IOMMU_H +#include <linux/iommu.h> +#include <linux/of.h> +#ifdef CONFIG_OF_IOMMU 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 of_iommu_init (void ); +#else static inline int of_get_dma_window(struct device_node *dn, const char *prefix,
@@ -16,6 +21,24 @@ static inline int of_get_dma_window(struct device_node *dn, const char *prefix,return -EINVAL ; } +static inline void of_iommu_init (void ) { } +#endif /* CONFIG_OF_IOMMU */ +static inline void of_iommu_set_data (struct device_node *np, +struct iommu_data *data) +{ + np->data = data; +} + +static inline struct iommu_data *of_iommu_get_data (struct device_node *np) +{ +return np->data; +} + +extern struct of_device_id __iommu_of_table; + +#define IOMMU_OF_DECLARE (name, compat, fn) \ + OF_DECLARE_1(iommu, name, compat, fn) +#endif /* __OF_IOMMU_H */
Signature · 1 line
2.1.0
Marek Szyprowski
maintainerRFC PATCH v2 1/7 iommu: provide early initialisation hook for IOMMU drivers
Hello,
Quoted 121 lines · Will Deacon
IOMMU drivers must be initialised before any of their upstream devices, otherwise the relevant
iommu_opswon't be configured for the bus in question. To solve this, a number of IOMMU drivers use initcalls to initialise the driver before anything has a chance to be probed.Whilst this solves the immediate problem, it leaves the job of probing the IOMMU completely separate from the
iommu_opsto configure the IOMMU, which are called on a per-bus basis and require the driver to figure out exactly which instance of the IOMMU is being requested. In particular, theadd_devicecallback simply passes a struct device to the driver, which then has to parse firmware tables or probe buses to identify the relevant IOMMU instance.This patch takes the first step in addressing this problem by adding an early initialisation pass for IOMMU drivers, giving them the ability to set some per-instance data on their
of_nodein the form of a newiommu_datastructure. This can later be used when parsing OF masters to identify the IOMMU instance in question.Signed-off-by Will Deacon <[email protected]>--- drivers/iommu/of_iommu.c | 14 ++++++++++++++ include/asm-generic/vmlinux.lds.h | 2 ++ include/linux/iommu.h | 6 ++++++ include/linux/of_iommu.h | 23 +++++++++++++++++++++++ 4 files changed, 45 insertions(+)drivers/iommu/of_iommu.c +14
-0@@ -89,3 +89,17 @@ int of_get_dma_window(struct device_node *dn, const char *prefix, int index,return 0 ; }EXPORT_SYMBOL_GPL (of_get_dma_window); + +void __init of_iommu_init (void ) +{ +struct device_node *np; +const struct of_device_id *match, *matches = &__iommu_of_table; + +for_each_matching_node_and_match (np, matches, &match) { +const int (*init_fn)(struct device_node *) = match->data; + +if (init_fn (np)) +pr_err ("Failed to initialise IOMMU %s\n" , +of_node_full_name (np)); + } +}include/asm-generic/vmlinux.lds.h +2
-0@@ -162,6 +162,7 @@#define CLKSRC_OF_TABLES () OF_TABLE(CONFIG_CLKSRC_OF, clksrc)#define IRQCHIP_OF_MATCH_TABLE () OF_TABLE(CONFIG_IRQCHIP, irqchip)#define CLK_OF_TABLES () OF_TABLE(CONFIG_COMMON_CLK, clk) +#define IOMMU_OF_TABLES () OF_TABLE(CONFIG_OF_IOMMU, iommu)#define RESERVEDMEM_OF_TABLES () OF_TABLE(CONFIG_OF_RESERVED_MEM, reservedmem)#define CPU_METHOD_OF_TABLES () OF_TABLE(CONFIG_SMP, cpu_method)#define EARLYCON_OF_TABLES () OF_TABLE(CONFIG_SERIAL_EARLYCON, earlycon)@@ -495,6 +496,7 @@ CLK_OF_TABLES() \ RESERVEDMEM_OF_TABLES() \ CLKSRC_OF_TABLES() \ + IOMMU_OF_TABLES() \ CPU_METHOD_OF_TABLES() \ KERNEL_DTB() \IRQCHIP_OF_MATCH_TABLE () \include/linux/iommu.h +6
-0@@ -57,6 +57,12 @@ struct iommu_domain {struct iommu_domain_geometry geometry; }; +struct iommu_data { +struct iommu_domain *domain; +struct iova_domain *iovad; +void *priv; +}; +#define IOMMU_CAP_CACHE_COHERENCY 0x1#define IOMMU_CAP_INTR_REMAP 0x2/* isolates device intrs */ include/linux/of_iommu.h +12
-0@@ -1,12 +1,17 @@#ifndef __OF_IOMMU_H#define __OF_IOMMU_H +#include <linux/iommu.h> +#include <linux/of.h> +#ifdef CONFIG_OF_IOMMU 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 of_iommu_init (void ); +#else static inline int of_get_dma_window(struct device_node *dn, const char *prefix,@@ -16,6 +21,24 @@ static inline int of_get_dma_window(struct device_node *dn, const char *prefix, return -EINVAL; } +static inline void of_iommu_init (void ) { } +#endif /* CONFIG_OF_IOMMU */ +static inline void of_iommu_set_data (struct device_node *np, +struct iommu_data *data) +{ + np->data = data; +}
include/linux/of_iommu.h static inline int of_get_dma_window(struct device_node *dn, const char *prefix, · line 42
Quoted 10 lines
include/linux/of_iommu.h +10
-0+ +static inline struct iommu_data *of_iommu_get_data (struct device_node *np) +{ +return np->data; +} + +extern struct of_device_id __iommu_of_table; + +#define IOMMU_OF_DECLARE (name, compat, fn) \ + OF_DECLARE_1(iommu, name, compat, fn)
OF_DECLARE_1 assumes that init_fn doesn't return anything, however in of_iommu_init() you expect the init function to return an error code, so the above lines should be changed to:
typedef int (*of_iommu_init_fn)(struct device_node *);
#define IOMMU_OF_DECLARE(name, compat, fn) \
_OF_DECLARE(iommu, name, compat, fn, of_iommu_init_fn)
include/linux/of_iommu.h static inline int of_get_dma_window(struct device_node *dn, const char *prefix, · line 44
Quoted 2 lines
include/linux/of_iommu.h +1
-0+#endif /* __OF_IOMMU_H */
Best regards
Signature · 2 lines
Marek Szyprowski, PhD Samsung R&D Institute Poland
RFC PATCH v2 2/7 dma-mapping: replace set_arch_dma_coherent_ops with arch_setup_dma_ops
In reply to Will Deaconset_arch_dma_coherent_ops is called from of_dma_configure in order to swizzle the architectural dma-mapping functions over to a cache-coherent implementation. This is currently implemented only for ARM.
In anticipation of re-using this mechanism for IOMMU-backed dma-mapping ops too, this patch replaces the function with a broader arch_setup_dma_ops callback which is also responsible for setting the DMA mask and offset as well as selecting the correct mapping functions.
A further advantage of this split is that it nicely isolates the of-specific code from the dma-mapping code, allowing potential reuse by other buses (e.g. PCI) in the future.
--- arch/arm/include/asm/dma-mapping.h | 13 ++++++++---- drivers/of/platform.c | 42 ++++++++++---------------------------- include/linux/dma-mapping.h | 8 +++----- 3 files changed, 23 insertions(+), 40 deletions(-)
arch/arm/include/asm/dma-mapping.h +9 -4
@@ -121,12 +121,17 @@ static inline unsigned long dma_max_pfn(struct device *dev) }#define dma_max_pfn (dev) dma_max_pfn(dev) -static inline int set_arch_dma_coherent_ops (struct device *dev) +static inline void arch_setup_dma_ops (struct device *dev,u64 mask, +unsigned long offset,bool coherent) { -set_dma_ops (dev, &arm_coherent_dma_ops); -return 0 ; + dev->coherent_dma_mask = mask; + dev->dma_mask = &dev->coherent_dma_mask; + dev->dma_pfn_offset = offset; + +if (coherent) +set_dma_ops (dev, &arm_coherent_dma_ops); } -#define set_arch_dma_coherent_ops (dev) set_arch_dma_coherent_ops(dev) +#define arch_setup_dma_ops arch_setup_dma_opsstatic inline dma_addr_t phys_to_dma (struct device *dev,phys_addr_t paddr) {
drivers/of/platform.c +11 -31
54 lines not on this page · raw message
include/linux/dma-mapping.h +3 -5
@@ -129,11 +129,9 @@ static inline int dma_coerce_mask_and_coherent(struct device *dev, u64 mask)extern u64 dma_get_required_mask (struct device *dev); -#ifndef set_arch_dma_coherent_ops -static inline int set_arch_dma_coherent_ops (struct device *dev) -{ -return 0 ; -} +#ifndef arch_setup_dma_ops +static inline void arch_setup_dma_ops (struct device *dev,u64 mask, +unsigned long offset,bool coherent) { }#endif static inline unsigned int dma_get_max_seg_size (struct device *dev)
Signature · 1 line
2.1.0
RFC PATCH v2 2/7 dma-mapping: replace set_arch_dma_coherent_ops with arch_setup_dma_ops
Hi Will,
Quoted 4 lines · Will Deacon
set_arch_dma_coherent_opsis called fromof_dma_configurein order to swizzle the architectural dma-mapping functions over to a cache-coherent implementation. This is currently implemented only for ARM.
Quoted 8 lines
In anticipation of re-using this mechanism for IOMMU-backed dma-mapping ops too, this patch replaces the function with a broader
arch_setup_dma_opscallback which is also responsible for setting the DMA mask and offset as well as selecting the correct mapping functions.A further advantage of this split is that it nicely isolates the of-specific code from the dma-mapping code, allowing potential reuse by other buses (e.g. PCI) in the future.
I think this patch can introduce a regression if it will be used as is :(
When this code was initially created there ware a lot of discussion about and finally it was decided to configure all common (for all arches) DMA specific parameters for devices in common code, while strictly arch specific things using arch specific APIs/callbacks.
The following parameters are common now:dev->coherent_dma_mask = mask;dev->dma_mask = &dev->coherent_dma_mask;dev->dma_pfn_offset = offset;
and they need to be set always, otherwise it will affect on other DT-based arches.
Links:
- [PATCH v2 0/7] ARM: dma: Support dma-ranges and dma-coherent
http://www.spinics.net/lists/arm-kernel/msg311678.html
- [PATCH 0/7] of: setup dma parameters using dma-ranges and dma-coherent
https://lkml.org/lkml/2014/3/6/186
- [PATCH v2 0/7] of: setup dma parameters using dma-ranges and dma-coherent
https://lkml.org/lkml/2014/4/19/80
- [PATCH v3 0/7] of: setup dma parameters using dma-ranges and dma-coherent
http://thread.gmane.org/gmane.linux.kernel/1690224/focus=319246
Quoted 8 lines
Signed-off-by Will Deacon <[email protected]>--- arch/arm/include/asm/dma-mapping.h | 13 ++++++++---- drivers/of/platform.c | 42 ++++++++++---------------------------- include/linux/dma-mapping.h | 8 +++----- 3 files changed, 23 insertions(+), 40 deletions(-)
[...]
Quoted 14 lines
drivers/of/platform.c +1
-0+arch_setup_dma_ops (dev,DMA_BIT_MASK (32 ), offset, coherent); }/** include/linux/dma-mapping.h +0
-1@@ -129,11 +129,9 @@ static inline int dma_coerce_mask_and_coherent(struct device *dev, u64 mask)extern u64 dma_get_required_mask (struct device *dev); -#ifndef set_arch_dma_coherent_ops
include/linux/dma-mapping.h static inline int dma_coerce_mask_and_coherent(struct device *dev, u64 mask) · line 137
Quoted 10 lines
include/linux/dma-mapping.h +3
-4-static inline int set_arch_dma_coherent_ops (struct device *dev) -{ -return 0 ; -} +#ifndef arch_setup_dma_ops +static inline void arch_setup_dma_ops (struct device *dev,u64 mask, +unsigned long offset,bool coherent) { }#endif static inline unsigned int dma_get_max_seg_size (struct device *dev)
Regards,
-grygorii
RFC PATCH v2 2/7 dma-mapping: replace set_arch_dma_coherent_ops with arch_setup_dma_ops
Quoted 1 line · Grygorii Strashko
Hi Will,
Hi Grygorii,
Quoted 21 lines · Will Deacon
Quoted 4 lines
set_arch_dma_coherent_opsis called fromof_dma_configurein order to swizzle the architectural dma-mapping functions over to a cache-coherent implementation. This is currently implemented only for ARM.Quoted 8 lines
In anticipation of re-using this mechanism for IOMMU-backed dma-mapping ops too, this patch replaces the function with a broader
arch_setup_dma_opscallback which is also responsible for setting the DMA mask and offset as well as selecting the correct mapping functions.A further advantage of this split is that it nicely isolates the of-specific code from the dma-mapping code, allowing potential reuse by other buses (e.g. PCI) in the future.
I think this patch can introduce a regression if it will be used as is :(
When this code was initially created there ware a lot of discussion about and finally it was decided to configure all common (for all arches) DMA specific parameters for devices in common code, while strictly arch specific things using arch specific APIs/callbacks.
Quoted 7 lines
The following parameters are common now:
dev->coherent_dma_mask= mask;dev->dma_mask=&dev->coherent_dma_mask;dev->dma_pfn_offset= offset;and they need to be set always, otherwise it will affect on other DT-based arches.
Ok, in which case we can either configure the struct device in of_dma_configure before calling arch_setup_dma_ops, or we can do the work in a generic version of arch_setup_dma_ops (that I haven't added yet).
The former is how it's done in mainline atm, so I'll stick with that.
Thanks,
Will
RFC PATCH v2 2/7 dma-mapping: replace set_arch_dma_coherent_ops with arch_setup_dma_ops
Hi Will,
Quoted 28 lines · Will Deacon
Quoted 26 lines · Grygorii Strashko
Quoted 4 lines · Will Deacon
set_arch_dma_coherent_opsis called fromof_dma_configurein order to swizzle the architectural dma-mapping functions over to a cache-coherent implementation. This is currently implemented only for ARM.Quoted 8 lines
In anticipation of re-using this mechanism for IOMMU-backed dma-mapping ops too, this patch replaces the function with a broader
arch_setup_dma_opscallback which is also responsible for setting the DMA mask and offset as well as selecting the correct mapping functions.A further advantage of this split is that it nicely isolates the of-specific code from the dma-mapping code, allowing potential reuse by other buses (e.g. PCI) in the future.
I think this patch can introduce a regression if it will be used as is :(
When this code was initially created there ware a lot of discussion about and finally it was decided to configure all common (for all arches) DMA specific parameters for devices in common code, while strictly arch specific things using arch specific APIs/callbacks.
The following parameters are common now:
dev->coherent_dma_mask= mask;dev->dma_mask=&dev->coherent_dma_mask;dev->dma_pfn_offset= offset;
Quoted 6 lines
Quoted 2 lines
and they need to be set always, otherwise it will affect on other DT-based arches.
Ok, in which case we can either configure the struct device in
of_dma_configurebefore callingarch_setup_dma_ops, or we can do the work in a generic version ofarch_setup_dma_ops(that I haven't added yet).
Just think that it would more simpler to add arch-API:
arch_setup_iommu(struct device *dev, struct iommu_dma_mapping *iommu)
and call it at the end of of_dma_configure() as following:
arch_setup_iommu(dev, of_iommu_configure(dev));
so it will setup IOMMU parameters for device and overwrite DMA parameters respectively.
if IOMMU is not present/disabled arch_setup_iommu() will be a NOP and system will roll back to default (old) behavior.
Also it will simplify ARM dma-mapping changes -
only IOMMU code will need to be added.
Best regards,
-grygorii
RFC PATCH v2 3/7 iommu: add new iommu_ops callback for adding an OF device
In reply to Will DeaconThis patch adds a new function to the iommu_ops structure to allow an OF device to be added to a specific IOMMU instance using the recently merged generic devicetree binding for IOMMUs. The callback (of_xlate) takes a struct device representing the master and an of_phandle_args representing the IOMMU and the correspondong IDs for the new master.
--- include/linux/iommu.h | 5 +++++ 1 file changed, 5 insertions(+)
include/linux/iommu.h +5 -0
@@ -21,6 +21,7 @@#include <linux/errno.h> #include <linux/err.h> +#include <linux/of.h> #include <linux/types.h> #include <trace/events/iommu.h>
@@ -136,6 +137,10 @@ struct iommu_ops {/* Get the numer of window per domain */ u32 (*domain_get_windows)(struct iommu_domain *domain); +#ifdef CONFIG_OF_IOMMU +int (*of_xlate)(struct device *dev,struct of_phandle_args *args); +#endif +unsigned long pgsize_bitmap; };
Signature · 1 line
2.1.0
Marek Szyprowski
maintainerRFC PATCH v2 3/7 iommu: add new iommu_ops callback for adding an OF device
Hello,
Quoted 24 lines · Will Deacon
This patch adds a new function to the
iommu_opsstructure to allow an OF device to be added to a specific IOMMU instance using the recently merged generic devicetree binding for IOMMUs. The callback (of_xlate) takes a struct device representing the master and anof_phandle_argsrepresenting the IOMMU and the correspondong IDs for the new master.Signed-off-by Will Deacon <[email protected]>--- include/linux/iommu.h | 5 +++++ 1 file changed, 5 insertions(+)include/linux/iommu.h +1
-0@@ -21,6 +21,7 @@#include <linux/errno.h> #include <linux/err.h> +#include <linux/of.h> #include <linux/types.h> #include <trace/events/iommu.h>
include/linux/iommu.h struct iommu_ops { · line 141
Quoted 5 lines
include/linux/iommu.h +2
-0@@ -136,6 +137,10 @@ struct iommu_ops {/* Get the numer of window per domain */ u32 (*domain_get_windows)(struct iommu_domain *domain); +#ifdef CONFIG_OF_IOMMU +int (*of_xlate)(struct device *dev,struct of_phandle_args *args);
If I understand correctly how it is designed to work, then it should be:
struct iommu_data *(*of_xlate)(struct device *dev, struct of_phandle_args *args);
include/linux/iommu.h struct iommu_ops { · line 146
Quoted 5 lines
include/linux/iommu.h +2
-0+#endif +unsigned long pgsize_bitmap; };
Best regards
Signature · 2 lines
Marek Szyprowski, PhD Samsung R&D Institute Poland
RFC PATCH v2 3/7 iommu: add new iommu_ops callback for adding an OF device
Quoted 28 lines · Marek Szyprowski
Quoted 27 lines · Will Deacon
This patch adds a new function to the
iommu_opsstructure to allow an OF device to be added to a specific IOMMU instance using the recently merged generic devicetree binding for IOMMUs. The callback (of_xlate) takes a struct device representing the master and anof_phandle_argsrepresenting the IOMMU and the correspondong IDs for the new master.Signed-off-by Will Deacon <[email protected]>--- include/linux/iommu.h | 5 +++++ 1 file changed, 5 insertions(+)include/linux/iommu.h +1
-0@@ -21,6 +21,7 @@#include <linux/errno.h> #include <linux/err.h> +#include <linux/of.h> #include <linux/types.h> #include <trace/events/iommu.h> @@ -136,6 +137,10 @@ struct iommu_ops {/* Get the numer of window per domain */ u32 (*domain_get_windows)(struct iommu_domain *domain);
Quoted 7 lines
include/linux/iommu.h struct iommu_ops { · line 141
Quoted 2 lines
include/linux/iommu.h +2
-0+#ifdef CONFIG_OF_IOMMU +int (*of_xlate)(struct device *dev,struct of_phandle_args *args);If I understand correctly how it is designed to work, then it should be:
struct
iommu_data*(*of_xlate)(struct device *dev, structof_phandle_args*args);
Yeah, that might be cleaner than the of_iommu_get_data call in of_dma_configure. I'm currently cooking a v3, so I'll include this change.
Will
RFC PATCH v2 3/7 iommu: add new iommu_ops callback for adding an OF device
Quoted 7 lines · Will Deacon
Quoted 6 lines · Marek Szyprowski
include/linux/iommu.h struct iommu_ops { · line 141
Quoted 2 lines · Will Deacon
include/linux/iommu.h +2
-0+#ifdef CONFIG_OF_IOMMU +int (*of_xlate)(struct device *dev,struct of_phandle_args *args);If I understand correctly how it is designed to work, then it should be:
Quoted 5 lines
Quoted 2 lines
struct
iommu_data*(*of_xlate)(struct device *dev, structof_phandle_args*args);Yeah, that might be cleaner than the
of_iommu_get_datacall inof_dma_configure. I'm currently cooking a v3, so I'll include this change.
Actually, I spoke too soon. If we make of_xlate return the iommu_data, then we have to continue getting the iommu_ops from the bus_type, otherwise we have no way to call the right of_xlate.
So I'd rather leave of_dma_configure using of_iommu_get_data (I'm currently ripping out the bus code in there) so that we can embed the iommu_ops in iommu_data instead.
Will
RFC PATCH v2 4/7 iommu: provide helper function to configure an IOMMU for an of master
In reply to Will DeaconThe generic IOMMU device-tree bindings can be used to add arbitrary OF masters to an IOMMU with a compliant binding.
This patch introduces of_iommu_configure, which does exactly that.
--- drivers/iommu/Kconfig | 2 +- drivers/iommu/of_iommu.c | 52 +++++++++++++++++++++++++++++++++++++++++++++ include/linux/dma-mapping.h | 7 ++++++ include/linux/of_iommu.h | 8 +++++++ 4 files changed, 68 insertions(+), 1 deletion(-)
drivers/iommu/Kconfig +1 -1
@@ -15,7 +15,7 @@ if IOMMU_SUPPORT config OF_IOMMU def_bool y - depends on OF + depends on OF && IOMMU_API config FSL_PAMU bool "Freescale IOMMU support"
drivers/iommu/of_iommu.c +52 -0
64 lines not on this page · raw message
include/linux/dma-mapping.h +7 -0
@@ -62,6 +62,13 @@ struct dma_map_ops {int is_phys; }; +struct iommu_data ; + +struct iommu_dma_mapping { +struct iommu_data *iommu; +struct list_head node; +}; +#define DMA_BIT_MASK (n) (((n) == 64) ? ~0ULL : ((1ULL<<(n))-1))#define DMA_MASK_NONE 0x0ULL
include/linux/of_iommu.h +8 -0
@@ -1,9 +1,12 @@#ifndef __OF_IOMMU_H#define __OF_IOMMU_H +#include <linux/device.h> #include <linux/iommu.h> #include <linux/of.h> +struct iommu_dma_mapping ; +#ifdef CONFIG_OF_IOMMU extern int of_get_dma_window(struct device_node *dn, const char *prefix,
@@ -11,6 +14,7 @@ extern int of_get_dma_window(struct device_node *dn, const char *prefix, size_t *size);extern void of_iommu_init (void ); +extern struct iommu_dma_mapping *of_iommu_configure (struct device *dev);#else
@@ -22,6 +26,10 @@ static inline int of_get_dma_window(struct device_node *dn, const char *prefix, }static inline void of_iommu_init (void ) { } +static inline struct iommu_dma_mapping *of_iommu_configure (struct device *dev) +{ +return NULL ; +}#endif /* CONFIG_OF_IOMMU */
Signature · 1 line
2.1.0
Arnd Bergmann
maintainerRFC PATCH v2 4/7 iommu: provide helper function to configure an IOMMU for an of master
drivers/iommu/of_iommu.c int of_get_dma_window(struct device_node *dn, const char *prefix, int index, · line 99
Quoted 6 lines · On Tuesday 02 September 2014 18:56:24 Will Deacon wrote:
drivers/iommu/of_iommu.c +6
-0+struct iommu_dma_mapping *of_iommu_configure (struct device *dev) +{ +struct of_phandle_args iommu_spec; +struct iommu_dma_mapping *mapping; +struct bus_type *bus = dev->bus; +const struct iommu_ops *ops = bus->iommu_ops;
I think it would be best to not even introduce the tight coupling between bus_type and iommu_ops here, one of the main reasons we are doing this is to break that connection.
Better put the iommu_ops into the iommu_data pointer that gets looked up per iommu device.
Quoted 11 lines
drivers/iommu/of_iommu.c +11
-0+struct iommu_data *iommu =NULL ; +int idx =0 ; + +if (!iommu_present (bus) || !ops->of_xlate) +return NULL ; + +/* +* We don't currently walk up the tree looking for a parent IOMMU. +* See the `Notes:' section of +* Documentation/devicetree/bindings/iommu/iommu.txt +*/
drivers/iommu/of_iommu.c int of_get_dma_window(struct device_node *dn, const char *prefix, int index, · line 119
Quoted 10 lines
drivers/iommu/of_iommu.c +10
-0+*/ +while (!of_parse_phandle_with_args (dev->of_node,"iommus" , +"#iommu-cells" , idx, + &iommu_spec)) { +struct device_node *np = iommu_spec.np; +struct iommu_data *data =of_iommu_get_data (np); + +if (!iommu) { +if (!ops->of_xlate (dev, &iommu_spec)) + iommu = data;
I would make the first argument of the of_xlate function the iommu_data, so the code can find the right instance.
Maybe also add an extra argument at the end that can be used by the PCI code and potentially other drivers with multiple master IDs behind one "iommus" property to pass some value identifying which of the masters is meant.
The format of that is unfortunately bus specific and our platform_bus really covers a number of different hardware buses (AXI, AHB, OPB, ...) but the caller should be able to provide the data in the right form that the iommu understands. I would try using a single u64 argument as a start, hoping that this covers all the buses we need. At least it's enough for PCI (bus/device/function) and for AXI (requester-id?).
Quoted 11 lines
drivers/iommu/of_iommu.c +10
-0+ }else if (iommu != data) { +pr_warn ("Rejecting device %s with multiple IOMMU instances\n" , +dev_name (dev)); + iommu =NULL ; + } + +of_node_put (np); + +if (!iommu) +break ;
drivers/iommu/of_iommu.c int of_get_dma_window(struct device_node *dn, const char *prefix, int index, · line 139
Quoted 10 lines
drivers/iommu/of_iommu.c +10
-0+ + idx++; + } + +if (!iommu) +return NULL ; + + mapping =devm_kzalloc (dev,sizeof (*mapping),GFP_KERNEL ); +if (!mapping) +return NULL ;
I don't think it's safe to use devm_* functions here: this is during device discovery, and this data will be freed if probe() fails or the device gets removed from a driver.
Arnd
RFC PATCH v2 4/7 iommu: provide helper function to configure an IOMMU for an of master
Hi Arnd,
Thanks for the review.
Quoted 12 lines · Arnd Bergmann
drivers/iommu/of_iommu.c int of_get_dma_window(struct device_node *dn, const char *prefix, int index, · line 99
Quoted 6 lines · On Tuesday 02 September 2014 18:56:24 Will Deacon wrote:
drivers/iommu/of_iommu.c +6
-0+struct iommu_dma_mapping *of_iommu_configure (struct device *dev) +{ +struct of_phandle_args iommu_spec; +struct iommu_dma_mapping *mapping; +struct bus_type *bus = dev->bus; +const struct iommu_ops *ops = bus->iommu_ops;I think it would be best to not even introduce the tight coupling between
bus_typeandiommu_opshere, one of the main reasons we are doing this is to break that connection.
Quoted 2 lines
Better put the
iommu_opsinto theiommu_datapointer that gets looked up per iommu device.
Yes, I'll add that. It's a bit weird, because those same ops will later be duplicated in iommu_data->domain->ops, but that's an artifact of how the domain is currently constructed by iommu_domain_alloc.
Quoted 16 lines
Quoted 16 lines
drivers/iommu/of_iommu.c +16
-0+struct iommu_data *iommu = NULL; +int idx = 0; + +if (!iommu_present(bus) || !ops->of_xlate) +return NULL; + +/* +* We don't currently walk up the tree looking for a parent IOMMU. +* See the `Notes:' section of +* Documentation/devicetree/bindings/iommu/iommu.txt +*/ + */ + while (!of_parse_phandle_with_args(dev->of_node, "iommus", +"#iommu-cells" , idx, + &iommu_spec)) { +struct device_node *np = iommu_spec.np;
Quoted 8 lines
drivers/iommu/of_iommu.c int of_get_dma_window(struct device_node *dn, const char *prefix, int index, · line 119
Quoted 5 lines
drivers/iommu/of_iommu.c +5
-0+struct iommu_data *data =of_iommu_get_data (np); + +if (!iommu) { +if (!ops->of_xlate (dev, &iommu_spec)) + iommu = data;I would make the first argument of the
of_xlatefunction theiommu_data, so the code can find the right instance.
Oops, that's what I intended. Well spotted.
Quoted 11 lines
Maybe also add an extra argument at the end that can be used by the PCI code and potentially other drivers with multiple master IDs behind one "iommus" property to pass some value identifying which of the masters is meant.
The format of that is unfortunately bus specific and our
platform_busreally covers a number of different hardware buses (AXI, AHB, OPB, ...) but the caller should be able to provide the data in the right form that the iommu understands. I would try using a single u64 argument as a start, hoping that this covers all the buses we need. At least it's enough for PCI (bus/device/function) and for AXI (requester-id?).
Yeah, I think that will work. It's kind of like a device `index' for a device that sits behind a bridge (trying to avoid yet another ID parameter :).
Quoted 18 lines
Quoted 18 lines
drivers/iommu/of_iommu.c +17
-0+ }else if (iommu != data) { +pr_warn ("Rejecting device %s with multiple IOMMU instances\n" , +dev_name (dev)); + iommu =NULL ; + } + +of_node_put (np); + +if (!iommu) +break ; + + idx++; + } + +if (!iommu) +return NULL ; +
Quoted 8 lines
drivers/iommu/of_iommu.c int of_get_dma_window(struct device_node *dn, const char *prefix, int index, · line 139
Quoted 4 lines
drivers/iommu/of_iommu.c +3
-0+ mapping =devm_kzalloc (dev,sizeof (*mapping),GFP_KERNEL ); +if (!mapping) +return NULL ;I don't think it's safe to use devm_* functions here: this is during device discovery, and this data will be freed if
probe()fails or the device gets removed from a driver.
So I can make this a standard kzalloc, but I have no idea where the corresponding kfree should live. Is there something equivalent to of_dma_unconfigure, or is this data that is expected to persist?
Will
Arnd Bergmann
maintainerRFC PATCH v2 4/7 iommu: provide helper function to configure an IOMMU for an of master
Quoted 27 lines · On Thursday 04 September 2014 12:26:25 Will Deacon wrote:
Quoted 18 lines
Quoted 18 lines
drivers/iommu/of_iommu.c +17
-0+ }else if (iommu != data) { +pr_warn ("Rejecting device %s with multiple IOMMU instances\n" , +dev_name (dev)); + iommu =NULL ; + } + +of_node_put (np); + +if (!iommu) +break ; + + idx++; + } + +if (!iommu) +return NULL ; +Quoted 8 lines
drivers/iommu/of_iommu.c int of_get_dma_window(struct device_node *dn, const char *prefix, int index, · line 139
Quoted 4 lines
drivers/iommu/of_iommu.c +3
-0+ mapping =devm_kzalloc (dev,sizeof (*mapping),GFP_KERNEL ); +if (!mapping) +return NULL ;I don't think it's safe to use devm_* functions here: this is during device discovery, and this data will be freed if
probe()fails or the device gets removed from a driver.
Quoted 4 lines
So I can make this a standard kzalloc, but I have no idea where the corresponding kfree should live. Is there something equivalent to
of_dma_unconfigure, or is this data that is expected to persist?
Can this be a simple kfree in of_platform_device_create_pdata?
Arnd
RFC PATCH v2 4/7 iommu: provide helper function to configure an IOMMU for an of master
Quoted 28 lines · Arnd Bergmann
Quoted 27 lines · On Thursday 04 September 2014 12:26:25 Will Deacon wrote:
Quoted 26 lines
Quoted 12 lines
drivers/iommu/of_iommu.c +10
-0+ }else if (iommu != data) { +pr_warn ("Rejecting device %s with multiple IOMMU instances\n" , +dev_name (dev)); + iommu =NULL ; + } + +of_node_put (np); + +if (!iommu) +break ;drivers/iommu/of_iommu.c int of_get_dma_window(struct device_node *dn, const char *prefix, int index, · line 139
Quoted 10 lines
drivers/iommu/of_iommu.c +10
-0+ + idx++; + } + +if (!iommu) +return NULL ; + + mapping =devm_kzalloc (dev,sizeof (*mapping),GFP_KERNEL ); +if (!mapping) +return NULL ;I don't think it's safe to use devm_* functions here: this is during device discovery, and this data will be freed if
probe()fails or the device gets removed from a driver.
Quoted 6 lines
Quoted 4 lines
So I can make this a standard kzalloc, but I have no idea where the corresponding kfree should live. Is there something equivalent to
of_dma_unconfigure, or is this data that is expected to persist?Can this be a simple kfree in
of_platform_device_create_pdata?
We could certainly hook into the error path there (when of_device_add fails), yes, but I was also thinking about device removal and whether we need to care about that. I guess not for the OF case.
Will
RFC PATCH v2 4/7 iommu: provide helper function to configure an IOMMU for an of master
In reply to Will DeaconHi Will,
Thank you for the patch.
Quoted 58 lines · On Tuesday 02 September 2014 18:56:24 Will Deacon wrote:
The generic IOMMU device-tree bindings can be used to add arbitrary OF masters to an IOMMU with a compliant binding.
This patch introduces
of_iommu_configure, which does exactly that.Signed-off-by Will Deacon <[email protected]>--- drivers/iommu/Kconfig | 2 +- drivers/iommu/of_iommu.c | 52 ++++++++++++++++++++++++++++++++++++++++++ include/linux/dma-mapping.h | 7 ++++++ include/linux/of_iommu.h | 8 +++++++ 4 files changed, 68 insertions(+), 1 deletion(-)drivers/iommu/Kconfig +1
-1@@ -15,7 +15,7 @@ if IOMMU_SUPPORT config OF_IOMMU def_bool y - depends on OF + depends on OF && IOMMU_API config FSL_PAMU bool "Freescale IOMMU support"drivers/iommu/of_iommu.c +17
-0@@ -18,6 +18,7 @@*/ #include <linux/export.h> +#include <linux/iommu.h> #include <linux/limits.h> #include <linux/of.h> #include <linux/of_iommu.h> @@ -90,6 +91,57 @@ int of_get_dma_window(struct device_node *dn, const char *prefix, int index, }EXPORT_SYMBOL_GPL (of_get_dma_window); +struct iommu_dma_mapping *of_iommu_configure (struct device *dev) +{ +struct of_phandle_args iommu_spec; +struct iommu_dma_mapping *mapping; +struct bus_type *bus = dev->bus; +const struct iommu_ops *ops = bus->iommu_ops; +struct iommu_data *iommu =NULL ; +int idx =0 ; + +if (!iommu_present (bus) || !ops->of_xlate) +return NULL ; + +/* +* We don't currently walk up the tree looking for a parent IOMMU. +* See the `Notes:' section of +* Documentation/devicetree/bindings/iommu/iommu.txt
drivers/iommu/of_iommu.c int of_get_dma_window(struct device_node *dn, const char · line 119
Quoted 10 lines
drivers/iommu/of_iommu.c +10
-0+*/ +while (!of_parse_phandle_with_args (dev->of_node,"iommus" , +"#iommu-cells" , idx, + &iommu_spec)) { +struct device_node *np = iommu_spec.np; +struct iommu_data *data =of_iommu_get_data (np); + +if (!iommu) { +if (!ops->of_xlate (dev, &iommu_spec)) + iommu = data;
If I understand the code correctly, this will call of_xlate for the first IOMMU reference only and silently ignore all subsequent references if they point to the same IOMMU device but with different stream/requester IDs. Is that the desired behaviour ?
Quoted 81 lines
drivers/iommu/of_iommu.c +25
-0+ }else if (iommu != data) { +pr_warn ("Rejecting device %s with multiple IOMMU instances\n" , +dev_name (dev)); + iommu =NULL ; + } + +of_node_put (np); + +if (!iommu) +break ; + + idx++; + } + +if (!iommu) +return NULL ; + + mapping =devm_kzalloc (dev,sizeof (*mapping),GFP_KERNEL ); +if (!mapping) +return NULL ; + + mapping->iommu = iommu; +return mapping; +} +void __init of_iommu_init (void ) {struct device_node *np;include/linux/dma-mapping.h +7
-0@@ -62,6 +62,13 @@ struct dma_map_ops {int is_phys; }; +struct iommu_data ; + +struct iommu_dma_mapping { +struct iommu_data *iommu; +struct list_head node; +}; +#define DMA_BIT_MASK (n) (((n) == 64) ? ~0ULL : ((1ULL<<(n))-1))#define DMA_MASK_NONE 0x0ULLinclude/linux/of_iommu.h +7
-0@@ -1,9 +1,12 @@#ifndef __OF_IOMMU_H#define __OF_IOMMU_H +#include <linux/device.h> #include <linux/iommu.h> #include <linux/of.h> +struct iommu_dma_mapping ; +#ifdef CONFIG_OF_IOMMU extern int of_get_dma_window(struct device_node *dn, const char *prefix,@@ -11,6 +14,7 @@ extern int of_get_dma_window(struct device_node *dn, const char *prefix, size_t *size);extern void of_iommu_init (void ); +extern struct iommu_dma_mapping *of_iommu_configure (struct device *dev);#else @@ -22,6 +26,10 @@ static inline int of_get_dma_window(struct device_node *dn, const char *prefix, }static inline void of_iommu_init (void ) { } +static inline struct iommu_dma_mapping *of_iommu_configure (struct device *dev) +{ +return NULL ; +}#endif /* CONFIG_OF_IOMMU */
Signature · 3 lines
Regards, Laurent Pinchart
RFC PATCH v2 4/7 iommu: provide helper function to configure an IOMMU for an of master
Hi Laurent,
Cheers for the review.
Quoted 24 lines · Laurent Pinchart
Quoted 23 lines · On Tuesday 02 September 2014 18:56:24 Will Deacon wrote:
drivers/iommu/of_iommu.c +23
-0+struct iommu_dma_mapping *of_iommu_configure (struct device *dev) +{ +struct of_phandle_args iommu_spec; +struct iommu_dma_mapping *mapping; +struct bus_type *bus = dev->bus; +const struct iommu_ops *ops = bus->iommu_ops; +struct iommu_data *iommu =NULL ; +int idx =0 ; + +if (!iommu_present (bus) || !ops->of_xlate) +return NULL ; + +/* +* We don't currently walk up the tree looking for a parent IOMMU. +* See the `Notes:' section of +* Documentation/devicetree/bindings/iommu/iommu.txt +*/ +while (!of_parse_phandle_with_args (dev->of_node,"iommus" , +"#iommu-cells" , idx, + &iommu_spec)) { +struct device_node *np = iommu_spec.np; +struct iommu_data *data =of_iommu_get_data (np); +
Quoted 8 lines
drivers/iommu/of_iommu.c int of_get_dma_window(struct device_node *dn, const char *prefix, int index, · line 119
Quoted 3 lines
drivers/iommu/of_iommu.c +3
-0+if (!iommu) { +if (!ops->of_xlate (dev, &iommu_spec)) + iommu = data;If I understand the code correctly, this will call
of_xlatefor the first IOMMU reference only and silently ignore all subsequent references if they point to the same IOMMU device but with different stream/requester IDs. Is that the desired behaviour ?
No; I just fixed that actually. I'll send a v3 soon which has a bunch of fixes like this.
Will
RFC PATCH v2 5/7 dma-mapping: detect and configure IOMMU in of_dma_configure
In reply to Will DeaconThis patch extends of_dma_configure so that it sets up the IOMMU for a device, as well as the coherent/non-coherent DMA mapping ops.
--- arch/arm/include/asm/dma-mapping.h | 5 ++++- drivers/of/platform.c | 36 ++++++++++++++++++++++-------------- include/linux/dma-mapping.h | 5 ++++- 3 files changed, 30 insertions(+), 16 deletions(-)
arch/arm/include/asm/dma-mapping.h +4 -1
@@ -122,7 +122,10 @@ static inline unsigned long dma_max_pfn(struct device *dev)#define dma_max_pfn (dev) dma_max_pfn(dev)static inline void arch_setup_dma_ops (struct device *dev,u64 mask, -unsigned long offset,bool coherent) +u64 dma_base,u64 size, +unsigned long offset, +struct iommu_dma_mapping *iommu, +bool coherent) { dev->coherent_dma_mask = mask; dev->dma_mask = &dev->coherent_dma_mask;
drivers/of/platform.c +22 -14
@@ -19,6 +19,7 @@#include <linux/slab.h> #include <linux/of_address.h> #include <linux/of_device.h> +#include <linux/of_iommu.h> #include <linux/of_irq.h> #include <linux/of_platform.h> #include <linux/platform_device.h>
@@ -162,25 +163,37 @@ EXPORT_SYMBOL(of_device_alloc);*/ static void of_dma_configure (struct platform_device *pdev) { -u64 dma_addr, paddr, size; +u64 dma_addr, paddr, size, mask;int ret;bool coherent;unsigned long offset; +struct iommu_dma_mapping *iommu;struct device *dev = &pdev->dev; +/* +* Set default dma-mask to 32 bit. Drivers are expected to setup +* the correct supported dma_mask. +*/ + mask =DMA_BIT_MASK (32 ); + ret =of_dma_get_range (dev->of_node, &dma_addr, &paddr, &size); - offset = ret <0 ?0 :PFN_DOWN (paddr - dma_addr); -dev_dbg (dev,"dma_pfn_offset(%#08lx)\n" , dev->dma_pfn_offset); +if (ret <0 ) { + dma_addr = offset =0 ; + size = mask; + }else { + offset =PFN_DOWN (paddr - dma_addr); +dev_dbg (dev,"dma_pfn_offset(%#08lx)\n" , dev->dma_pfn_offset); + } coherent =of_dma_is_coherent (dev->of_node);dev_dbg (dev,"device is%sdma coherent\n" , coherent ?" " :" not " ); -/* -* Set default dma-mask to 32 bit. Drivers are expected to setup -* the correct supported dma_mask. -*/ -arch_setup_dma_ops (dev,DMA_BIT_MASK (32 ), offset, coherent); + iommu =of_iommu_configure (dev); +dev_dbg (dev,"device is%sbehind an iommu\n" , + iommu ?" " :" not " ); + +arch_setup_dma_ops (dev, mask, dma_addr, size, offset, iommu, coherent); }/**
@@ -209,14 +222,9 @@ static struct platform_device *of_platform_device_create_pdata(if (!dev) goto err_clear_flag; -of_dma_configure (dev); dev->dev.bus = &platform_bus_type; dev->dev.platform_data = platform_data; - -/* We do not fill the DMA ops for platform devices by default. -* This is currently the responsibility of the platform code -* to do such, possibly using a device notifier -*/ +of_dma_configure (dev);if (of_device_add (dev) !=0 ) {platform_device_put (dev);
include/linux/dma-mapping.h +4 -1
@@ -138,7 +138,10 @@ extern u64 dma_get_required_mask(struct device *dev);#ifndef arch_setup_dma_opsstatic inline void arch_setup_dma_ops (struct device *dev,u64 mask, -unsigned long offset,bool coherent) { } +u64 dma_base,u64 size, +unsigned long offset, +struct iommu_dma_mapping *iommu, +bool coherent) { }#endif static inline unsigned int dma_get_max_seg_size (struct device *dev)
Signature · 1 line
2.1.0
RFC PATCH v2 6/7 arm: call iommu_init before of_platform_populate
In reply to Will DeaconWe need to ensure that the IOMMUs in the system have a chance to perform some basic initialisation before we start adding masters to them.
This patch adds a call to of_iommu_init before of_platform_populate.
--- arch/arm/kernel/setup.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
arch/arm/kernel/setup.c +4 -1
@@ -18,6 +18,7 @@#include <linux/bootmem.h> #include <linux/seq_file.h> #include <linux/screen_info.h> +#include <linux/of_iommu.h> #include <linux/of_platform.h> #include <linux/init.h> #include <linux/kexec.h>
@@ -803,9 +804,11 @@ static int __init customize_machine(void)if (machine_desc->init_machine) machine_desc->init_machine ();#ifdef CONFIG_OF - else + else { +of_iommu_init ();of_platform_populate (NULL , of_default_bus_match_table,NULL ,NULL ); + }#endif return 0 ; }
Signature · 1 line
2.1.0
Arnd Bergmann
maintainerRFC PATCH v2 6/7 arm: call iommu_init before of_platform_populate
arch/arm/kernel/setup.c static int __init customize_machine(void) · line 814
Quoted 13 lines · On Tuesday 02 September 2014 18:56:26 Will Deacon wrote:
arch/arm/kernel/setup.c +3
-1@@ -803,9 +804,11 @@ static int __init customize_machine(void)if (machine_desc->init_machine) machine_desc->init_machine ();#ifdef CONFIG_OF - else + else { +of_iommu_init ();of_platform_populate (NULL , of_default_bus_match_table,NULL ,NULL ); + }#endif return 0 ; }
I think it would be better to not have this depend on the presence of an init_machine callback. Why not move of_iommu_init() in front of the if()? It shouldn't do anything unless we have an iommu driver that we should be using.
Arnd
RFC PATCH v2 7/7 arm: dma-mapping: plumb our iommu mapping ops into arch_setup_dma_ops
In reply to Will DeaconThis patch plumbs the existing ARM IOMMU DMA infrastructure (which isn't actually called outside of a few drivers) into arch_setup_dma_ops, so that we can use IOMMUs for DMA transfers in a more generic fashion.
Since this significantly complicates the arch_setup_dma_ops function, it is moved out of line into dma-mapping.c. If CONFIG_ARM_DMA_USE_IOMMU is not set, the iommu paramater is ignored and the normal ops are used instead.
--- arch/arm/include/asm/dma-mapping.h | 17 +++------ arch/arm/mm/dma-mapping.c | 72 +++++++++++++++++++++++++++++++++----- 2 files changed, 68 insertions(+), 21 deletions(-)
arch/arm/include/asm/dma-mapping.h +4 -13
@@ -121,20 +121,11 @@ static inline unsigned long dma_max_pfn(struct device *dev) }#define dma_max_pfn (dev) dma_max_pfn(dev) -static inline void arch_setup_dma_ops (struct device *dev,u64 mask, -u64 dma_base,u64 size, -unsigned long offset, -struct iommu_dma_mapping *iommu, -bool coherent) -{ - dev->coherent_dma_mask = mask; - dev->dma_mask = &dev->coherent_dma_mask; - dev->dma_pfn_offset = offset; - -if (coherent) -set_dma_ops (dev, &arm_coherent_dma_ops); -}#define arch_setup_dma_ops arch_setup_dma_ops +extern void arch_setup_dma_ops (struct device *dev,u64 mask,u64 dma_base, +u64 size,unsigned long offset, +struct iommu_dma_mapping *iommu, +bool coherent);static inline dma_addr_t phys_to_dma (struct device *dev,phys_addr_t paddr) {
arch/arm/mm/dma-mapping.c +64 -8
98 lines not on this page · raw message
Signature · 1 line
2.1.0
Arnd Bergmann
maintainerRFC PATCH v2 7/7 arm: dma-mapping: plumb our iommu mapping ops into arch_setup_dma_ops
Quoted 11 lines · On Tuesday 02 September 2014 18:56:27 Will Deacon wrote:
This patch plumbs the existing ARM IOMMU DMA infrastructure (which isn't actually called outside of a few drivers) into
arch_setup_dma_ops, so that we can use IOMMUs for DMA transfers in a more generic fashion.Since this significantly complicates the
arch_setup_dma_opsfunction, it is moved out of line intodma-mapping.c. IfCONFIG_ARM_DMA_USE_IOMMUis not set, the iommu paramater is ignored and the normal ops are used instead.Signed-off-by Will Deacon <[email protected]>
Looks great to me.
Arnd
Arnd Bergmann
maintainerv2 cover Introduce automatic DMA configuration for IOMMU masters
In reply to Will DeaconQuoted 7 lines · On Tuesday 02 September 2014 18:56:20 Will Deacon wrote:
The main difference since v1 is that I've introduced some generic structures to represent IOMMUs and their mappings (struct
iommu_dataand structiommu_dma_mapping). This allows us to propagate the per-instance data all the way down to the DMA-mapping code, which can then manage a per-instance domain. Note that the ARM dma-mapping implementation does not currently make use of this information.
Overall I'm pretty happy with how this is turning out so far. I have commented on a few patches, everything else looks good to me.
Arnd