Skip to content

Commit fd522d2

Browse files
committed
Merge tag 'of-iommu-configure' of git://git.kernel.org/pub/scm/linux/kernel/git/will/linux into next/iommu-config
Pull "Automatic DMA configuration for OF-based IOMMU masters" from Will Deacon: This series adds automatic IOMMU and DMA-mapping configuration for OF-based DMA masters described using the generic IOMMU devicetree bindings. Although there is plenty of future work around splitting up iommu_ops, adding default IOMMU domains and sorting out automatic IOMMU group creation for the platform_bus, this is already useful enough for people to port over their IOMMU drivers and start using the new probing infrastructure (indeed, Marek has patches queued for the Exynos IOMMU). * tag 'of-iommu-configure' of git://git.kernel.org/pub/scm/linux/kernel/git/will/linux: iommu: store DT-probed IOMMU data privately arm: dma-mapping: plumb our iommu mapping ops into arch_setup_dma_ops arm: call iommu_init before of_platform_populate dma-mapping: detect and configure IOMMU in of_dma_configure iommu: fix initialization without 'add_device' callback iommu: provide helper function to configure an IOMMU for an of master iommu: add new iommu_ops callback for adding an OF device dma-mapping: replace set_arch_dma_coherent_ops with arch_setup_dma_ops iommu: provide early initialisation hook for IOMMU drivers Signed-off-by: Arnd Bergmann <arnd@arndb.de>
2 parents 5d01410 + a42a7a1 commit fd522d2

File tree

11 files changed

+242
-44
lines changed

11 files changed

+242
-44
lines changed

arch/arm/include/asm/dma-mapping.h

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -121,12 +121,12 @@ static inline unsigned long dma_max_pfn(struct device *dev)
121121
}
122122
#define dma_max_pfn(dev) dma_max_pfn(dev)
123123

124-
static inline int set_arch_dma_coherent_ops(struct device *dev)
125-
{
126-
set_dma_ops(dev, &arm_coherent_dma_ops);
127-
return 0;
128-
}
129-
#define set_arch_dma_coherent_ops(dev) set_arch_dma_coherent_ops(dev)
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);
130130

131131
static inline dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr)
132132
{

arch/arm/kernel/setup.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include <linux/bootmem.h>
1919
#include <linux/seq_file.h>
2020
#include <linux/screen_info.h>
21+
#include <linux/of_iommu.h>
2122
#include <linux/of_platform.h>
2223
#include <linux/init.h>
2324
#include <linux/kexec.h>
@@ -806,6 +807,7 @@ static int __init customize_machine(void)
806807
* machine from the device tree, if no callback is provided,
807808
* otherwise we would always need an init_machine callback.
808809
*/
810+
of_iommu_init();
809811
if (machine_desc->init_machine)
810812
machine_desc->init_machine();
811813
#ifdef CONFIG_OF

arch/arm/mm/dma-mapping.c

Lines changed: 76 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1947,9 +1947,8 @@ EXPORT_SYMBOL_GPL(arm_iommu_release_mapping);
19471947
* arm_iommu_create_mapping)
19481948
*
19491949
* Attaches specified io address space mapping to the provided device,
1950-
* this replaces the dma operations (dma_map_ops pointer) with the
1951-
* IOMMU aware version. More than one client might be attached to
1952-
* the same io address space mapping.
1950+
* More than one client might be attached to the same io address space
1951+
* mapping.
19531952
*/
19541953
int arm_iommu_attach_device(struct device *dev,
19551954
struct dma_iommu_mapping *mapping)
@@ -1962,7 +1961,6 @@ int arm_iommu_attach_device(struct device *dev,
19621961

19631962
kref_get(&mapping->kref);
19641963
dev->archdata.mapping = mapping;
1965-
set_dma_ops(dev, &iommu_ops);
19661964

19671965
pr_debug("Attached IOMMU controller to %s device.\n", dev_name(dev));
19681966
return 0;
@@ -1974,7 +1972,6 @@ EXPORT_SYMBOL_GPL(arm_iommu_attach_device);
19741972
* @dev: valid struct device pointer
19751973
*
19761974
* Detaches the provided device from a previously attached map.
1977-
* This voids the dma operations (dma_map_ops pointer)
19781975
*/
19791976
void arm_iommu_detach_device(struct device *dev)
19801977
{
@@ -1989,10 +1986,82 @@ void arm_iommu_detach_device(struct device *dev)
19891986
iommu_detach_device(mapping->domain, dev);
19901987
kref_put(&mapping->kref, release_iommu_mapping);
19911988
dev->archdata.mapping = NULL;
1992-
set_dma_ops(dev, NULL);
19931989

19941990
pr_debug("Detached IOMMU controller from %s device.\n", dev_name(dev));
19951991
}
19961992
EXPORT_SYMBOL_GPL(arm_iommu_detach_device);
19971993

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+
}

drivers/iommu/Kconfig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ if IOMMU_SUPPORT
1515

1616
config OF_IOMMU
1717
def_bool y
18-
depends on OF
18+
depends on OF && IOMMU_API
1919

2020
config FSL_PAMU
2121
bool "Freescale IOMMU support"

drivers/iommu/iommu.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -737,7 +737,7 @@ static int add_iommu_group(struct device *dev, void *data)
737737
const struct iommu_ops *ops = cb->ops;
738738

739739
if (!ops->add_device)
740-
return -ENODEV;
740+
return 0;
741741

742742
WARN_ON(dev->iommu_group);
743743

drivers/iommu/of_iommu.c

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,14 @@
1818
*/
1919

2020
#include <linux/export.h>
21+
#include <linux/iommu.h>
2122
#include <linux/limits.h>
2223
#include <linux/of.h>
2324
#include <linux/of_iommu.h>
25+
#include <linux/slab.h>
26+
27+
static const struct of_device_id __iommu_of_table_sentinel
28+
__used __section(__iommu_of_table_end);
2429

2530
/**
2631
* of_get_dma_window - Parse *dma-window property and returns 0 if found.
@@ -89,3 +94,87 @@ int of_get_dma_window(struct device_node *dn, const char *prefix, int index,
8994
return 0;
9095
}
9196
EXPORT_SYMBOL_GPL(of_get_dma_window);
97+
98+
struct of_iommu_node {
99+
struct list_head list;
100+
struct device_node *np;
101+
struct iommu_ops *ops;
102+
};
103+
static LIST_HEAD(of_iommu_list);
104+
static DEFINE_SPINLOCK(of_iommu_lock);
105+
106+
void of_iommu_set_ops(struct device_node *np, struct iommu_ops *ops)
107+
{
108+
struct of_iommu_node *iommu = kzalloc(sizeof(*iommu), GFP_KERNEL);
109+
110+
if (WARN_ON(!iommu))
111+
return;
112+
113+
INIT_LIST_HEAD(&iommu->list);
114+
iommu->np = np;
115+
iommu->ops = ops;
116+
spin_lock(&of_iommu_lock);
117+
list_add_tail(&iommu->list, &of_iommu_list);
118+
spin_unlock(&of_iommu_lock);
119+
}
120+
121+
struct iommu_ops *of_iommu_get_ops(struct device_node *np)
122+
{
123+
struct of_iommu_node *node;
124+
struct iommu_ops *ops = NULL;
125+
126+
spin_lock(&of_iommu_lock);
127+
list_for_each_entry(node, &of_iommu_list, list)
128+
if (node->np == np) {
129+
ops = node->ops;
130+
break;
131+
}
132+
spin_unlock(&of_iommu_lock);
133+
return ops;
134+
}
135+
136+
struct iommu_ops *of_iommu_configure(struct device *dev)
137+
{
138+
struct of_phandle_args iommu_spec;
139+
struct device_node *np;
140+
struct iommu_ops *ops = NULL;
141+
int idx = 0;
142+
143+
/*
144+
* We don't currently walk up the tree looking for a parent IOMMU.
145+
* See the `Notes:' section of
146+
* Documentation/devicetree/bindings/iommu/iommu.txt
147+
*/
148+
while (!of_parse_phandle_with_args(dev->of_node, "iommus",
149+
"#iommu-cells", idx,
150+
&iommu_spec)) {
151+
np = iommu_spec.np;
152+
ops = of_iommu_get_ops(np);
153+
154+
if (!ops || !ops->of_xlate || ops->of_xlate(dev, &iommu_spec))
155+
goto err_put_node;
156+
157+
of_node_put(np);
158+
idx++;
159+
}
160+
161+
return ops;
162+
163+
err_put_node:
164+
of_node_put(np);
165+
return NULL;
166+
}
167+
168+
void __init of_iommu_init(void)
169+
{
170+
struct device_node *np;
171+
const struct of_device_id *match, *matches = &__iommu_of_table;
172+
173+
for_each_matching_node_and_match(np, matches, &match) {
174+
const of_iommu_init_fn init_fn = match->data;
175+
176+
if (init_fn(np))
177+
pr_err("Failed to initialise IOMMU %s\n",
178+
of_node_full_name(np));
179+
}
180+
}

drivers/of/platform.c

Lines changed: 26 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include <linux/slab.h>
2020
#include <linux/of_address.h>
2121
#include <linux/of_device.h>
22+
#include <linux/of_iommu.h>
2223
#include <linux/of_irq.h>
2324
#include <linux/of_platform.h>
2425
#include <linux/platform_device.h>
@@ -164,6 +165,9 @@ static void of_dma_configure(struct device *dev)
164165
{
165166
u64 dma_addr, paddr, size;
166167
int ret;
168+
bool coherent;
169+
unsigned long offset;
170+
struct iommu_ops *iommu;
167171

168172
/*
169173
* Set default dma-mask to 32 bit. Drivers are expected to setup
@@ -178,28 +182,30 @@ static void of_dma_configure(struct device *dev)
178182
if (!dev->dma_mask)
179183
dev->dma_mask = &dev->coherent_dma_mask;
180184

181-
/*
182-
* if dma-coherent property exist, call arch hook to setup
183-
* dma coherent operations.
184-
*/
185-
if (of_dma_is_coherent(dev->of_node)) {
186-
set_arch_dma_coherent_ops(dev);
187-
dev_dbg(dev, "device is dma coherent\n");
188-
}
189-
190-
/*
191-
* if dma-ranges property doesn't exist - just return else
192-
* setup the dma offset
193-
*/
194185
ret = of_dma_get_range(dev->of_node, &dma_addr, &paddr, &size);
195186
if (ret < 0) {
196-
dev_dbg(dev, "no dma range information to setup\n");
197-
return;
187+
dma_addr = offset = 0;
188+
size = dev->coherent_dma_mask;
189+
} else {
190+
offset = PFN_DOWN(paddr - dma_addr);
191+
dev_dbg(dev, "dma_pfn_offset(%#08lx)\n", dev->dma_pfn_offset);
198192
}
193+
dev->dma_pfn_offset = offset;
194+
195+
coherent = of_dma_is_coherent(dev->of_node);
196+
dev_dbg(dev, "device is%sdma coherent\n",
197+
coherent ? " " : " not ");
198+
199+
iommu = of_iommu_configure(dev);
200+
dev_dbg(dev, "device is%sbehind an iommu\n",
201+
iommu ? " " : " not ");
199202

200-
/* DMA ranges found. Calculate and set dma_pfn_offset */
201-
dev->dma_pfn_offset = PFN_DOWN(paddr - dma_addr);
202-
dev_dbg(dev, "dma_pfn_offset(%#08lx)\n", dev->dma_pfn_offset);
203+
arch_setup_dma_ops(dev, dma_addr, size, iommu, coherent);
204+
}
205+
206+
static void of_dma_deconfigure(struct device *dev)
207+
{
208+
arch_teardown_dma_ops(dev);
203209
}
204210

205211
/**
@@ -228,16 +234,12 @@ static struct platform_device *of_platform_device_create_pdata(
228234
if (!dev)
229235
goto err_clear_flag;
230236

231-
of_dma_configure(&dev->dev);
232237
dev->dev.bus = &platform_bus_type;
233238
dev->dev.platform_data = platform_data;
234-
235-
/* We do not fill the DMA ops for platform devices by default.
236-
* This is currently the responsibility of the platform code
237-
* to do such, possibly using a device notifier
238-
*/
239+
of_dma_configure(&dev->dev);
239240

240241
if (of_device_add(dev) != 0) {
242+
of_dma_deconfigure(&dev->dev);
241243
platform_device_put(dev);
242244
goto err_clear_flag;
243245
}

include/asm-generic/vmlinux.lds.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,7 @@
164164
#define CLKSRC_OF_TABLES() OF_TABLE(CONFIG_CLKSRC_OF, clksrc)
165165
#define IRQCHIP_OF_MATCH_TABLE() OF_TABLE(CONFIG_IRQCHIP, irqchip)
166166
#define CLK_OF_TABLES() OF_TABLE(CONFIG_COMMON_CLK, clk)
167+
#define IOMMU_OF_TABLES() OF_TABLE(CONFIG_OF_IOMMU, iommu)
167168
#define RESERVEDMEM_OF_TABLES() OF_TABLE(CONFIG_OF_RESERVED_MEM, reservedmem)
168169
#define CPU_METHOD_OF_TABLES() OF_TABLE(CONFIG_SMP, cpu_method)
169170
#define EARLYCON_OF_TABLES() OF_TABLE(CONFIG_SERIAL_EARLYCON, earlycon)
@@ -497,6 +498,7 @@
497498
CLK_OF_TABLES() \
498499
RESERVEDMEM_OF_TABLES() \
499500
CLKSRC_OF_TABLES() \
501+
IOMMU_OF_TABLES() \
500502
CPU_METHOD_OF_TABLES() \
501503
KERNEL_DTB() \
502504
IRQCHIP_OF_MATCH_TABLE() \

include/linux/dma-mapping.h

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -129,11 +129,14 @@ static inline int dma_coerce_mask_and_coherent(struct device *dev, u64 mask)
129129

130130
extern u64 dma_get_required_mask(struct device *dev);
131131

132-
#ifndef set_arch_dma_coherent_ops
133-
static inline int set_arch_dma_coherent_ops(struct device *dev)
134-
{
135-
return 0;
136-
}
132+
#ifndef arch_setup_dma_ops
133+
static inline void arch_setup_dma_ops(struct device *dev, u64 dma_base,
134+
u64 size, struct iommu_ops *iommu,
135+
bool coherent) { }
136+
#endif
137+
138+
#ifndef arch_teardown_dma_ops
139+
static inline void arch_teardown_dma_ops(struct device *dev) { }
137140
#endif
138141

139142
static inline unsigned int dma_get_max_seg_size(struct device *dev)

0 commit comments

Comments
 (0)