diff options
author | Will Deacon <will.deacon@arm.com> | 2014-08-27 12:52:44 -0400 |
---|---|---|
committer | Will Deacon <will.deacon@arm.com> | 2014-12-01 11:51:35 -0500 |
commit | 4bb25789ed28228a52c030bf28edb2fcdb214be8 (patch) | |
tree | aafa892add12a5acb47c69696de5dd7c95e0251e | |
parent | af4dda732ea044517f8beed4a38c852ea97e7690 (diff) |
arm: dma-mapping: plumb our iommu mapping ops into arch_setup_dma_ops
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_ops function,
it is moved out of line into dma-mapping.c. If CONFIG_ARM_DMA_USE_IOMMU
is not set, the iommu parameter is ignored and the normal ops are used
instead.
Acked-by: Russell King <rmk+kernel@arm.linux.org.uk>
Acked-by: Arnd Bergmann <arnd@arndb.de>
Acked-by: Marek Szyprowski <m.szyprowski@samsung.com>
Signed-off-by: Will Deacon <will.deacon@arm.com>
-rw-r--r-- | arch/arm/include/asm/dma-mapping.h | 12 | ||||
-rw-r--r-- | arch/arm/mm/dma-mapping.c | 83 |
2 files changed, 81 insertions, 14 deletions
diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h index f3c0d953f6a2..9410b7e548fc 100644 --- a/arch/arm/include/asm/dma-mapping.h +++ b/arch/arm/include/asm/dma-mapping.h | |||
@@ -121,14 +121,12 @@ static inline unsigned long dma_max_pfn(struct device *dev) | |||
121 | } | 121 | } |
122 | #define dma_max_pfn(dev) dma_max_pfn(dev) | 122 | #define dma_max_pfn(dev) dma_max_pfn(dev) |
123 | 123 | ||
124 | static inline void arch_setup_dma_ops(struct device *dev, u64 dma_base, | ||
125 | u64 size, struct iommu_ops *iommu, | ||
126 | bool coherent) | ||
127 | { | ||
128 | if (coherent) | ||
129 | set_dma_ops(dev, &arm_coherent_dma_ops); | ||
130 | } | ||
131 | #define arch_setup_dma_ops arch_setup_dma_ops | 124 | #define arch_setup_dma_ops arch_setup_dma_ops |
125 | extern void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size, | ||
126 | struct iommu_ops *iommu, bool coherent); | ||
127 | |||
128 | #define arch_teardown_dma_ops arch_teardown_dma_ops | ||
129 | extern void arch_teardown_dma_ops(struct device *dev); | ||
132 | 130 | ||
133 | static inline dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr) | 131 | static inline dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr) |
134 | { | 132 | { |
diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index e8907117861e..09645f00bd17 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c | |||
@@ -1947,9 +1947,8 @@ EXPORT_SYMBOL_GPL(arm_iommu_release_mapping); | |||
1947 | * arm_iommu_create_mapping) | 1947 | * arm_iommu_create_mapping) |
1948 | * | 1948 | * |
1949 | * Attaches specified io address space mapping to the provided device, | 1949 | * Attaches specified io address space mapping to the provided device, |
1950 | * this replaces the dma operations (dma_map_ops pointer) with the | 1950 | * More than one client might be attached to the same io address space |
1951 | * IOMMU aware version. More than one client might be attached to | 1951 | * mapping. |
1952 | * the same io address space mapping. | ||
1953 | */ | 1952 | */ |
1954 | int arm_iommu_attach_device(struct device *dev, | 1953 | int arm_iommu_attach_device(struct device *dev, |
1955 | struct dma_iommu_mapping *mapping) | 1954 | struct dma_iommu_mapping *mapping) |
@@ -1962,7 +1961,6 @@ int arm_iommu_attach_device(struct device *dev, | |||
1962 | 1961 | ||
1963 | kref_get(&mapping->kref); | 1962 | kref_get(&mapping->kref); |
1964 | dev->archdata.mapping = mapping; | 1963 | dev->archdata.mapping = mapping; |
1965 | set_dma_ops(dev, &iommu_ops); | ||
1966 | 1964 | ||
1967 | pr_debug("Attached IOMMU controller to %s device.\n", dev_name(dev)); | 1965 | pr_debug("Attached IOMMU controller to %s device.\n", dev_name(dev)); |
1968 | return 0; | 1966 | return 0; |
@@ -1974,7 +1972,6 @@ EXPORT_SYMBOL_GPL(arm_iommu_attach_device); | |||
1974 | * @dev: valid struct device pointer | 1972 | * @dev: valid struct device pointer |
1975 | * | 1973 | * |
1976 | * Detaches the provided device from a previously attached map. | 1974 | * Detaches the provided device from a previously attached map. |
1977 | * This voids the dma operations (dma_map_ops pointer) | ||
1978 | */ | 1975 | */ |
1979 | void arm_iommu_detach_device(struct device *dev) | 1976 | void arm_iommu_detach_device(struct device *dev) |
1980 | { | 1977 | { |
@@ -1989,10 +1986,82 @@ void arm_iommu_detach_device(struct device *dev) | |||
1989 | iommu_detach_device(mapping->domain, dev); | 1986 | iommu_detach_device(mapping->domain, dev); |
1990 | kref_put(&mapping->kref, release_iommu_mapping); | 1987 | kref_put(&mapping->kref, release_iommu_mapping); |
1991 | dev->archdata.mapping = NULL; | 1988 | dev->archdata.mapping = NULL; |
1992 | set_dma_ops(dev, NULL); | ||
1993 | 1989 | ||
1994 | pr_debug("Detached IOMMU controller from %s device.\n", dev_name(dev)); | 1990 | pr_debug("Detached IOMMU controller from %s device.\n", dev_name(dev)); |
1995 | } | 1991 | } |
1996 | EXPORT_SYMBOL_GPL(arm_iommu_detach_device); | 1992 | EXPORT_SYMBOL_GPL(arm_iommu_detach_device); |
1997 | 1993 | ||
1998 | #endif | 1994 | static struct dma_map_ops *arm_get_iommu_dma_map_ops(bool coherent) |
1995 | { | ||
1996 | return coherent ? &iommu_coherent_ops : &iommu_ops; | ||
1997 | } | ||
1998 | |||
1999 | static bool arm_setup_iommu_dma_ops(struct device *dev, u64 dma_base, u64 size, | ||
2000 | struct iommu_ops *iommu) | ||
2001 | { | ||
2002 | struct dma_iommu_mapping *mapping; | ||
2003 | |||
2004 | if (!iommu) | ||
2005 | return false; | ||
2006 | |||
2007 | mapping = arm_iommu_create_mapping(dev->bus, dma_base, size); | ||
2008 | if (IS_ERR(mapping)) { | ||
2009 | pr_warn("Failed to create %llu-byte IOMMU mapping for device %s\n", | ||
2010 | size, dev_name(dev)); | ||
2011 | return false; | ||
2012 | } | ||
2013 | |||
2014 | if (arm_iommu_attach_device(dev, mapping)) { | ||
2015 | pr_warn("Failed to attached device %s to IOMMU_mapping\n", | ||
2016 | dev_name(dev)); | ||
2017 | arm_iommu_release_mapping(mapping); | ||
2018 | return false; | ||
2019 | } | ||
2020 | |||
2021 | return true; | ||
2022 | } | ||
2023 | |||
2024 | static void arm_teardown_iommu_dma_ops(struct device *dev) | ||
2025 | { | ||
2026 | struct dma_iommu_mapping *mapping = dev->archdata.mapping; | ||
2027 | |||
2028 | arm_iommu_detach_device(dev); | ||
2029 | arm_iommu_release_mapping(mapping); | ||
2030 | } | ||
2031 | |||
2032 | #else | ||
2033 | |||
2034 | static bool arm_setup_iommu_dma_ops(struct device *dev, u64 dma_base, u64 size, | ||
2035 | struct iommu_ops *iommu) | ||
2036 | { | ||
2037 | return false; | ||
2038 | } | ||
2039 | |||
2040 | static void arm_teardown_iommu_dma_ops(struct device *dev) { } | ||
2041 | |||
2042 | #define arm_get_iommu_dma_map_ops arm_get_dma_map_ops | ||
2043 | |||
2044 | #endif /* CONFIG_ARM_DMA_USE_IOMMU */ | ||
2045 | |||
2046 | static struct dma_map_ops *arm_get_dma_map_ops(bool coherent) | ||
2047 | { | ||
2048 | return coherent ? &arm_coherent_dma_ops : &arm_dma_ops; | ||
2049 | } | ||
2050 | |||
2051 | void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size, | ||
2052 | struct iommu_ops *iommu, bool coherent) | ||
2053 | { | ||
2054 | struct dma_map_ops *dma_ops; | ||
2055 | |||
2056 | if (arm_setup_iommu_dma_ops(dev, dma_base, size, iommu)) | ||
2057 | dma_ops = arm_get_iommu_dma_map_ops(coherent); | ||
2058 | else | ||
2059 | dma_ops = arm_get_dma_map_ops(coherent); | ||
2060 | |||
2061 | set_dma_ops(dev, dma_ops); | ||
2062 | } | ||
2063 | |||
2064 | void arch_teardown_dma_ops(struct device *dev) | ||
2065 | { | ||
2066 | arm_teardown_iommu_dma_ops(dev); | ||
2067 | } | ||