11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
27568cb4eSPaul Mackerras /*
37568cb4eSPaul Mackerras * Copyright (C) 2001 Mike Corrigan & Dave Engebretsen, IBM Corporation
47568cb4eSPaul Mackerras *
57568cb4eSPaul Mackerras * Rewrite, cleanup, new allocation schemes, virtual merging:
67568cb4eSPaul Mackerras * Copyright (C) 2004 Olof Johansson, IBM Corporation
77568cb4eSPaul Mackerras * and Ben. Herrenschmidt, IBM Corporation
87568cb4eSPaul Mackerras *
97568cb4eSPaul Mackerras * Dynamic DMA mapping support, bus-independent parts.
107568cb4eSPaul Mackerras */
117568cb4eSPaul Mackerras
127568cb4eSPaul Mackerras
137568cb4eSPaul Mackerras #include <linux/init.h>
147568cb4eSPaul Mackerras #include <linux/types.h>
157568cb4eSPaul Mackerras #include <linux/slab.h>
167568cb4eSPaul Mackerras #include <linux/mm.h>
177568cb4eSPaul Mackerras #include <linux/spinlock.h>
187568cb4eSPaul Mackerras #include <linux/string.h>
197568cb4eSPaul Mackerras #include <linux/dma-mapping.h>
20a66022c4SAkinobu Mita #include <linux/bitmap.h>
21fb3475e9SFUJITA Tomonori #include <linux/iommu-helper.h>
2262a8bd6cSMilton Miller #include <linux/crash_dump.h>
23b4c3a872SAnton Blanchard #include <linux/hash.h>
24d6b9a81bSAnton Blanchard #include <linux/fault-inject.h>
25d6b9a81bSAnton Blanchard #include <linux/pci.h>
264e13c1acSAlexey Kardashevskiy #include <linux/iommu.h>
274e13c1acSAlexey Kardashevskiy #include <linux/sched.h>
28691602aaSAlexey Kardashevskiy #include <linux/debugfs.h>
297568cb4eSPaul Mackerras #include <asm/io.h>
307568cb4eSPaul Mackerras #include <asm/iommu.h>
317568cb4eSPaul Mackerras #include <asm/pci-bridge.h>
327568cb4eSPaul Mackerras #include <asm/machdep.h>
335f50867bSHaren Myneni #include <asm/kdump.h>
343ccc00a7SMahesh Salgaonkar #include <asm/fadump.h>
35d6b9a81bSAnton Blanchard #include <asm/vio.h>
364e13c1acSAlexey Kardashevskiy #include <asm/tce.h>
37c10c21efSAlexey Kardashevskiy #include <asm/mmu_context.h>
38a9409044SAlexey Kardashevskiy #include <asm/ppc-pci.h>
397568cb4eSPaul Mackerras
407568cb4eSPaul Mackerras #define DBG(...)
417568cb4eSPaul Mackerras
42691602aaSAlexey Kardashevskiy #ifdef CONFIG_IOMMU_DEBUGFS
iommu_debugfs_weight_get(void * data,u64 * val)43691602aaSAlexey Kardashevskiy static int iommu_debugfs_weight_get(void *data, u64 *val)
44691602aaSAlexey Kardashevskiy {
45691602aaSAlexey Kardashevskiy struct iommu_table *tbl = data;
46691602aaSAlexey Kardashevskiy *val = bitmap_weight(tbl->it_map, tbl->it_size);
47691602aaSAlexey Kardashevskiy return 0;
48691602aaSAlexey Kardashevskiy }
49691602aaSAlexey Kardashevskiy DEFINE_DEBUGFS_ATTRIBUTE(iommu_debugfs_fops_weight, iommu_debugfs_weight_get, NULL, "%llu\n");
50691602aaSAlexey Kardashevskiy
iommu_debugfs_add(struct iommu_table * tbl)51691602aaSAlexey Kardashevskiy static void iommu_debugfs_add(struct iommu_table *tbl)
52691602aaSAlexey Kardashevskiy {
53691602aaSAlexey Kardashevskiy char name[10];
54691602aaSAlexey Kardashevskiy struct dentry *liobn_entry;
55691602aaSAlexey Kardashevskiy
56691602aaSAlexey Kardashevskiy sprintf(name, "%08lx", tbl->it_index);
57691602aaSAlexey Kardashevskiy liobn_entry = debugfs_create_dir(name, iommu_debugfs_dir);
58691602aaSAlexey Kardashevskiy
59691602aaSAlexey Kardashevskiy debugfs_create_file_unsafe("weight", 0400, liobn_entry, tbl, &iommu_debugfs_fops_weight);
60691602aaSAlexey Kardashevskiy debugfs_create_ulong("it_size", 0400, liobn_entry, &tbl->it_size);
61691602aaSAlexey Kardashevskiy debugfs_create_ulong("it_page_shift", 0400, liobn_entry, &tbl->it_page_shift);
62691602aaSAlexey Kardashevskiy debugfs_create_ulong("it_reserved_start", 0400, liobn_entry, &tbl->it_reserved_start);
63691602aaSAlexey Kardashevskiy debugfs_create_ulong("it_reserved_end", 0400, liobn_entry, &tbl->it_reserved_end);
64691602aaSAlexey Kardashevskiy debugfs_create_ulong("it_indirect_levels", 0400, liobn_entry, &tbl->it_indirect_levels);
65691602aaSAlexey Kardashevskiy debugfs_create_ulong("it_level_size", 0400, liobn_entry, &tbl->it_level_size);
66691602aaSAlexey Kardashevskiy }
67691602aaSAlexey Kardashevskiy
iommu_debugfs_del(struct iommu_table * tbl)68691602aaSAlexey Kardashevskiy static void iommu_debugfs_del(struct iommu_table *tbl)
69691602aaSAlexey Kardashevskiy {
70691602aaSAlexey Kardashevskiy char name[10];
71691602aaSAlexey Kardashevskiy
72691602aaSAlexey Kardashevskiy sprintf(name, "%08lx", tbl->it_index);
73b5050639SGreg Kroah-Hartman debugfs_lookup_and_remove(name, iommu_debugfs_dir);
74691602aaSAlexey Kardashevskiy }
75691602aaSAlexey Kardashevskiy #else
iommu_debugfs_add(struct iommu_table * tbl)76691602aaSAlexey Kardashevskiy static void iommu_debugfs_add(struct iommu_table *tbl){}
iommu_debugfs_del(struct iommu_table * tbl)77691602aaSAlexey Kardashevskiy static void iommu_debugfs_del(struct iommu_table *tbl){}
78691602aaSAlexey Kardashevskiy #endif
79691602aaSAlexey Kardashevskiy
80191aee58SFUJITA Tomonori static int novmerge;
8156997559SJake Moilanen
826490c490SRobert Jennings static void __iommu_free(struct iommu_table *, dma_addr_t, unsigned int);
836490c490SRobert Jennings
setup_iommu(char * str)847568cb4eSPaul Mackerras static int __init setup_iommu(char *str)
857568cb4eSPaul Mackerras {
867568cb4eSPaul Mackerras if (!strcmp(str, "novmerge"))
877568cb4eSPaul Mackerras novmerge = 1;
887568cb4eSPaul Mackerras else if (!strcmp(str, "vmerge"))
897568cb4eSPaul Mackerras novmerge = 0;
907568cb4eSPaul Mackerras return 1;
917568cb4eSPaul Mackerras }
927568cb4eSPaul Mackerras
937568cb4eSPaul Mackerras __setup("iommu=", setup_iommu);
947568cb4eSPaul Mackerras
95b4c3a872SAnton Blanchard static DEFINE_PER_CPU(unsigned int, iommu_pool_hash);
96b4c3a872SAnton Blanchard
97b4c3a872SAnton Blanchard /*
98b4c3a872SAnton Blanchard * We precalculate the hash to avoid doing it on every allocation.
99b4c3a872SAnton Blanchard *
100b4c3a872SAnton Blanchard * The hash is important to spread CPUs across all the pools. For example,
101b4c3a872SAnton Blanchard * on a POWER7 with 4 way SMT we want interrupts on the primary threads and
102b4c3a872SAnton Blanchard * with 4 pools all primary threads would map to the same pool.
103b4c3a872SAnton Blanchard */
setup_iommu_pool_hash(void)104b4c3a872SAnton Blanchard static int __init setup_iommu_pool_hash(void)
105b4c3a872SAnton Blanchard {
106b4c3a872SAnton Blanchard unsigned int i;
107b4c3a872SAnton Blanchard
108b4c3a872SAnton Blanchard for_each_possible_cpu(i)
109b4c3a872SAnton Blanchard per_cpu(iommu_pool_hash, i) = hash_32(i, IOMMU_POOL_HASHBITS);
110b4c3a872SAnton Blanchard
111b4c3a872SAnton Blanchard return 0;
112b4c3a872SAnton Blanchard }
113b4c3a872SAnton Blanchard subsys_initcall(setup_iommu_pool_hash);
114b4c3a872SAnton Blanchard
115d6b9a81bSAnton Blanchard #ifdef CONFIG_FAIL_IOMMU
116d6b9a81bSAnton Blanchard
117d6b9a81bSAnton Blanchard static DECLARE_FAULT_ATTR(fail_iommu);
118d6b9a81bSAnton Blanchard
setup_fail_iommu(char * str)119d6b9a81bSAnton Blanchard static int __init setup_fail_iommu(char *str)
120d6b9a81bSAnton Blanchard {
121d6b9a81bSAnton Blanchard return setup_fault_attr(&fail_iommu, str);
122d6b9a81bSAnton Blanchard }
123d6b9a81bSAnton Blanchard __setup("fail_iommu=", setup_fail_iommu);
124d6b9a81bSAnton Blanchard
should_fail_iommu(struct device * dev)125d6b9a81bSAnton Blanchard static bool should_fail_iommu(struct device *dev)
126d6b9a81bSAnton Blanchard {
127d6b9a81bSAnton Blanchard return dev->archdata.fail_iommu && should_fail(&fail_iommu, 1);
128d6b9a81bSAnton Blanchard }
129d6b9a81bSAnton Blanchard
fail_iommu_debugfs(void)130d6b9a81bSAnton Blanchard static int __init fail_iommu_debugfs(void)
131d6b9a81bSAnton Blanchard {
132d6b9a81bSAnton Blanchard struct dentry *dir = fault_create_debugfs_attr("fail_iommu",
133d6b9a81bSAnton Blanchard NULL, &fail_iommu);
134d6b9a81bSAnton Blanchard
1358c6ffba0SRusty Russell return PTR_ERR_OR_ZERO(dir);
136d6b9a81bSAnton Blanchard }
137d6b9a81bSAnton Blanchard late_initcall(fail_iommu_debugfs);
138d6b9a81bSAnton Blanchard
fail_iommu_show(struct device * dev,struct device_attribute * attr,char * buf)139d6b9a81bSAnton Blanchard static ssize_t fail_iommu_show(struct device *dev,
140d6b9a81bSAnton Blanchard struct device_attribute *attr, char *buf)
141d6b9a81bSAnton Blanchard {
142d6b9a81bSAnton Blanchard return sprintf(buf, "%d\n", dev->archdata.fail_iommu);
143d6b9a81bSAnton Blanchard }
144d6b9a81bSAnton Blanchard
fail_iommu_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)145d6b9a81bSAnton Blanchard static ssize_t fail_iommu_store(struct device *dev,
146d6b9a81bSAnton Blanchard struct device_attribute *attr, const char *buf,
147d6b9a81bSAnton Blanchard size_t count)
148d6b9a81bSAnton Blanchard {
149d6b9a81bSAnton Blanchard int i;
150d6b9a81bSAnton Blanchard
151d6b9a81bSAnton Blanchard if (count > 0 && sscanf(buf, "%d", &i) > 0)
152d6b9a81bSAnton Blanchard dev->archdata.fail_iommu = (i == 0) ? 0 : 1;
153d6b9a81bSAnton Blanchard
154d6b9a81bSAnton Blanchard return count;
155d6b9a81bSAnton Blanchard }
156d6b9a81bSAnton Blanchard
1578a7aef2cSJulia Lawall static DEVICE_ATTR_RW(fail_iommu);
158d6b9a81bSAnton Blanchard
fail_iommu_bus_notify(struct notifier_block * nb,unsigned long action,void * data)159d6b9a81bSAnton Blanchard static int fail_iommu_bus_notify(struct notifier_block *nb,
160d6b9a81bSAnton Blanchard unsigned long action, void *data)
161d6b9a81bSAnton Blanchard {
162d6b9a81bSAnton Blanchard struct device *dev = data;
163d6b9a81bSAnton Blanchard
164d6b9a81bSAnton Blanchard if (action == BUS_NOTIFY_ADD_DEVICE) {
165d6b9a81bSAnton Blanchard if (device_create_file(dev, &dev_attr_fail_iommu))
166d6b9a81bSAnton Blanchard pr_warn("Unable to create IOMMU fault injection sysfs "
167d6b9a81bSAnton Blanchard "entries\n");
168d6b9a81bSAnton Blanchard } else if (action == BUS_NOTIFY_DEL_DEVICE) {
169d6b9a81bSAnton Blanchard device_remove_file(dev, &dev_attr_fail_iommu);
170d6b9a81bSAnton Blanchard }
171d6b9a81bSAnton Blanchard
172d6b9a81bSAnton Blanchard return 0;
173d6b9a81bSAnton Blanchard }
174d6b9a81bSAnton Blanchard
175c37b6908SRussell Currey /*
176c37b6908SRussell Currey * PCI and VIO buses need separate notifier_block structs, since they're linked
177c37b6908SRussell Currey * list nodes. Sharing a notifier_block would mean that any notifiers later
178c37b6908SRussell Currey * registered for PCI buses would also get called by VIO buses and vice versa.
179c37b6908SRussell Currey */
180c37b6908SRussell Currey static struct notifier_block fail_iommu_pci_bus_notifier = {
181d6b9a81bSAnton Blanchard .notifier_call = fail_iommu_bus_notify
182d6b9a81bSAnton Blanchard };
183d6b9a81bSAnton Blanchard
184c37b6908SRussell Currey #ifdef CONFIG_IBMVIO
185c37b6908SRussell Currey static struct notifier_block fail_iommu_vio_bus_notifier = {
186c37b6908SRussell Currey .notifier_call = fail_iommu_bus_notify
187c37b6908SRussell Currey };
188c37b6908SRussell Currey #endif
189c37b6908SRussell Currey
fail_iommu_setup(void)190d6b9a81bSAnton Blanchard static int __init fail_iommu_setup(void)
191d6b9a81bSAnton Blanchard {
192d6b9a81bSAnton Blanchard #ifdef CONFIG_PCI
193c37b6908SRussell Currey bus_register_notifier(&pci_bus_type, &fail_iommu_pci_bus_notifier);
194d6b9a81bSAnton Blanchard #endif
195d6b9a81bSAnton Blanchard #ifdef CONFIG_IBMVIO
196c37b6908SRussell Currey bus_register_notifier(&vio_bus_type, &fail_iommu_vio_bus_notifier);
197d6b9a81bSAnton Blanchard #endif
198d6b9a81bSAnton Blanchard
199d6b9a81bSAnton Blanchard return 0;
200d6b9a81bSAnton Blanchard }
201d6b9a81bSAnton Blanchard /*
202d6b9a81bSAnton Blanchard * Must execute after PCI and VIO subsystem have initialised but before
203d6b9a81bSAnton Blanchard * devices are probed.
204d6b9a81bSAnton Blanchard */
205d6b9a81bSAnton Blanchard arch_initcall(fail_iommu_setup);
206d6b9a81bSAnton Blanchard #else
should_fail_iommu(struct device * dev)207d6b9a81bSAnton Blanchard static inline bool should_fail_iommu(struct device *dev)
208d6b9a81bSAnton Blanchard {
209d6b9a81bSAnton Blanchard return false;
210d6b9a81bSAnton Blanchard }
211d6b9a81bSAnton Blanchard #endif
212d6b9a81bSAnton Blanchard
iommu_range_alloc(struct device * dev,struct iommu_table * tbl,unsigned long npages,unsigned long * handle,unsigned long mask,unsigned int align_order)213fb3475e9SFUJITA Tomonori static unsigned long iommu_range_alloc(struct device *dev,
214fb3475e9SFUJITA Tomonori struct iommu_table *tbl,
2157568cb4eSPaul Mackerras unsigned long npages,
2167568cb4eSPaul Mackerras unsigned long *handle,
2177daa411bSOlof Johansson unsigned long mask,
2187568cb4eSPaul Mackerras unsigned int align_order)
2197568cb4eSPaul Mackerras {
220fb3475e9SFUJITA Tomonori unsigned long n, end, start;
2217568cb4eSPaul Mackerras unsigned long limit;
2227568cb4eSPaul Mackerras int largealloc = npages > 15;
2237568cb4eSPaul Mackerras int pass = 0;
2247568cb4eSPaul Mackerras unsigned long align_mask;
225d3622137SAnton Blanchard unsigned long flags;
226b4c3a872SAnton Blanchard unsigned int pool_nr;
227b4c3a872SAnton Blanchard struct iommu_pool *pool;
2287568cb4eSPaul Mackerras
22963b85621SMichael Ellerman align_mask = (1ull << align_order) - 1;
2307568cb4eSPaul Mackerras
2317568cb4eSPaul Mackerras /* This allocator was derived from x86_64's bit string search */
2327568cb4eSPaul Mackerras
2337568cb4eSPaul Mackerras /* Sanity check */
23413a2eea1SNick Piggin if (unlikely(npages == 0)) {
2357568cb4eSPaul Mackerras if (printk_ratelimit())
2367568cb4eSPaul Mackerras WARN_ON(1);
237d11e3d3dSChristoph Hellwig return DMA_MAPPING_ERROR;
2387568cb4eSPaul Mackerras }
2397568cb4eSPaul Mackerras
240d6b9a81bSAnton Blanchard if (should_fail_iommu(dev))
241d11e3d3dSChristoph Hellwig return DMA_MAPPING_ERROR;
242d6b9a81bSAnton Blanchard
243b4c3a872SAnton Blanchard /*
244b4c3a872SAnton Blanchard * We don't need to disable preemption here because any CPU can
245b4c3a872SAnton Blanchard * safely use any IOMMU pool.
246b4c3a872SAnton Blanchard */
24775f327c6SVictor Aoqui pool_nr = raw_cpu_read(iommu_pool_hash) & (tbl->nr_pools - 1);
248d3622137SAnton Blanchard
249b4c3a872SAnton Blanchard if (largealloc)
250b4c3a872SAnton Blanchard pool = &(tbl->large_pool);
251b4c3a872SAnton Blanchard else
252b4c3a872SAnton Blanchard pool = &(tbl->pools[pool_nr]);
253b4c3a872SAnton Blanchard
254b4c3a872SAnton Blanchard spin_lock_irqsave(&(pool->lock), flags);
255b4c3a872SAnton Blanchard
256b4c3a872SAnton Blanchard again:
257d900bd73SAnton Blanchard if ((pass == 0) && handle && *handle &&
258d900bd73SAnton Blanchard (*handle >= pool->start) && (*handle < pool->end))
2597568cb4eSPaul Mackerras start = *handle;
2607568cb4eSPaul Mackerras else
261b4c3a872SAnton Blanchard start = pool->hint;
2627568cb4eSPaul Mackerras
263b4c3a872SAnton Blanchard limit = pool->end;
2647568cb4eSPaul Mackerras
2657568cb4eSPaul Mackerras /* The case below can happen if we have a small segment appended
2667568cb4eSPaul Mackerras * to a large, or when the previous alloc was at the very end of
2677568cb4eSPaul Mackerras * the available space. If so, go back to the initial start.
2687568cb4eSPaul Mackerras */
2697568cb4eSPaul Mackerras if (start >= limit)
270b4c3a872SAnton Blanchard start = pool->start;
2717568cb4eSPaul Mackerras
2727daa411bSOlof Johansson if (limit + tbl->it_offset > mask) {
2737daa411bSOlof Johansson limit = mask - tbl->it_offset + 1;
2747daa411bSOlof Johansson /* If we're constrained on address range, first try
2757daa411bSOlof Johansson * at the masked hint to avoid O(n) search complexity,
276b4c3a872SAnton Blanchard * but on second pass, start at 0 in pool 0.
2777daa411bSOlof Johansson */
278b4c3a872SAnton Blanchard if ((start & mask) >= limit || pass > 0) {
279d900bd73SAnton Blanchard spin_unlock(&(pool->lock));
280b4c3a872SAnton Blanchard pool = &(tbl->pools[0]);
281d900bd73SAnton Blanchard spin_lock(&(pool->lock));
282b4c3a872SAnton Blanchard start = pool->start;
283b4c3a872SAnton Blanchard } else {
2847daa411bSOlof Johansson start &= mask;
2857daa411bSOlof Johansson }
286b4c3a872SAnton Blanchard }
2877daa411bSOlof Johansson
288d0847757SAlistair Popple n = iommu_area_alloc(tbl->it_map, limit, start, npages, tbl->it_offset,
2891e9d90dbSNicolin Chen dma_get_seg_boundary_nr_pages(dev, tbl->it_page_shift),
2901e9d90dbSNicolin Chen align_mask);
291fb3475e9SFUJITA Tomonori if (n == -1) {
292b4c3a872SAnton Blanchard if (likely(pass == 0)) {
293b4c3a872SAnton Blanchard /* First try the pool from the start */
294b4c3a872SAnton Blanchard pool->hint = pool->start;
2957568cb4eSPaul Mackerras pass++;
2967568cb4eSPaul Mackerras goto again;
297b4c3a872SAnton Blanchard
298b4c3a872SAnton Blanchard } else if (pass <= tbl->nr_pools) {
299b4c3a872SAnton Blanchard /* Now try scanning all the other pools */
300b4c3a872SAnton Blanchard spin_unlock(&(pool->lock));
301b4c3a872SAnton Blanchard pool_nr = (pool_nr + 1) & (tbl->nr_pools - 1);
302b4c3a872SAnton Blanchard pool = &tbl->pools[pool_nr];
303b4c3a872SAnton Blanchard spin_lock(&(pool->lock));
304b4c3a872SAnton Blanchard pool->hint = pool->start;
305b4c3a872SAnton Blanchard pass++;
306b4c3a872SAnton Blanchard goto again;
307b4c3a872SAnton Blanchard
308fc5590fdSLeonardo Bras } else if (pass == tbl->nr_pools + 1) {
309fc5590fdSLeonardo Bras /* Last resort: try largepool */
310fc5590fdSLeonardo Bras spin_unlock(&pool->lock);
311fc5590fdSLeonardo Bras pool = &tbl->large_pool;
312fc5590fdSLeonardo Bras spin_lock(&pool->lock);
313fc5590fdSLeonardo Bras pool->hint = pool->start;
314fc5590fdSLeonardo Bras pass++;
315fc5590fdSLeonardo Bras goto again;
316fc5590fdSLeonardo Bras
3177568cb4eSPaul Mackerras } else {
318b4c3a872SAnton Blanchard /* Give up */
319b4c3a872SAnton Blanchard spin_unlock_irqrestore(&(pool->lock), flags);
320d11e3d3dSChristoph Hellwig return DMA_MAPPING_ERROR;
3217568cb4eSPaul Mackerras }
3227568cb4eSPaul Mackerras }
3237568cb4eSPaul Mackerras
324fb3475e9SFUJITA Tomonori end = n + npages;
3257568cb4eSPaul Mackerras
3267568cb4eSPaul Mackerras /* Bump the hint to a new block for small allocs. */
3277568cb4eSPaul Mackerras if (largealloc) {
3287568cb4eSPaul Mackerras /* Don't bump to new block to avoid fragmentation */
329b4c3a872SAnton Blanchard pool->hint = end;
3307568cb4eSPaul Mackerras } else {
3317568cb4eSPaul Mackerras /* Overflow will be taken care of at the next allocation */
332b4c3a872SAnton Blanchard pool->hint = (end + tbl->it_blocksize - 1) &
3337568cb4eSPaul Mackerras ~(tbl->it_blocksize - 1);
3347568cb4eSPaul Mackerras }
3357568cb4eSPaul Mackerras
3367568cb4eSPaul Mackerras /* Update handle for SG allocations */
3377568cb4eSPaul Mackerras if (handle)
3387568cb4eSPaul Mackerras *handle = end;
3397568cb4eSPaul Mackerras
340b4c3a872SAnton Blanchard spin_unlock_irqrestore(&(pool->lock), flags);
341b4c3a872SAnton Blanchard
3427568cb4eSPaul Mackerras return n;
3437568cb4eSPaul Mackerras }
3447568cb4eSPaul Mackerras
iommu_alloc(struct device * dev,struct iommu_table * tbl,void * page,unsigned int npages,enum dma_data_direction direction,unsigned long mask,unsigned int align_order,unsigned long attrs)345fb3475e9SFUJITA Tomonori static dma_addr_t iommu_alloc(struct device *dev, struct iommu_table *tbl,
346fb3475e9SFUJITA Tomonori void *page, unsigned int npages,
347fb3475e9SFUJITA Tomonori enum dma_data_direction direction,
3484f3dd8a0SMark Nelson unsigned long mask, unsigned int align_order,
34900085f1eSKrzysztof Kozlowski unsigned long attrs)
3507568cb4eSPaul Mackerras {
351d3622137SAnton Blanchard unsigned long entry;
352d11e3d3dSChristoph Hellwig dma_addr_t ret = DMA_MAPPING_ERROR;
3536490c490SRobert Jennings int build_fail;
3547568cb4eSPaul Mackerras
355fb3475e9SFUJITA Tomonori entry = iommu_range_alloc(dev, tbl, npages, NULL, mask, align_order);
3560e4bc95dSAnton Blanchard
357d11e3d3dSChristoph Hellwig if (unlikely(entry == DMA_MAPPING_ERROR))
358d11e3d3dSChristoph Hellwig return DMA_MAPPING_ERROR;
3597568cb4eSPaul Mackerras
3607568cb4eSPaul Mackerras entry += tbl->it_offset; /* Offset into real TCE table */
361d0847757SAlistair Popple ret = entry << tbl->it_page_shift; /* Set the return dma address */
3627568cb4eSPaul Mackerras
3637568cb4eSPaul Mackerras /* Put the TCEs in the HW table */
364da004c36SAlexey Kardashevskiy build_fail = tbl->it_ops->set(tbl, entry, npages,
365d0847757SAlistair Popple (unsigned long)page &
366d0847757SAlistair Popple IOMMU_PAGE_MASK(tbl), direction, attrs);
3677568cb4eSPaul Mackerras
368da004c36SAlexey Kardashevskiy /* tbl->it_ops->set() only returns non-zero for transient errors.
3696490c490SRobert Jennings * Clean up the table bitmap in this case and return
370d11e3d3dSChristoph Hellwig * DMA_MAPPING_ERROR. For all other errors the functionality is
3716490c490SRobert Jennings * not altered.
3726490c490SRobert Jennings */
3736490c490SRobert Jennings if (unlikely(build_fail)) {
3746490c490SRobert Jennings __iommu_free(tbl, ret, npages);
375d11e3d3dSChristoph Hellwig return DMA_MAPPING_ERROR;
3766490c490SRobert Jennings }
3777568cb4eSPaul Mackerras
3787568cb4eSPaul Mackerras /* Flush/invalidate TLB caches if necessary */
379da004c36SAlexey Kardashevskiy if (tbl->it_ops->flush)
380da004c36SAlexey Kardashevskiy tbl->it_ops->flush(tbl);
3817568cb4eSPaul Mackerras
3827568cb4eSPaul Mackerras /* Make sure updates are seen by hardware */
3837568cb4eSPaul Mackerras mb();
3847568cb4eSPaul Mackerras
3857568cb4eSPaul Mackerras return ret;
3867568cb4eSPaul Mackerras }
3877568cb4eSPaul Mackerras
iommu_free_check(struct iommu_table * tbl,dma_addr_t dma_addr,unsigned int npages)38867ca1415SAnton Blanchard static bool iommu_free_check(struct iommu_table *tbl, dma_addr_t dma_addr,
3897568cb4eSPaul Mackerras unsigned int npages)
3907568cb4eSPaul Mackerras {
3917568cb4eSPaul Mackerras unsigned long entry, free_entry;
3927568cb4eSPaul Mackerras
393d0847757SAlistair Popple entry = dma_addr >> tbl->it_page_shift;
3947568cb4eSPaul Mackerras free_entry = entry - tbl->it_offset;
3957568cb4eSPaul Mackerras
3967568cb4eSPaul Mackerras if (((free_entry + npages) > tbl->it_size) ||
3977568cb4eSPaul Mackerras (entry < tbl->it_offset)) {
3987568cb4eSPaul Mackerras if (printk_ratelimit()) {
3997568cb4eSPaul Mackerras printk(KERN_INFO "iommu_free: invalid entry\n");
4007568cb4eSPaul Mackerras printk(KERN_INFO "\tentry = 0x%lx\n", entry);
401fe333321SIngo Molnar printk(KERN_INFO "\tdma_addr = 0x%llx\n", (u64)dma_addr);
402fe333321SIngo Molnar printk(KERN_INFO "\tTable = 0x%llx\n", (u64)tbl);
403fe333321SIngo Molnar printk(KERN_INFO "\tbus# = 0x%llx\n", (u64)tbl->it_busno);
404fe333321SIngo Molnar printk(KERN_INFO "\tsize = 0x%llx\n", (u64)tbl->it_size);
405fe333321SIngo Molnar printk(KERN_INFO "\tstartOff = 0x%llx\n", (u64)tbl->it_offset);
406fe333321SIngo Molnar printk(KERN_INFO "\tindex = 0x%llx\n", (u64)tbl->it_index);
4077568cb4eSPaul Mackerras WARN_ON(1);
4087568cb4eSPaul Mackerras }
40967ca1415SAnton Blanchard
41067ca1415SAnton Blanchard return false;
4117568cb4eSPaul Mackerras }
4127568cb4eSPaul Mackerras
41367ca1415SAnton Blanchard return true;
41467ca1415SAnton Blanchard }
41567ca1415SAnton Blanchard
get_pool(struct iommu_table * tbl,unsigned long entry)416b4c3a872SAnton Blanchard static struct iommu_pool *get_pool(struct iommu_table *tbl,
417b4c3a872SAnton Blanchard unsigned long entry)
418b4c3a872SAnton Blanchard {
419b4c3a872SAnton Blanchard struct iommu_pool *p;
420b4c3a872SAnton Blanchard unsigned long largepool_start = tbl->large_pool.start;
421b4c3a872SAnton Blanchard
422b4c3a872SAnton Blanchard /* The large pool is the last pool at the top of the table */
423b4c3a872SAnton Blanchard if (entry >= largepool_start) {
424b4c3a872SAnton Blanchard p = &tbl->large_pool;
425b4c3a872SAnton Blanchard } else {
426b4c3a872SAnton Blanchard unsigned int pool_nr = entry / tbl->poolsize;
427b4c3a872SAnton Blanchard
428b4c3a872SAnton Blanchard BUG_ON(pool_nr > tbl->nr_pools);
429b4c3a872SAnton Blanchard p = &tbl->pools[pool_nr];
430b4c3a872SAnton Blanchard }
431b4c3a872SAnton Blanchard
432b4c3a872SAnton Blanchard return p;
433b4c3a872SAnton Blanchard }
434b4c3a872SAnton Blanchard
__iommu_free(struct iommu_table * tbl,dma_addr_t dma_addr,unsigned int npages)43567ca1415SAnton Blanchard static void __iommu_free(struct iommu_table *tbl, dma_addr_t dma_addr,
43667ca1415SAnton Blanchard unsigned int npages)
43767ca1415SAnton Blanchard {
43867ca1415SAnton Blanchard unsigned long entry, free_entry;
43967ca1415SAnton Blanchard unsigned long flags;
440b4c3a872SAnton Blanchard struct iommu_pool *pool;
44167ca1415SAnton Blanchard
442d0847757SAlistair Popple entry = dma_addr >> tbl->it_page_shift;
44367ca1415SAnton Blanchard free_entry = entry - tbl->it_offset;
44467ca1415SAnton Blanchard
445b4c3a872SAnton Blanchard pool = get_pool(tbl, free_entry);
446b4c3a872SAnton Blanchard
44767ca1415SAnton Blanchard if (!iommu_free_check(tbl, dma_addr, npages))
44867ca1415SAnton Blanchard return;
44967ca1415SAnton Blanchard
450da004c36SAlexey Kardashevskiy tbl->it_ops->clear(tbl, entry, npages);
45167ca1415SAnton Blanchard
452b4c3a872SAnton Blanchard spin_lock_irqsave(&(pool->lock), flags);
45367ca1415SAnton Blanchard bitmap_clear(tbl->it_map, free_entry, npages);
454b4c3a872SAnton Blanchard spin_unlock_irqrestore(&(pool->lock), flags);
45567ca1415SAnton Blanchard }
45667ca1415SAnton Blanchard
iommu_free(struct iommu_table * tbl,dma_addr_t dma_addr,unsigned int npages)4577568cb4eSPaul Mackerras static void iommu_free(struct iommu_table *tbl, dma_addr_t dma_addr,
4587568cb4eSPaul Mackerras unsigned int npages)
4597568cb4eSPaul Mackerras {
4607568cb4eSPaul Mackerras __iommu_free(tbl, dma_addr, npages);
4617568cb4eSPaul Mackerras
4627568cb4eSPaul Mackerras /* Make sure TLB cache is flushed if the HW needs it. We do
4637568cb4eSPaul Mackerras * not do an mb() here on purpose, it is not needed on any of
4647568cb4eSPaul Mackerras * the current platforms.
4657568cb4eSPaul Mackerras */
466da004c36SAlexey Kardashevskiy if (tbl->it_ops->flush)
467da004c36SAlexey Kardashevskiy tbl->it_ops->flush(tbl);
4687568cb4eSPaul Mackerras }
4697568cb4eSPaul Mackerras
ppc_iommu_map_sg(struct device * dev,struct iommu_table * tbl,struct scatterlist * sglist,int nelems,unsigned long mask,enum dma_data_direction direction,unsigned long attrs)4700690cbd2SJoerg Roedel int ppc_iommu_map_sg(struct device *dev, struct iommu_table *tbl,
471c8692362SMark Nelson struct scatterlist *sglist, int nelems,
4723affedc4SMark Nelson unsigned long mask, enum dma_data_direction direction,
47300085f1eSKrzysztof Kozlowski unsigned long attrs)
4747568cb4eSPaul Mackerras {
4757568cb4eSPaul Mackerras dma_addr_t dma_next = 0, dma_addr;
4767568cb4eSPaul Mackerras struct scatterlist *s, *outs, *segstart;
4776490c490SRobert Jennings int outcount, incount, i, build_fail = 0;
478d262c32aSBenjamin Herrenschmidt unsigned int align;
4797568cb4eSPaul Mackerras unsigned long handle;
480740c3ce6SFUJITA Tomonori unsigned int max_seg_size;
4817568cb4eSPaul Mackerras
4827568cb4eSPaul Mackerras BUG_ON(direction == DMA_NONE);
4837568cb4eSPaul Mackerras
4847568cb4eSPaul Mackerras if ((nelems == 0) || !tbl)
485c4e0e892SMartin Oliveira return -EINVAL;
4867568cb4eSPaul Mackerras
4877568cb4eSPaul Mackerras outs = s = segstart = &sglist[0];
4887568cb4eSPaul Mackerras outcount = 1;
4897568cb4eSPaul Mackerras incount = nelems;
4907568cb4eSPaul Mackerras handle = 0;
4917568cb4eSPaul Mackerras
4927568cb4eSPaul Mackerras /* Init first segment length for backout at failure */
4937568cb4eSPaul Mackerras outs->dma_length = 0;
4947568cb4eSPaul Mackerras
4955d2efba6SLinas Vepstas DBG("sg mapping %d elements:\n", nelems);
4967568cb4eSPaul Mackerras
497740c3ce6SFUJITA Tomonori max_seg_size = dma_get_max_seg_size(dev);
49878bdc310SJens Axboe for_each_sg(sglist, s, nelems, i) {
4997568cb4eSPaul Mackerras unsigned long vaddr, npages, entry, slen;
5007568cb4eSPaul Mackerras
5017568cb4eSPaul Mackerras slen = s->length;
5027568cb4eSPaul Mackerras /* Sanity check */
5037568cb4eSPaul Mackerras if (slen == 0) {
5047568cb4eSPaul Mackerras dma_next = 0;
5057568cb4eSPaul Mackerras continue;
5067568cb4eSPaul Mackerras }
5077568cb4eSPaul Mackerras /* Allocate iommu entries for that segment */
50858b053e4SJens Axboe vaddr = (unsigned long) sg_virt(s);
509d0847757SAlistair Popple npages = iommu_num_pages(vaddr, slen, IOMMU_PAGE_SIZE(tbl));
510d262c32aSBenjamin Herrenschmidt align = 0;
511d0847757SAlistair Popple if (tbl->it_page_shift < PAGE_SHIFT && slen >= PAGE_SIZE &&
512d262c32aSBenjamin Herrenschmidt (vaddr & ~PAGE_MASK) == 0)
513d0847757SAlistair Popple align = PAGE_SHIFT - tbl->it_page_shift;
514fb3475e9SFUJITA Tomonori entry = iommu_range_alloc(dev, tbl, npages, &handle,
515d0847757SAlistair Popple mask >> tbl->it_page_shift, align);
5167568cb4eSPaul Mackerras
5177568cb4eSPaul Mackerras DBG(" - vaddr: %lx, size: %lx\n", vaddr, slen);
5187568cb4eSPaul Mackerras
5197568cb4eSPaul Mackerras /* Handle failure */
520d11e3d3dSChristoph Hellwig if (unlikely(entry == DMA_MAPPING_ERROR)) {
521af8a2498SMauricio Faria de Oliveira if (!(attrs & DMA_ATTR_NO_WARN) &&
522af8a2498SMauricio Faria de Oliveira printk_ratelimit())
5234dfa9c47SAnton Blanchard dev_info(dev, "iommu_alloc failed, tbl %p "
5244dfa9c47SAnton Blanchard "vaddr %lx npages %lu\n", tbl, vaddr,
5254dfa9c47SAnton Blanchard npages);
5267568cb4eSPaul Mackerras goto failure;
5277568cb4eSPaul Mackerras }
5287568cb4eSPaul Mackerras
5297568cb4eSPaul Mackerras /* Convert entry to a dma_addr_t */
5307568cb4eSPaul Mackerras entry += tbl->it_offset;
531d0847757SAlistair Popple dma_addr = entry << tbl->it_page_shift;
532096339abSGaurav Batra dma_addr |= (vaddr & ~IOMMU_PAGE_MASK(tbl));
5337568cb4eSPaul Mackerras
5345d2efba6SLinas Vepstas DBG(" - %lu pages, entry: %lx, dma_addr: %lx\n",
5357568cb4eSPaul Mackerras npages, entry, dma_addr);
5367568cb4eSPaul Mackerras
5377568cb4eSPaul Mackerras /* Insert into HW table */
538da004c36SAlexey Kardashevskiy build_fail = tbl->it_ops->set(tbl, entry, npages,
539d0847757SAlistair Popple vaddr & IOMMU_PAGE_MASK(tbl),
5404f3dd8a0SMark Nelson direction, attrs);
5416490c490SRobert Jennings if(unlikely(build_fail))
5426490c490SRobert Jennings goto failure;
5437568cb4eSPaul Mackerras
5447568cb4eSPaul Mackerras /* If we are in an open segment, try merging */
5457568cb4eSPaul Mackerras if (segstart != s) {
5467568cb4eSPaul Mackerras DBG(" - trying merge...\n");
5477568cb4eSPaul Mackerras /* We cannot merge if:
5487568cb4eSPaul Mackerras * - allocated dma_addr isn't contiguous to previous allocation
5497568cb4eSPaul Mackerras */
550740c3ce6SFUJITA Tomonori if (novmerge || (dma_addr != dma_next) ||
551740c3ce6SFUJITA Tomonori (outs->dma_length + s->length > max_seg_size)) {
5527568cb4eSPaul Mackerras /* Can't merge: create a new segment */
5537568cb4eSPaul Mackerras segstart = s;
55478bdc310SJens Axboe outcount++;
55578bdc310SJens Axboe outs = sg_next(outs);
5567568cb4eSPaul Mackerras DBG(" can't merge, new segment.\n");
5577568cb4eSPaul Mackerras } else {
5587568cb4eSPaul Mackerras outs->dma_length += s->length;
5595d2efba6SLinas Vepstas DBG(" merged, new len: %ux\n", outs->dma_length);
5607568cb4eSPaul Mackerras }
5617568cb4eSPaul Mackerras }
5627568cb4eSPaul Mackerras
5637568cb4eSPaul Mackerras if (segstart == s) {
5647568cb4eSPaul Mackerras /* This is a new segment, fill entries */
5657568cb4eSPaul Mackerras DBG(" - filling new segment.\n");
5667568cb4eSPaul Mackerras outs->dma_address = dma_addr;
5677568cb4eSPaul Mackerras outs->dma_length = slen;
5687568cb4eSPaul Mackerras }
5697568cb4eSPaul Mackerras
5707568cb4eSPaul Mackerras /* Calculate next page pointer for contiguous check */
5717568cb4eSPaul Mackerras dma_next = dma_addr + slen;
5727568cb4eSPaul Mackerras
5737568cb4eSPaul Mackerras DBG(" - dma next is: %lx\n", dma_next);
5747568cb4eSPaul Mackerras }
5757568cb4eSPaul Mackerras
5767568cb4eSPaul Mackerras /* Flush/invalidate TLB caches if necessary */
577da004c36SAlexey Kardashevskiy if (tbl->it_ops->flush)
578da004c36SAlexey Kardashevskiy tbl->it_ops->flush(tbl);
5797568cb4eSPaul Mackerras
5807568cb4eSPaul Mackerras DBG("mapped %d elements:\n", outcount);
5817568cb4eSPaul Mackerras
5820690cbd2SJoerg Roedel /* For the sake of ppc_iommu_unmap_sg, we clear out the length in the
5837568cb4eSPaul Mackerras * next entry of the sglist if we didn't fill the list completely
5847568cb4eSPaul Mackerras */
5857568cb4eSPaul Mackerras if (outcount < incount) {
58678bdc310SJens Axboe outs = sg_next(outs);
5877568cb4eSPaul Mackerras outs->dma_length = 0;
5887568cb4eSPaul Mackerras }
589a958a264SJake Moilanen
590a958a264SJake Moilanen /* Make sure updates are seen by hardware */
591a958a264SJake Moilanen mb();
592a958a264SJake Moilanen
5937568cb4eSPaul Mackerras return outcount;
5947568cb4eSPaul Mackerras
5957568cb4eSPaul Mackerras failure:
59678bdc310SJens Axboe for_each_sg(sglist, s, nelems, i) {
5977568cb4eSPaul Mackerras if (s->dma_length != 0) {
5987568cb4eSPaul Mackerras unsigned long vaddr, npages;
5997568cb4eSPaul Mackerras
600d0847757SAlistair Popple vaddr = s->dma_address & IOMMU_PAGE_MASK(tbl);
6012994a3b2SJoerg Roedel npages = iommu_num_pages(s->dma_address, s->dma_length,
602d0847757SAlistair Popple IOMMU_PAGE_SIZE(tbl));
603d3622137SAnton Blanchard __iommu_free(tbl, vaddr, npages);
604a958a264SJake Moilanen s->dma_length = 0;
6057568cb4eSPaul Mackerras }
60678bdc310SJens Axboe if (s == outs)
60778bdc310SJens Axboe break;
6087568cb4eSPaul Mackerras }
609c4e0e892SMartin Oliveira return -EIO;
6107568cb4eSPaul Mackerras }
6117568cb4eSPaul Mackerras
6127568cb4eSPaul Mackerras
ppc_iommu_unmap_sg(struct iommu_table * tbl,struct scatterlist * sglist,int nelems,enum dma_data_direction direction,unsigned long attrs)6130690cbd2SJoerg Roedel void ppc_iommu_unmap_sg(struct iommu_table *tbl, struct scatterlist *sglist,
6143affedc4SMark Nelson int nelems, enum dma_data_direction direction,
61500085f1eSKrzysztof Kozlowski unsigned long attrs)
6167568cb4eSPaul Mackerras {
61778bdc310SJens Axboe struct scatterlist *sg;
6187568cb4eSPaul Mackerras
6197568cb4eSPaul Mackerras BUG_ON(direction == DMA_NONE);
6207568cb4eSPaul Mackerras
6217568cb4eSPaul Mackerras if (!tbl)
6227568cb4eSPaul Mackerras return;
6237568cb4eSPaul Mackerras
62478bdc310SJens Axboe sg = sglist;
6257568cb4eSPaul Mackerras while (nelems--) {
6267568cb4eSPaul Mackerras unsigned int npages;
62778bdc310SJens Axboe dma_addr_t dma_handle = sg->dma_address;
6287568cb4eSPaul Mackerras
62978bdc310SJens Axboe if (sg->dma_length == 0)
6307568cb4eSPaul Mackerras break;
6312994a3b2SJoerg Roedel npages = iommu_num_pages(dma_handle, sg->dma_length,
632d0847757SAlistair Popple IOMMU_PAGE_SIZE(tbl));
633d3622137SAnton Blanchard __iommu_free(tbl, dma_handle, npages);
63478bdc310SJens Axboe sg = sg_next(sg);
6357568cb4eSPaul Mackerras }
6367568cb4eSPaul Mackerras
6377568cb4eSPaul Mackerras /* Flush/invalidate TLBs if necessary. As for iommu_free(), we
6387568cb4eSPaul Mackerras * do not do an mb() here, the affected platforms do not need it
6397568cb4eSPaul Mackerras * when freeing.
6407568cb4eSPaul Mackerras */
641da004c36SAlexey Kardashevskiy if (tbl->it_ops->flush)
642da004c36SAlexey Kardashevskiy tbl->it_ops->flush(tbl);
6437568cb4eSPaul Mackerras }
6447568cb4eSPaul Mackerras
iommu_table_clear(struct iommu_table * tbl)64554622f10SMohan Kumar M static void iommu_table_clear(struct iommu_table *tbl)
64654622f10SMohan Kumar M {
6473ccc00a7SMahesh Salgaonkar /*
6483ccc00a7SMahesh Salgaonkar * In case of firmware assisted dump system goes through clean
6493ccc00a7SMahesh Salgaonkar * reboot process at the time of system crash. Hence it's safe to
6503ccc00a7SMahesh Salgaonkar * clear the TCE entries if firmware assisted dump is active.
6513ccc00a7SMahesh Salgaonkar */
6523ccc00a7SMahesh Salgaonkar if (!is_kdump_kernel() || is_fadump_active()) {
65354622f10SMohan Kumar M /* Clear the table in case firmware left allocations in it */
654da004c36SAlexey Kardashevskiy tbl->it_ops->clear(tbl, tbl->it_offset, tbl->it_size);
65554622f10SMohan Kumar M return;
65654622f10SMohan Kumar M }
65754622f10SMohan Kumar M
65854622f10SMohan Kumar M #ifdef CONFIG_CRASH_DUMP
659da004c36SAlexey Kardashevskiy if (tbl->it_ops->get) {
66054622f10SMohan Kumar M unsigned long index, tceval, tcecount = 0;
66154622f10SMohan Kumar M
66254622f10SMohan Kumar M /* Reserve the existing mappings left by the first kernel. */
66354622f10SMohan Kumar M for (index = 0; index < tbl->it_size; index++) {
664da004c36SAlexey Kardashevskiy tceval = tbl->it_ops->get(tbl, index + tbl->it_offset);
66554622f10SMohan Kumar M /*
66654622f10SMohan Kumar M * Freed TCE entry contains 0x7fffffffffffffff on JS20
66754622f10SMohan Kumar M */
66854622f10SMohan Kumar M if (tceval && (tceval != 0x7fffffffffffffffUL)) {
66954622f10SMohan Kumar M __set_bit(index, tbl->it_map);
67054622f10SMohan Kumar M tcecount++;
67154622f10SMohan Kumar M }
67254622f10SMohan Kumar M }
67354622f10SMohan Kumar M
67454622f10SMohan Kumar M if ((tbl->it_size - tcecount) < KDUMP_MIN_TCE_ENTRIES) {
67554622f10SMohan Kumar M printk(KERN_WARNING "TCE table is full; freeing ");
67654622f10SMohan Kumar M printk(KERN_WARNING "%d entries for the kdump boot\n",
67754622f10SMohan Kumar M KDUMP_MIN_TCE_ENTRIES);
67854622f10SMohan Kumar M for (index = tbl->it_size - KDUMP_MIN_TCE_ENTRIES;
67954622f10SMohan Kumar M index < tbl->it_size; index++)
68054622f10SMohan Kumar M __clear_bit(index, tbl->it_map);
68154622f10SMohan Kumar M }
68254622f10SMohan Kumar M }
68354622f10SMohan Kumar M #endif
68454622f10SMohan Kumar M }
68554622f10SMohan Kumar M
iommu_table_reserve_pages(struct iommu_table * tbl,unsigned long res_start,unsigned long res_end)686201ed7f3SAlexey Kardashevskiy static void iommu_table_reserve_pages(struct iommu_table *tbl,
687201ed7f3SAlexey Kardashevskiy unsigned long res_start, unsigned long res_end)
688201ed7f3SAlexey Kardashevskiy {
689201ed7f3SAlexey Kardashevskiy int i;
690201ed7f3SAlexey Kardashevskiy
691201ed7f3SAlexey Kardashevskiy WARN_ON_ONCE(res_end < res_start);
692201ed7f3SAlexey Kardashevskiy /*
693201ed7f3SAlexey Kardashevskiy * Reserve page 0 so it will not be used for any mappings.
694201ed7f3SAlexey Kardashevskiy * This avoids buggy drivers that consider page 0 to be invalid
695201ed7f3SAlexey Kardashevskiy * to crash the machine or even lose data.
696201ed7f3SAlexey Kardashevskiy */
697201ed7f3SAlexey Kardashevskiy if (tbl->it_offset == 0)
698201ed7f3SAlexey Kardashevskiy set_bit(0, tbl->it_map);
699201ed7f3SAlexey Kardashevskiy
7003c33066aSLeonardo Bras if (res_start < tbl->it_offset)
7013c33066aSLeonardo Bras res_start = tbl->it_offset;
7023c33066aSLeonardo Bras
7033c33066aSLeonardo Bras if (res_end > (tbl->it_offset + tbl->it_size))
7043c33066aSLeonardo Bras res_end = tbl->it_offset + tbl->it_size;
7053c33066aSLeonardo Bras
7063c33066aSLeonardo Bras /* Check if res_start..res_end is a valid range in the table */
7073c33066aSLeonardo Bras if (res_start >= res_end) {
7083c33066aSLeonardo Bras tbl->it_reserved_start = tbl->it_offset;
7093c33066aSLeonardo Bras tbl->it_reserved_end = tbl->it_offset;
7103c33066aSLeonardo Bras return;
7113c33066aSLeonardo Bras }
7123c33066aSLeonardo Bras
713201ed7f3SAlexey Kardashevskiy tbl->it_reserved_start = res_start;
714201ed7f3SAlexey Kardashevskiy tbl->it_reserved_end = res_end;
715201ed7f3SAlexey Kardashevskiy
716201ed7f3SAlexey Kardashevskiy for (i = tbl->it_reserved_start; i < tbl->it_reserved_end; ++i)
717201ed7f3SAlexey Kardashevskiy set_bit(i - tbl->it_offset, tbl->it_map);
718201ed7f3SAlexey Kardashevskiy }
719201ed7f3SAlexey Kardashevskiy
7207568cb4eSPaul Mackerras /*
7217568cb4eSPaul Mackerras * Build a iommu_table structure. This contains a bit map which
7227568cb4eSPaul Mackerras * is used to manage allocation of the tce space.
7237568cb4eSPaul Mackerras */
iommu_init_table(struct iommu_table * tbl,int nid,unsigned long res_start,unsigned long res_end)724201ed7f3SAlexey Kardashevskiy struct iommu_table *iommu_init_table(struct iommu_table *tbl, int nid,
725201ed7f3SAlexey Kardashevskiy unsigned long res_start, unsigned long res_end)
7267568cb4eSPaul Mackerras {
7277568cb4eSPaul Mackerras unsigned long sz;
7287568cb4eSPaul Mackerras static int welcomed = 0;
729b4c3a872SAnton Blanchard unsigned int i;
730b4c3a872SAnton Blanchard struct iommu_pool *p;
7317568cb4eSPaul Mackerras
732da004c36SAlexey Kardashevskiy BUG_ON(!tbl->it_ops);
733da004c36SAlexey Kardashevskiy
7347568cb4eSPaul Mackerras /* number of bytes needed for the bitmap */
735c5a0809aSAkinobu Mita sz = BITS_TO_LONGS(tbl->it_size) * sizeof(unsigned long);
7367568cb4eSPaul Mackerras
7377f1fa82dSAlexey Kardashevskiy tbl->it_map = vzalloc_node(sz, nid);
7384be518d8SAlexey Kardashevskiy if (!tbl->it_map) {
7394be518d8SAlexey Kardashevskiy pr_err("%s: Can't allocate %ld bytes\n", __func__, sz);
7404be518d8SAlexey Kardashevskiy return NULL;
7414be518d8SAlexey Kardashevskiy }
7427568cb4eSPaul Mackerras
743201ed7f3SAlexey Kardashevskiy iommu_table_reserve_pages(tbl, res_start, res_end);
744d12b524fSThadeu Lima de Souza Cascardo
745b4c3a872SAnton Blanchard /* We only split the IOMMU table if we have 1GB or more of space */
746d0847757SAlistair Popple if ((tbl->it_size << tbl->it_page_shift) >= (1UL * 1024 * 1024 * 1024))
747b4c3a872SAnton Blanchard tbl->nr_pools = IOMMU_NR_POOLS;
748b4c3a872SAnton Blanchard else
749b4c3a872SAnton Blanchard tbl->nr_pools = 1;
750b4c3a872SAnton Blanchard
751b4c3a872SAnton Blanchard /* We reserve the top 1/4 of the table for large allocations */
752dcd261baSBenjamin Herrenschmidt tbl->poolsize = (tbl->it_size * 3 / 4) / tbl->nr_pools;
753b4c3a872SAnton Blanchard
754dcd261baSBenjamin Herrenschmidt for (i = 0; i < tbl->nr_pools; i++) {
755b4c3a872SAnton Blanchard p = &tbl->pools[i];
756b4c3a872SAnton Blanchard spin_lock_init(&(p->lock));
757b4c3a872SAnton Blanchard p->start = tbl->poolsize * i;
758b4c3a872SAnton Blanchard p->hint = p->start;
759b4c3a872SAnton Blanchard p->end = p->start + tbl->poolsize;
760b4c3a872SAnton Blanchard }
761b4c3a872SAnton Blanchard
762b4c3a872SAnton Blanchard p = &tbl->large_pool;
763b4c3a872SAnton Blanchard spin_lock_init(&(p->lock));
764b4c3a872SAnton Blanchard p->start = tbl->poolsize * i;
765b4c3a872SAnton Blanchard p->hint = p->start;
766b4c3a872SAnton Blanchard p->end = tbl->it_size;
7677568cb4eSPaul Mackerras
76854622f10SMohan Kumar M iommu_table_clear(tbl);
7697568cb4eSPaul Mackerras
7707568cb4eSPaul Mackerras if (!welcomed) {
7717568cb4eSPaul Mackerras printk(KERN_INFO "IOMMU table initialized, virtual merging %s\n",
7727568cb4eSPaul Mackerras novmerge ? "disabled" : "enabled");
7737568cb4eSPaul Mackerras welcomed = 1;
7747568cb4eSPaul Mackerras }
7757568cb4eSPaul Mackerras
776691602aaSAlexey Kardashevskiy iommu_debugfs_add(tbl);
777691602aaSAlexey Kardashevskiy
7787568cb4eSPaul Mackerras return tbl;
7797568cb4eSPaul Mackerras }
7807568cb4eSPaul Mackerras
iommu_table_in_use(struct iommu_table * tbl)7813c33066aSLeonardo Bras bool iommu_table_in_use(struct iommu_table *tbl)
7823c33066aSLeonardo Bras {
7833c33066aSLeonardo Bras unsigned long start = 0, end;
7843c33066aSLeonardo Bras
7853c33066aSLeonardo Bras /* ignore reserved bit0 */
7863c33066aSLeonardo Bras if (tbl->it_offset == 0)
7873c33066aSLeonardo Bras start = 1;
788d80f6de9SAlexey Kardashevskiy
789d80f6de9SAlexey Kardashevskiy /* Simple case with no reserved MMIO32 region */
790d80f6de9SAlexey Kardashevskiy if (!tbl->it_reserved_start && !tbl->it_reserved_end)
791d80f6de9SAlexey Kardashevskiy return find_next_bit(tbl->it_map, tbl->it_size, start) != tbl->it_size;
792d80f6de9SAlexey Kardashevskiy
7933c33066aSLeonardo Bras end = tbl->it_reserved_start - tbl->it_offset;
7943c33066aSLeonardo Bras if (find_next_bit(tbl->it_map, end, start) != end)
7953c33066aSLeonardo Bras return true;
7963c33066aSLeonardo Bras
7973c33066aSLeonardo Bras start = tbl->it_reserved_end - tbl->it_offset;
7983c33066aSLeonardo Bras end = tbl->it_size;
7993c33066aSLeonardo Bras return find_next_bit(tbl->it_map, end, start) != end;
8003c33066aSLeonardo Bras }
8013c33066aSLeonardo Bras
iommu_table_free(struct kref * kref)802e5afdf9dSAlexey Kardashevskiy static void iommu_table_free(struct kref *kref)
8037568cb4eSPaul Mackerras {
804e5afdf9dSAlexey Kardashevskiy struct iommu_table *tbl;
8057568cb4eSPaul Mackerras
806e5afdf9dSAlexey Kardashevskiy tbl = container_of(kref, struct iommu_table, it_kref);
8078aca92d8SAlexey Kardashevskiy
80811edf116SAlexey Kardashevskiy if (tbl->it_ops->free)
80911edf116SAlexey Kardashevskiy tbl->it_ops->free(tbl);
81011edf116SAlexey Kardashevskiy
8118aca92d8SAlexey Kardashevskiy if (!tbl->it_map) {
8128aca92d8SAlexey Kardashevskiy kfree(tbl);
8137568cb4eSPaul Mackerras return;
8147568cb4eSPaul Mackerras }
8157568cb4eSPaul Mackerras
816691602aaSAlexey Kardashevskiy iommu_debugfs_del(tbl);
817691602aaSAlexey Kardashevskiy
8187568cb4eSPaul Mackerras /* verify that table contains no entries */
8193c33066aSLeonardo Bras if (iommu_table_in_use(tbl))
820e5afdf9dSAlexey Kardashevskiy pr_warn("%s: Unexpected TCEs\n", __func__);
8217568cb4eSPaul Mackerras
8227568cb4eSPaul Mackerras /* free bitmap */
8237f1fa82dSAlexey Kardashevskiy vfree(tbl->it_map);
8247568cb4eSPaul Mackerras
8257568cb4eSPaul Mackerras /* free table */
8267568cb4eSPaul Mackerras kfree(tbl);
8277568cb4eSPaul Mackerras }
828e5afdf9dSAlexey Kardashevskiy
iommu_tce_table_get(struct iommu_table * tbl)829e5afdf9dSAlexey Kardashevskiy struct iommu_table *iommu_tce_table_get(struct iommu_table *tbl)
830e5afdf9dSAlexey Kardashevskiy {
831e5afdf9dSAlexey Kardashevskiy if (kref_get_unless_zero(&tbl->it_kref))
832e5afdf9dSAlexey Kardashevskiy return tbl;
833e5afdf9dSAlexey Kardashevskiy
834e5afdf9dSAlexey Kardashevskiy return NULL;
835e5afdf9dSAlexey Kardashevskiy }
836e5afdf9dSAlexey Kardashevskiy EXPORT_SYMBOL_GPL(iommu_tce_table_get);
837e5afdf9dSAlexey Kardashevskiy
iommu_tce_table_put(struct iommu_table * tbl)838e5afdf9dSAlexey Kardashevskiy int iommu_tce_table_put(struct iommu_table *tbl)
839e5afdf9dSAlexey Kardashevskiy {
840e5afdf9dSAlexey Kardashevskiy if (WARN_ON(!tbl))
841e5afdf9dSAlexey Kardashevskiy return 0;
842e5afdf9dSAlexey Kardashevskiy
843e5afdf9dSAlexey Kardashevskiy return kref_put(&tbl->it_kref, iommu_table_free);
844e5afdf9dSAlexey Kardashevskiy }
845e5afdf9dSAlexey Kardashevskiy EXPORT_SYMBOL_GPL(iommu_tce_table_put);
8467568cb4eSPaul Mackerras
8477568cb4eSPaul Mackerras /* Creates TCEs for a user provided buffer. The user buffer must be
848f9226d57SMark Nelson * contiguous real kernel storage (not vmalloc). The address passed here
849f9226d57SMark Nelson * comprises a page address and offset into that page. The dma_addr_t
850f9226d57SMark Nelson * returned will point to the same byte within the page as was passed in.
8517568cb4eSPaul Mackerras */
iommu_map_page(struct device * dev,struct iommu_table * tbl,struct page * page,unsigned long offset,size_t size,unsigned long mask,enum dma_data_direction direction,unsigned long attrs)852f9226d57SMark Nelson dma_addr_t iommu_map_page(struct device *dev, struct iommu_table *tbl,
853f9226d57SMark Nelson struct page *page, unsigned long offset, size_t size,
854f9226d57SMark Nelson unsigned long mask, enum dma_data_direction direction,
85500085f1eSKrzysztof Kozlowski unsigned long attrs)
8567568cb4eSPaul Mackerras {
857d11e3d3dSChristoph Hellwig dma_addr_t dma_handle = DMA_MAPPING_ERROR;
858f9226d57SMark Nelson void *vaddr;
8597568cb4eSPaul Mackerras unsigned long uaddr;
860d262c32aSBenjamin Herrenschmidt unsigned int npages, align;
8617568cb4eSPaul Mackerras
8627568cb4eSPaul Mackerras BUG_ON(direction == DMA_NONE);
8637568cb4eSPaul Mackerras
864f9226d57SMark Nelson vaddr = page_address(page) + offset;
8657568cb4eSPaul Mackerras uaddr = (unsigned long)vaddr;
8667568cb4eSPaul Mackerras
8677568cb4eSPaul Mackerras if (tbl) {
868984ecdd6SBreno Leitao npages = iommu_num_pages(uaddr, size, IOMMU_PAGE_SIZE(tbl));
869d262c32aSBenjamin Herrenschmidt align = 0;
870d0847757SAlistair Popple if (tbl->it_page_shift < PAGE_SHIFT && size >= PAGE_SIZE &&
871d262c32aSBenjamin Herrenschmidt ((unsigned long)vaddr & ~PAGE_MASK) == 0)
872d0847757SAlistair Popple align = PAGE_SHIFT - tbl->it_page_shift;
873d262c32aSBenjamin Herrenschmidt
874fb3475e9SFUJITA Tomonori dma_handle = iommu_alloc(dev, tbl, vaddr, npages, direction,
875d0847757SAlistair Popple mask >> tbl->it_page_shift, align,
8764f3dd8a0SMark Nelson attrs);
877d11e3d3dSChristoph Hellwig if (dma_handle == DMA_MAPPING_ERROR) {
878af8a2498SMauricio Faria de Oliveira if (!(attrs & DMA_ATTR_NO_WARN) &&
879af8a2498SMauricio Faria de Oliveira printk_ratelimit()) {
8804dfa9c47SAnton Blanchard dev_info(dev, "iommu_alloc failed, tbl %p "
8814dfa9c47SAnton Blanchard "vaddr %p npages %d\n", tbl, vaddr,
8824dfa9c47SAnton Blanchard npages);
8837568cb4eSPaul Mackerras }
8847568cb4eSPaul Mackerras } else
885d0847757SAlistair Popple dma_handle |= (uaddr & ~IOMMU_PAGE_MASK(tbl));
8867568cb4eSPaul Mackerras }
8877568cb4eSPaul Mackerras
8887568cb4eSPaul Mackerras return dma_handle;
8897568cb4eSPaul Mackerras }
8907568cb4eSPaul Mackerras
iommu_unmap_page(struct iommu_table * tbl,dma_addr_t dma_handle,size_t size,enum dma_data_direction direction,unsigned long attrs)891f9226d57SMark Nelson void iommu_unmap_page(struct iommu_table *tbl, dma_addr_t dma_handle,
8923affedc4SMark Nelson size_t size, enum dma_data_direction direction,
89300085f1eSKrzysztof Kozlowski unsigned long attrs)
8947568cb4eSPaul Mackerras {
8955d2efba6SLinas Vepstas unsigned int npages;
8965d2efba6SLinas Vepstas
8977568cb4eSPaul Mackerras BUG_ON(direction == DMA_NONE);
8987568cb4eSPaul Mackerras
8995d2efba6SLinas Vepstas if (tbl) {
900d0847757SAlistair Popple npages = iommu_num_pages(dma_handle, size,
901d0847757SAlistair Popple IOMMU_PAGE_SIZE(tbl));
9025d2efba6SLinas Vepstas iommu_free(tbl, dma_handle, npages);
9035d2efba6SLinas Vepstas }
9047568cb4eSPaul Mackerras }
9057568cb4eSPaul Mackerras
9067568cb4eSPaul Mackerras /* Allocates a contiguous real buffer and creates mappings over it.
9077568cb4eSPaul Mackerras * Returns the virtual address of the buffer and sets dma_handle
9087568cb4eSPaul Mackerras * to the dma address (mapping) of the first page.
9097568cb4eSPaul Mackerras */
iommu_alloc_coherent(struct device * dev,struct iommu_table * tbl,size_t size,dma_addr_t * dma_handle,unsigned long mask,gfp_t flag,int node)910fb3475e9SFUJITA Tomonori void *iommu_alloc_coherent(struct device *dev, struct iommu_table *tbl,
911fb3475e9SFUJITA Tomonori size_t size, dma_addr_t *dma_handle,
912fb3475e9SFUJITA Tomonori unsigned long mask, gfp_t flag, int node)
9137568cb4eSPaul Mackerras {
9147568cb4eSPaul Mackerras void *ret = NULL;
9157568cb4eSPaul Mackerras dma_addr_t mapping;
9165d2efba6SLinas Vepstas unsigned int order;
9175d2efba6SLinas Vepstas unsigned int nio_pages, io_order;
9188eb6c6e3SChristoph Hellwig struct page *page;
919096339abSGaurav Batra int tcesize = (1 << tbl->it_page_shift);
9207568cb4eSPaul Mackerras
9217568cb4eSPaul Mackerras size = PAGE_ALIGN(size);
9227568cb4eSPaul Mackerras order = get_order(size);
9237568cb4eSPaul Mackerras
9247568cb4eSPaul Mackerras /*
9257568cb4eSPaul Mackerras * Client asked for way too much space. This is checked later
9267568cb4eSPaul Mackerras * anyway. It is easier to debug here for the drivers than in
9277568cb4eSPaul Mackerras * the tce tables.
9287568cb4eSPaul Mackerras */
9297568cb4eSPaul Mackerras if (order >= IOMAP_MAX_ORDER) {
9304dfa9c47SAnton Blanchard dev_info(dev, "iommu_alloc_consistent size too large: 0x%lx\n",
9314dfa9c47SAnton Blanchard size);
9327568cb4eSPaul Mackerras return NULL;
9337568cb4eSPaul Mackerras }
9347568cb4eSPaul Mackerras
9357568cb4eSPaul Mackerras if (!tbl)
9367568cb4eSPaul Mackerras return NULL;
9377568cb4eSPaul Mackerras
9387568cb4eSPaul Mackerras /* Alloc enough pages (and possibly more) */
93905061354SPaul Mackerras page = alloc_pages_node(node, flag, order);
9408eb6c6e3SChristoph Hellwig if (!page)
9417568cb4eSPaul Mackerras return NULL;
9428eb6c6e3SChristoph Hellwig ret = page_address(page);
9437568cb4eSPaul Mackerras memset(ret, 0, size);
9447568cb4eSPaul Mackerras
9457568cb4eSPaul Mackerras /* Set up tces to cover the allocated range */
946096339abSGaurav Batra nio_pages = IOMMU_PAGE_ALIGN(size, tbl) >> tbl->it_page_shift;
947096339abSGaurav Batra
94859cc84c8SFrederic Barrat io_order = get_iommu_order(size, tbl);
949fb3475e9SFUJITA Tomonori mapping = iommu_alloc(dev, tbl, ret, nio_pages, DMA_BIDIRECTIONAL,
95000085f1eSKrzysztof Kozlowski mask >> tbl->it_page_shift, io_order, 0);
951d11e3d3dSChristoph Hellwig if (mapping == DMA_MAPPING_ERROR) {
9527568cb4eSPaul Mackerras free_pages((unsigned long)ret, order);
9538eb6c6e3SChristoph Hellwig return NULL;
9548eb6c6e3SChristoph Hellwig }
955096339abSGaurav Batra
956096339abSGaurav Batra *dma_handle = mapping | ((u64)ret & (tcesize - 1));
9577568cb4eSPaul Mackerras return ret;
9587568cb4eSPaul Mackerras }
9597568cb4eSPaul Mackerras
iommu_free_coherent(struct iommu_table * tbl,size_t size,void * vaddr,dma_addr_t dma_handle)9607568cb4eSPaul Mackerras void iommu_free_coherent(struct iommu_table *tbl, size_t size,
9617568cb4eSPaul Mackerras void *vaddr, dma_addr_t dma_handle)
9627568cb4eSPaul Mackerras {
9637568cb4eSPaul Mackerras if (tbl) {
96459cc84c8SFrederic Barrat unsigned int nio_pages;
9655d2efba6SLinas Vepstas
96659cc84c8SFrederic Barrat size = PAGE_ALIGN(size);
967096339abSGaurav Batra nio_pages = IOMMU_PAGE_ALIGN(size, tbl) >> tbl->it_page_shift;
9685d2efba6SLinas Vepstas iommu_free(tbl, dma_handle, nio_pages);
9695d2efba6SLinas Vepstas size = PAGE_ALIGN(size);
9707568cb4eSPaul Mackerras free_pages((unsigned long)vaddr, get_order(size));
9717568cb4eSPaul Mackerras }
9727568cb4eSPaul Mackerras }
9734e13c1acSAlexey Kardashevskiy
iommu_direction_to_tce_perm(enum dma_data_direction dir)97410b35b2bSAlexey Kardashevskiy unsigned long iommu_direction_to_tce_perm(enum dma_data_direction dir)
97510b35b2bSAlexey Kardashevskiy {
97610b35b2bSAlexey Kardashevskiy switch (dir) {
97710b35b2bSAlexey Kardashevskiy case DMA_BIDIRECTIONAL:
97810b35b2bSAlexey Kardashevskiy return TCE_PCI_READ | TCE_PCI_WRITE;
97910b35b2bSAlexey Kardashevskiy case DMA_FROM_DEVICE:
98010b35b2bSAlexey Kardashevskiy return TCE_PCI_WRITE;
98110b35b2bSAlexey Kardashevskiy case DMA_TO_DEVICE:
98210b35b2bSAlexey Kardashevskiy return TCE_PCI_READ;
98310b35b2bSAlexey Kardashevskiy default:
98410b35b2bSAlexey Kardashevskiy return 0;
98510b35b2bSAlexey Kardashevskiy }
98610b35b2bSAlexey Kardashevskiy }
98710b35b2bSAlexey Kardashevskiy EXPORT_SYMBOL_GPL(iommu_direction_to_tce_perm);
98810b35b2bSAlexey Kardashevskiy
9894e13c1acSAlexey Kardashevskiy #ifdef CONFIG_IOMMU_API
9904e13c1acSAlexey Kardashevskiy /*
9914e13c1acSAlexey Kardashevskiy * SPAPR TCE API
9924e13c1acSAlexey Kardashevskiy */
group_release(void * iommu_data)9934e13c1acSAlexey Kardashevskiy static void group_release(void *iommu_data)
9944e13c1acSAlexey Kardashevskiy {
995b348aa65SAlexey Kardashevskiy struct iommu_table_group *table_group = iommu_data;
996b348aa65SAlexey Kardashevskiy
997b348aa65SAlexey Kardashevskiy table_group->group = NULL;
9984e13c1acSAlexey Kardashevskiy }
9994e13c1acSAlexey Kardashevskiy
iommu_register_group(struct iommu_table_group * table_group,int pci_domain_number,unsigned long pe_num)1000b348aa65SAlexey Kardashevskiy void iommu_register_group(struct iommu_table_group *table_group,
10014e13c1acSAlexey Kardashevskiy int pci_domain_number, unsigned long pe_num)
10024e13c1acSAlexey Kardashevskiy {
10034e13c1acSAlexey Kardashevskiy struct iommu_group *grp;
10044e13c1acSAlexey Kardashevskiy char *name;
10054e13c1acSAlexey Kardashevskiy
10064e13c1acSAlexey Kardashevskiy grp = iommu_group_alloc();
10074e13c1acSAlexey Kardashevskiy if (IS_ERR(grp)) {
10084e13c1acSAlexey Kardashevskiy pr_warn("powerpc iommu api: cannot create new group, err=%ld\n",
10094e13c1acSAlexey Kardashevskiy PTR_ERR(grp));
10104e13c1acSAlexey Kardashevskiy return;
10114e13c1acSAlexey Kardashevskiy }
1012b348aa65SAlexey Kardashevskiy table_group->group = grp;
1013b348aa65SAlexey Kardashevskiy iommu_group_set_iommudata(grp, table_group, group_release);
10144e13c1acSAlexey Kardashevskiy name = kasprintf(GFP_KERNEL, "domain%d-pe%lx",
10154e13c1acSAlexey Kardashevskiy pci_domain_number, pe_num);
10164e13c1acSAlexey Kardashevskiy if (!name)
10174e13c1acSAlexey Kardashevskiy return;
10184e13c1acSAlexey Kardashevskiy iommu_group_set_name(grp, name);
10194e13c1acSAlexey Kardashevskiy kfree(name);
10204e13c1acSAlexey Kardashevskiy }
10214e13c1acSAlexey Kardashevskiy
iommu_tce_direction(unsigned long tce)10224e13c1acSAlexey Kardashevskiy enum dma_data_direction iommu_tce_direction(unsigned long tce)
10234e13c1acSAlexey Kardashevskiy {
10244e13c1acSAlexey Kardashevskiy if ((tce & TCE_PCI_READ) && (tce & TCE_PCI_WRITE))
10254e13c1acSAlexey Kardashevskiy return DMA_BIDIRECTIONAL;
10264e13c1acSAlexey Kardashevskiy else if (tce & TCE_PCI_READ)
10274e13c1acSAlexey Kardashevskiy return DMA_TO_DEVICE;
10284e13c1acSAlexey Kardashevskiy else if (tce & TCE_PCI_WRITE)
10294e13c1acSAlexey Kardashevskiy return DMA_FROM_DEVICE;
10304e13c1acSAlexey Kardashevskiy else
10314e13c1acSAlexey Kardashevskiy return DMA_NONE;
10324e13c1acSAlexey Kardashevskiy }
10334e13c1acSAlexey Kardashevskiy EXPORT_SYMBOL_GPL(iommu_tce_direction);
10344e13c1acSAlexey Kardashevskiy
iommu_flush_tce(struct iommu_table * tbl)10354e13c1acSAlexey Kardashevskiy void iommu_flush_tce(struct iommu_table *tbl)
10364e13c1acSAlexey Kardashevskiy {
10374e13c1acSAlexey Kardashevskiy /* Flush/invalidate TLB caches if necessary */
1038da004c36SAlexey Kardashevskiy if (tbl->it_ops->flush)
1039da004c36SAlexey Kardashevskiy tbl->it_ops->flush(tbl);
10404e13c1acSAlexey Kardashevskiy
10414e13c1acSAlexey Kardashevskiy /* Make sure updates are seen by hardware */
10424e13c1acSAlexey Kardashevskiy mb();
10434e13c1acSAlexey Kardashevskiy }
10444e13c1acSAlexey Kardashevskiy EXPORT_SYMBOL_GPL(iommu_flush_tce);
10454e13c1acSAlexey Kardashevskiy
iommu_tce_check_ioba(unsigned long page_shift,unsigned long offset,unsigned long size,unsigned long ioba,unsigned long npages)1046b1af23d8SAlexey Kardashevskiy int iommu_tce_check_ioba(unsigned long page_shift,
1047b1af23d8SAlexey Kardashevskiy unsigned long offset, unsigned long size,
1048b1af23d8SAlexey Kardashevskiy unsigned long ioba, unsigned long npages)
10494e13c1acSAlexey Kardashevskiy {
1050b1af23d8SAlexey Kardashevskiy unsigned long mask = (1UL << page_shift) - 1;
1051b1af23d8SAlexey Kardashevskiy
1052b1af23d8SAlexey Kardashevskiy if (ioba & mask)
10534e13c1acSAlexey Kardashevskiy return -EINVAL;
10544e13c1acSAlexey Kardashevskiy
1055b1af23d8SAlexey Kardashevskiy ioba >>= page_shift;
1056b1af23d8SAlexey Kardashevskiy if (ioba < offset)
10574e13c1acSAlexey Kardashevskiy return -EINVAL;
10584e13c1acSAlexey Kardashevskiy
1059b1af23d8SAlexey Kardashevskiy if ((ioba + 1) > (offset + size))
10604e13c1acSAlexey Kardashevskiy return -EINVAL;
10614e13c1acSAlexey Kardashevskiy
10624e13c1acSAlexey Kardashevskiy return 0;
10634e13c1acSAlexey Kardashevskiy }
1064b1af23d8SAlexey Kardashevskiy EXPORT_SYMBOL_GPL(iommu_tce_check_ioba);
10654e13c1acSAlexey Kardashevskiy
iommu_tce_check_gpa(unsigned long page_shift,unsigned long gpa)1066b1af23d8SAlexey Kardashevskiy int iommu_tce_check_gpa(unsigned long page_shift, unsigned long gpa)
10674e13c1acSAlexey Kardashevskiy {
1068b1af23d8SAlexey Kardashevskiy unsigned long mask = (1UL << page_shift) - 1;
10694e13c1acSAlexey Kardashevskiy
1070b1af23d8SAlexey Kardashevskiy if (gpa & mask)
10714e13c1acSAlexey Kardashevskiy return -EINVAL;
10724e13c1acSAlexey Kardashevskiy
10734e13c1acSAlexey Kardashevskiy return 0;
10744e13c1acSAlexey Kardashevskiy }
1075b1af23d8SAlexey Kardashevskiy EXPORT_SYMBOL_GPL(iommu_tce_check_gpa);
10764e13c1acSAlexey Kardashevskiy
iommu_tce_xchg_no_kill(struct mm_struct * mm,struct iommu_table * tbl,unsigned long entry,unsigned long * hpa,enum dma_data_direction * direction)107735872480SAlexey Kardashevskiy extern long iommu_tce_xchg_no_kill(struct mm_struct *mm,
107835872480SAlexey Kardashevskiy struct iommu_table *tbl,
1079c10c21efSAlexey Kardashevskiy unsigned long entry, unsigned long *hpa,
1080c10c21efSAlexey Kardashevskiy enum dma_data_direction *direction)
10814e13c1acSAlexey Kardashevskiy {
108205c6cfb9SAlexey Kardashevskiy long ret;
1083c10c21efSAlexey Kardashevskiy unsigned long size = 0;
10844e13c1acSAlexey Kardashevskiy
1085cad32d9dSAlexey Kardashevskiy ret = tbl->it_ops->xchg_no_kill(tbl, entry, hpa, direction);
108605c6cfb9SAlexey Kardashevskiy if (!ret && ((*direction == DMA_FROM_DEVICE) ||
1087c10c21efSAlexey Kardashevskiy (*direction == DMA_BIDIRECTIONAL)) &&
1088c10c21efSAlexey Kardashevskiy !mm_iommu_is_devmem(mm, *hpa, tbl->it_page_shift,
1089c10c21efSAlexey Kardashevskiy &size))
109005c6cfb9SAlexey Kardashevskiy SetPageDirty(pfn_to_page(*hpa >> PAGE_SHIFT));
10914e13c1acSAlexey Kardashevskiy
10924e13c1acSAlexey Kardashevskiy return ret;
10934e13c1acSAlexey Kardashevskiy }
109435872480SAlexey Kardashevskiy EXPORT_SYMBOL_GPL(iommu_tce_xchg_no_kill);
109535872480SAlexey Kardashevskiy
iommu_tce_kill(struct iommu_table * tbl,unsigned long entry,unsigned long pages)109635872480SAlexey Kardashevskiy void iommu_tce_kill(struct iommu_table *tbl,
109735872480SAlexey Kardashevskiy unsigned long entry, unsigned long pages)
109835872480SAlexey Kardashevskiy {
109935872480SAlexey Kardashevskiy if (tbl->it_ops->tce_kill)
1100cad32d9dSAlexey Kardashevskiy tbl->it_ops->tce_kill(tbl, entry, pages);
110135872480SAlexey Kardashevskiy }
110235872480SAlexey Kardashevskiy EXPORT_SYMBOL_GPL(iommu_tce_kill);
11034e13c1acSAlexey Kardashevskiy
1104bfd8d989STimothy Pearson #if defined(CONFIG_PPC_PSERIES) || defined(CONFIG_PPC_POWERNV)
iommu_take_ownership(struct iommu_table * tbl)11059d67c943SAlexey Kardashevskiy static int iommu_take_ownership(struct iommu_table *tbl)
11064e13c1acSAlexey Kardashevskiy {
1107b82c75bfSAlexey Kardashevskiy unsigned long flags, i, sz = (tbl->it_size + 7) >> 3;
1108b82c75bfSAlexey Kardashevskiy int ret = 0;
1109b82c75bfSAlexey Kardashevskiy
111005c6cfb9SAlexey Kardashevskiy /*
111105c6cfb9SAlexey Kardashevskiy * VFIO does not control TCE entries allocation and the guest
111205c6cfb9SAlexey Kardashevskiy * can write new TCEs on top of existing ones so iommu_tce_build()
111305c6cfb9SAlexey Kardashevskiy * must be able to release old pages. This functionality
111405c6cfb9SAlexey Kardashevskiy * requires exchange() callback defined so if it is not
111505c6cfb9SAlexey Kardashevskiy * implemented, we disallow taking ownership over the table.
111605c6cfb9SAlexey Kardashevskiy */
1117a102f139SAlexey Kardashevskiy if (!tbl->it_ops->xchg_no_kill)
111805c6cfb9SAlexey Kardashevskiy return -EINVAL;
111905c6cfb9SAlexey Kardashevskiy
1120b82c75bfSAlexey Kardashevskiy spin_lock_irqsave(&tbl->large_pool.lock, flags);
1121b82c75bfSAlexey Kardashevskiy for (i = 0; i < tbl->nr_pools; i++)
1122cc7130bfSAlexey Kardashevskiy spin_lock_nest_lock(&tbl->pools[i].lock, &tbl->large_pool.lock);
11234e13c1acSAlexey Kardashevskiy
11243c33066aSLeonardo Bras if (iommu_table_in_use(tbl)) {
11254e13c1acSAlexey Kardashevskiy pr_err("iommu_tce: it_map is not empty");
1126b82c75bfSAlexey Kardashevskiy ret = -EBUSY;
1127b82c75bfSAlexey Kardashevskiy } else {
1128b82c75bfSAlexey Kardashevskiy memset(tbl->it_map, 0xff, sz);
11294e13c1acSAlexey Kardashevskiy }
11304e13c1acSAlexey Kardashevskiy
1131b82c75bfSAlexey Kardashevskiy for (i = 0; i < tbl->nr_pools; i++)
1132b82c75bfSAlexey Kardashevskiy spin_unlock(&tbl->pools[i].lock);
1133b82c75bfSAlexey Kardashevskiy spin_unlock_irqrestore(&tbl->large_pool.lock, flags);
11344e13c1acSAlexey Kardashevskiy
1135b82c75bfSAlexey Kardashevskiy return ret;
11364e13c1acSAlexey Kardashevskiy }
11374e13c1acSAlexey Kardashevskiy
iommu_release_ownership(struct iommu_table * tbl)11389d67c943SAlexey Kardashevskiy static void iommu_release_ownership(struct iommu_table *tbl)
11394e13c1acSAlexey Kardashevskiy {
1140b82c75bfSAlexey Kardashevskiy unsigned long flags, i, sz = (tbl->it_size + 7) >> 3;
1141b82c75bfSAlexey Kardashevskiy
1142b82c75bfSAlexey Kardashevskiy spin_lock_irqsave(&tbl->large_pool.lock, flags);
1143b82c75bfSAlexey Kardashevskiy for (i = 0; i < tbl->nr_pools; i++)
1144cc7130bfSAlexey Kardashevskiy spin_lock_nest_lock(&tbl->pools[i].lock, &tbl->large_pool.lock);
11454e13c1acSAlexey Kardashevskiy
11464e13c1acSAlexey Kardashevskiy memset(tbl->it_map, 0, sz);
11474e13c1acSAlexey Kardashevskiy
1148201ed7f3SAlexey Kardashevskiy iommu_table_reserve_pages(tbl, tbl->it_reserved_start,
1149201ed7f3SAlexey Kardashevskiy tbl->it_reserved_end);
1150b82c75bfSAlexey Kardashevskiy
1151b82c75bfSAlexey Kardashevskiy for (i = 0; i < tbl->nr_pools; i++)
1152b82c75bfSAlexey Kardashevskiy spin_unlock(&tbl->pools[i].lock);
1153b82c75bfSAlexey Kardashevskiy spin_unlock_irqrestore(&tbl->large_pool.lock, flags);
11544e13c1acSAlexey Kardashevskiy }
1155bfd8d989STimothy Pearson #endif
11564e13c1acSAlexey Kardashevskiy
iommu_add_device(struct iommu_table_group * table_group,struct device * dev)1157c4e9d3c1SAlexey Kardashevskiy int iommu_add_device(struct iommu_table_group *table_group, struct device *dev)
11584e13c1acSAlexey Kardashevskiy {
1159763fe0adSGavin Shan /*
1160763fe0adSGavin Shan * The sysfs entries should be populated before
1161763fe0adSGavin Shan * binding IOMMU group. If sysfs entries isn't
1162763fe0adSGavin Shan * ready, we simply bail.
1163763fe0adSGavin Shan */
1164763fe0adSGavin Shan if (!device_is_registered(dev))
1165763fe0adSGavin Shan return -ENOENT;
1166763fe0adSGavin Shan
1167bf8763d8SJoerg Roedel if (device_iommu_mapped(dev)) {
1168763fe0adSGavin Shan pr_debug("%s: Skipping device %s with iommu group %d\n",
1169763fe0adSGavin Shan __func__, dev_name(dev),
11704e13c1acSAlexey Kardashevskiy iommu_group_id(dev->iommu_group));
11714e13c1acSAlexey Kardashevskiy return -EBUSY;
11724e13c1acSAlexey Kardashevskiy }
11734e13c1acSAlexey Kardashevskiy
1174763fe0adSGavin Shan pr_debug("%s: Adding %s to iommu group %d\n",
1175c4e9d3c1SAlexey Kardashevskiy __func__, dev_name(dev), iommu_group_id(table_group->group));
1176a9409044SAlexey Kardashevskiy /*
1177a9409044SAlexey Kardashevskiy * This is still not adding devices via the IOMMU bus notifier because
1178a9409044SAlexey Kardashevskiy * of pcibios_init() from arch/powerpc/kernel/pci_64.c which calls
1179a9409044SAlexey Kardashevskiy * pcibios_scan_phb() first (and this guy adds devices and triggers
1180a9409044SAlexey Kardashevskiy * the notifier) and only then it calls pci_bus_add_devices() which
1181a9409044SAlexey Kardashevskiy * configures DMA for buses which also creates PEs and IOMMU groups.
1182a9409044SAlexey Kardashevskiy */
1183a9409044SAlexey Kardashevskiy return iommu_probe_device(dev);
11844e13c1acSAlexey Kardashevskiy }
1185d905c5dfSAlexey Kardashevskiy EXPORT_SYMBOL_GPL(iommu_add_device);
11864e13c1acSAlexey Kardashevskiy
1187bfd8d989STimothy Pearson #if defined(CONFIG_PPC_PSERIES) || defined(CONFIG_PPC_POWERNV)
11889d67c943SAlexey Kardashevskiy /*
11899d67c943SAlexey Kardashevskiy * A simple iommu_table_group_ops which only allows reusing the existing
11909d67c943SAlexey Kardashevskiy * iommu_table. This handles VFIO for POWER7 or the nested KVM.
11919d67c943SAlexey Kardashevskiy * The ops does not allow creating windows and only allows reusing the existing
11929d67c943SAlexey Kardashevskiy * one if it matches table_group->tce32_start/tce32_size/page_shift.
11939d67c943SAlexey Kardashevskiy */
spapr_tce_get_table_size(__u32 page_shift,__u64 window_size,__u32 levels)11949d67c943SAlexey Kardashevskiy static unsigned long spapr_tce_get_table_size(__u32 page_shift,
11959d67c943SAlexey Kardashevskiy __u64 window_size, __u32 levels)
11969d67c943SAlexey Kardashevskiy {
11979d67c943SAlexey Kardashevskiy unsigned long size;
11989d67c943SAlexey Kardashevskiy
11999d67c943SAlexey Kardashevskiy if (levels > 1)
12009d67c943SAlexey Kardashevskiy return ~0U;
12019d67c943SAlexey Kardashevskiy size = window_size >> (page_shift - 3);
12029d67c943SAlexey Kardashevskiy return size;
12039d67c943SAlexey Kardashevskiy }
12049d67c943SAlexey Kardashevskiy
spapr_tce_create_table(struct iommu_table_group * table_group,int num,__u32 page_shift,__u64 window_size,__u32 levels,struct iommu_table ** ptbl)12059d67c943SAlexey Kardashevskiy static long spapr_tce_create_table(struct iommu_table_group *table_group, int num,
12069d67c943SAlexey Kardashevskiy __u32 page_shift, __u64 window_size, __u32 levels,
12079d67c943SAlexey Kardashevskiy struct iommu_table **ptbl)
12089d67c943SAlexey Kardashevskiy {
12099d67c943SAlexey Kardashevskiy struct iommu_table *tbl = table_group->tables[0];
12109d67c943SAlexey Kardashevskiy
12119d67c943SAlexey Kardashevskiy if (num > 0)
12129d67c943SAlexey Kardashevskiy return -EPERM;
12139d67c943SAlexey Kardashevskiy
12149d67c943SAlexey Kardashevskiy if (tbl->it_page_shift != page_shift ||
12159d67c943SAlexey Kardashevskiy tbl->it_size != (window_size >> page_shift) ||
12169d67c943SAlexey Kardashevskiy tbl->it_indirect_levels != levels - 1)
12179d67c943SAlexey Kardashevskiy return -EINVAL;
12189d67c943SAlexey Kardashevskiy
12199d67c943SAlexey Kardashevskiy *ptbl = iommu_tce_table_get(tbl);
12209d67c943SAlexey Kardashevskiy return 0;
12219d67c943SAlexey Kardashevskiy }
12229d67c943SAlexey Kardashevskiy
spapr_tce_set_window(struct iommu_table_group * table_group,int num,struct iommu_table * tbl)12239d67c943SAlexey Kardashevskiy static long spapr_tce_set_window(struct iommu_table_group *table_group,
12249d67c943SAlexey Kardashevskiy int num, struct iommu_table *tbl)
12259d67c943SAlexey Kardashevskiy {
12269d67c943SAlexey Kardashevskiy return tbl == table_group->tables[num] ? 0 : -EPERM;
12279d67c943SAlexey Kardashevskiy }
12289d67c943SAlexey Kardashevskiy
spapr_tce_unset_window(struct iommu_table_group * table_group,int num)12299d67c943SAlexey Kardashevskiy static long spapr_tce_unset_window(struct iommu_table_group *table_group, int num)
12309d67c943SAlexey Kardashevskiy {
12319d67c943SAlexey Kardashevskiy return 0;
12329d67c943SAlexey Kardashevskiy }
12339d67c943SAlexey Kardashevskiy
spapr_tce_take_ownership(struct iommu_table_group * table_group)12349d67c943SAlexey Kardashevskiy static long spapr_tce_take_ownership(struct iommu_table_group *table_group)
12359d67c943SAlexey Kardashevskiy {
12369d67c943SAlexey Kardashevskiy int i, j, rc = 0;
12379d67c943SAlexey Kardashevskiy
12389d67c943SAlexey Kardashevskiy for (i = 0; i < IOMMU_TABLE_GROUP_MAX_TABLES; ++i) {
12399d67c943SAlexey Kardashevskiy struct iommu_table *tbl = table_group->tables[i];
12409d67c943SAlexey Kardashevskiy
12419d67c943SAlexey Kardashevskiy if (!tbl || !tbl->it_map)
12429d67c943SAlexey Kardashevskiy continue;
12439d67c943SAlexey Kardashevskiy
12449d67c943SAlexey Kardashevskiy rc = iommu_take_ownership(tbl);
12459d67c943SAlexey Kardashevskiy if (!rc)
12469d67c943SAlexey Kardashevskiy continue;
1247a9409044SAlexey Kardashevskiy
12489d67c943SAlexey Kardashevskiy for (j = 0; j < i; ++j)
12499d67c943SAlexey Kardashevskiy iommu_release_ownership(table_group->tables[j]);
12509d67c943SAlexey Kardashevskiy return rc;
12519d67c943SAlexey Kardashevskiy }
12529d67c943SAlexey Kardashevskiy return 0;
12539d67c943SAlexey Kardashevskiy }
12549d67c943SAlexey Kardashevskiy
spapr_tce_release_ownership(struct iommu_table_group * table_group)12559d67c943SAlexey Kardashevskiy static void spapr_tce_release_ownership(struct iommu_table_group *table_group)
12569d67c943SAlexey Kardashevskiy {
12579d67c943SAlexey Kardashevskiy int i;
12589d67c943SAlexey Kardashevskiy
12599d67c943SAlexey Kardashevskiy for (i = 0; i < IOMMU_TABLE_GROUP_MAX_TABLES; ++i) {
12609d67c943SAlexey Kardashevskiy struct iommu_table *tbl = table_group->tables[i];
12619d67c943SAlexey Kardashevskiy
12629d67c943SAlexey Kardashevskiy if (!tbl)
12639d67c943SAlexey Kardashevskiy continue;
12649d67c943SAlexey Kardashevskiy
12659d67c943SAlexey Kardashevskiy iommu_table_clear(tbl);
12669d67c943SAlexey Kardashevskiy if (tbl->it_map)
12679d67c943SAlexey Kardashevskiy iommu_release_ownership(tbl);
12689d67c943SAlexey Kardashevskiy }
12699d67c943SAlexey Kardashevskiy }
12709d67c943SAlexey Kardashevskiy
12719d67c943SAlexey Kardashevskiy struct iommu_table_group_ops spapr_tce_table_group_ops = {
12729d67c943SAlexey Kardashevskiy .get_table_size = spapr_tce_get_table_size,
12739d67c943SAlexey Kardashevskiy .create_table = spapr_tce_create_table,
12749d67c943SAlexey Kardashevskiy .set_window = spapr_tce_set_window,
12759d67c943SAlexey Kardashevskiy .unset_window = spapr_tce_unset_window,
12769d67c943SAlexey Kardashevskiy .take_ownership = spapr_tce_take_ownership,
12779d67c943SAlexey Kardashevskiy .release_ownership = spapr_tce_release_ownership,
12789d67c943SAlexey Kardashevskiy };
12799d67c943SAlexey Kardashevskiy
1280a9409044SAlexey Kardashevskiy /*
1281a9409044SAlexey Kardashevskiy * A simple iommu_ops to allow less cruft in generic VFIO code.
1282a9409044SAlexey Kardashevskiy */
spapr_tce_blocking_iommu_attach_dev(struct iommu_domain * dom,struct device * dev)1283a9409044SAlexey Kardashevskiy static int spapr_tce_blocking_iommu_attach_dev(struct iommu_domain *dom,
1284a9409044SAlexey Kardashevskiy struct device *dev)
1285a9409044SAlexey Kardashevskiy {
1286a9409044SAlexey Kardashevskiy struct iommu_group *grp = iommu_group_get(dev);
1287a9409044SAlexey Kardashevskiy struct iommu_table_group *table_group;
1288a9409044SAlexey Kardashevskiy int ret = -EINVAL;
1289a9409044SAlexey Kardashevskiy
1290a9409044SAlexey Kardashevskiy if (!grp)
1291a9409044SAlexey Kardashevskiy return -ENODEV;
1292a9409044SAlexey Kardashevskiy
1293a9409044SAlexey Kardashevskiy table_group = iommu_group_get_iommudata(grp);
1294a9409044SAlexey Kardashevskiy ret = table_group->ops->take_ownership(table_group);
1295a9409044SAlexey Kardashevskiy iommu_group_put(grp);
1296a9409044SAlexey Kardashevskiy
1297a9409044SAlexey Kardashevskiy return ret;
1298a9409044SAlexey Kardashevskiy }
1299a9409044SAlexey Kardashevskiy
spapr_tce_blocking_iommu_set_platform_dma(struct device * dev)1300a9409044SAlexey Kardashevskiy static void spapr_tce_blocking_iommu_set_platform_dma(struct device *dev)
1301a9409044SAlexey Kardashevskiy {
1302a9409044SAlexey Kardashevskiy struct iommu_group *grp = iommu_group_get(dev);
1303a9409044SAlexey Kardashevskiy struct iommu_table_group *table_group;
1304a9409044SAlexey Kardashevskiy
1305a9409044SAlexey Kardashevskiy table_group = iommu_group_get_iommudata(grp);
1306a9409044SAlexey Kardashevskiy table_group->ops->release_ownership(table_group);
1307a9409044SAlexey Kardashevskiy }
1308a9409044SAlexey Kardashevskiy
1309a9409044SAlexey Kardashevskiy static const struct iommu_domain_ops spapr_tce_blocking_domain_ops = {
1310a9409044SAlexey Kardashevskiy .attach_dev = spapr_tce_blocking_iommu_attach_dev,
1311a9409044SAlexey Kardashevskiy };
1312a9409044SAlexey Kardashevskiy
spapr_tce_iommu_capable(struct device * dev,enum iommu_cap cap)1313a9409044SAlexey Kardashevskiy static bool spapr_tce_iommu_capable(struct device *dev, enum iommu_cap cap)
1314a9409044SAlexey Kardashevskiy {
1315a9409044SAlexey Kardashevskiy switch (cap) {
1316a9409044SAlexey Kardashevskiy case IOMMU_CAP_CACHE_COHERENCY:
1317a9409044SAlexey Kardashevskiy return true;
1318a9409044SAlexey Kardashevskiy default:
1319a9409044SAlexey Kardashevskiy break;
1320a9409044SAlexey Kardashevskiy }
1321a9409044SAlexey Kardashevskiy
1322a9409044SAlexey Kardashevskiy return false;
1323a9409044SAlexey Kardashevskiy }
1324a9409044SAlexey Kardashevskiy
spapr_tce_iommu_domain_alloc(unsigned int type)1325a9409044SAlexey Kardashevskiy static struct iommu_domain *spapr_tce_iommu_domain_alloc(unsigned int type)
1326a9409044SAlexey Kardashevskiy {
1327a9409044SAlexey Kardashevskiy struct iommu_domain *dom;
1328a9409044SAlexey Kardashevskiy
1329a9409044SAlexey Kardashevskiy if (type != IOMMU_DOMAIN_BLOCKED)
1330a9409044SAlexey Kardashevskiy return NULL;
1331a9409044SAlexey Kardashevskiy
1332a9409044SAlexey Kardashevskiy dom = kzalloc(sizeof(*dom), GFP_KERNEL);
1333a9409044SAlexey Kardashevskiy if (!dom)
1334a9409044SAlexey Kardashevskiy return NULL;
1335a9409044SAlexey Kardashevskiy
1336a9409044SAlexey Kardashevskiy dom->ops = &spapr_tce_blocking_domain_ops;
1337a9409044SAlexey Kardashevskiy
1338a9409044SAlexey Kardashevskiy return dom;
1339a9409044SAlexey Kardashevskiy }
1340a9409044SAlexey Kardashevskiy
spapr_tce_iommu_probe_device(struct device * dev)1341a9409044SAlexey Kardashevskiy static struct iommu_device *spapr_tce_iommu_probe_device(struct device *dev)
1342a9409044SAlexey Kardashevskiy {
1343a9409044SAlexey Kardashevskiy struct pci_dev *pdev;
1344a9409044SAlexey Kardashevskiy struct pci_controller *hose;
1345a9409044SAlexey Kardashevskiy
1346a9409044SAlexey Kardashevskiy if (!dev_is_pci(dev))
1347*b8315b2eSGaurav Batra return ERR_PTR(-ENODEV);
1348a9409044SAlexey Kardashevskiy
1349a9409044SAlexey Kardashevskiy pdev = to_pci_dev(dev);
1350a9409044SAlexey Kardashevskiy hose = pdev->bus->sysdata;
1351a9409044SAlexey Kardashevskiy
1352a9409044SAlexey Kardashevskiy return &hose->iommu;
1353a9409044SAlexey Kardashevskiy }
1354a9409044SAlexey Kardashevskiy
spapr_tce_iommu_release_device(struct device * dev)1355a9409044SAlexey Kardashevskiy static void spapr_tce_iommu_release_device(struct device *dev)
1356a9409044SAlexey Kardashevskiy {
1357a9409044SAlexey Kardashevskiy }
1358a9409044SAlexey Kardashevskiy
spapr_tce_iommu_device_group(struct device * dev)1359a9409044SAlexey Kardashevskiy static struct iommu_group *spapr_tce_iommu_device_group(struct device *dev)
1360a9409044SAlexey Kardashevskiy {
1361a9409044SAlexey Kardashevskiy struct pci_controller *hose;
1362a9409044SAlexey Kardashevskiy struct pci_dev *pdev;
1363a9409044SAlexey Kardashevskiy
1364a9409044SAlexey Kardashevskiy pdev = to_pci_dev(dev);
1365a9409044SAlexey Kardashevskiy hose = pdev->bus->sysdata;
1366a9409044SAlexey Kardashevskiy
1367a9409044SAlexey Kardashevskiy if (!hose->controller_ops.device_group)
1368a9409044SAlexey Kardashevskiy return ERR_PTR(-ENOENT);
1369a9409044SAlexey Kardashevskiy
1370a9409044SAlexey Kardashevskiy return hose->controller_ops.device_group(hose, pdev);
1371a9409044SAlexey Kardashevskiy }
1372a9409044SAlexey Kardashevskiy
1373a9409044SAlexey Kardashevskiy static const struct iommu_ops spapr_tce_iommu_ops = {
1374a9409044SAlexey Kardashevskiy .capable = spapr_tce_iommu_capable,
1375a9409044SAlexey Kardashevskiy .domain_alloc = spapr_tce_iommu_domain_alloc,
1376a9409044SAlexey Kardashevskiy .probe_device = spapr_tce_iommu_probe_device,
1377a9409044SAlexey Kardashevskiy .release_device = spapr_tce_iommu_release_device,
1378a9409044SAlexey Kardashevskiy .device_group = spapr_tce_iommu_device_group,
1379a9409044SAlexey Kardashevskiy .set_platform_dma_ops = spapr_tce_blocking_iommu_set_platform_dma,
1380a9409044SAlexey Kardashevskiy };
1381a9409044SAlexey Kardashevskiy
1382a9409044SAlexey Kardashevskiy static struct attribute *spapr_tce_iommu_attrs[] = {
1383a9409044SAlexey Kardashevskiy NULL,
1384a9409044SAlexey Kardashevskiy };
1385a9409044SAlexey Kardashevskiy
1386a9409044SAlexey Kardashevskiy static struct attribute_group spapr_tce_iommu_group = {
1387a9409044SAlexey Kardashevskiy .name = "spapr-tce-iommu",
1388a9409044SAlexey Kardashevskiy .attrs = spapr_tce_iommu_attrs,
1389a9409044SAlexey Kardashevskiy };
1390a9409044SAlexey Kardashevskiy
1391a9409044SAlexey Kardashevskiy static const struct attribute_group *spapr_tce_iommu_groups[] = {
1392a9409044SAlexey Kardashevskiy &spapr_tce_iommu_group,
1393a9409044SAlexey Kardashevskiy NULL,
1394a9409044SAlexey Kardashevskiy };
1395a9409044SAlexey Kardashevskiy
ppc_iommu_register_device(struct pci_controller * phb)1396*b8315b2eSGaurav Batra void ppc_iommu_register_device(struct pci_controller *phb)
1397*b8315b2eSGaurav Batra {
1398*b8315b2eSGaurav Batra iommu_device_sysfs_add(&phb->iommu, phb->parent,
1399*b8315b2eSGaurav Batra spapr_tce_iommu_groups, "iommu-phb%04x",
1400*b8315b2eSGaurav Batra phb->global_number);
1401*b8315b2eSGaurav Batra iommu_device_register(&phb->iommu, &spapr_tce_iommu_ops,
1402*b8315b2eSGaurav Batra phb->parent);
1403*b8315b2eSGaurav Batra }
1404*b8315b2eSGaurav Batra
ppc_iommu_unregister_device(struct pci_controller * phb)1405*b8315b2eSGaurav Batra void ppc_iommu_unregister_device(struct pci_controller *phb)
1406*b8315b2eSGaurav Batra {
1407*b8315b2eSGaurav Batra iommu_device_unregister(&phb->iommu);
1408*b8315b2eSGaurav Batra iommu_device_sysfs_remove(&phb->iommu);
1409*b8315b2eSGaurav Batra }
1410*b8315b2eSGaurav Batra
1411a9409044SAlexey Kardashevskiy /*
1412a9409044SAlexey Kardashevskiy * This registers IOMMU devices of PHBs. This needs to happen
1413a9409044SAlexey Kardashevskiy * after core_initcall(iommu_init) + postcore_initcall(pci_driver_init) and
1414a9409044SAlexey Kardashevskiy * before subsys_initcall(iommu_subsys_init).
1415a9409044SAlexey Kardashevskiy */
spapr_tce_setup_phb_iommus_initcall(void)1416a9409044SAlexey Kardashevskiy static int __init spapr_tce_setup_phb_iommus_initcall(void)
1417a9409044SAlexey Kardashevskiy {
1418a9409044SAlexey Kardashevskiy struct pci_controller *hose;
1419a9409044SAlexey Kardashevskiy
1420a9409044SAlexey Kardashevskiy list_for_each_entry(hose, &hose_list, list_node) {
1421*b8315b2eSGaurav Batra ppc_iommu_register_device(hose);
1422a9409044SAlexey Kardashevskiy }
1423a9409044SAlexey Kardashevskiy return 0;
1424a9409044SAlexey Kardashevskiy }
1425a9409044SAlexey Kardashevskiy postcore_initcall_sync(spapr_tce_setup_phb_iommus_initcall);
1426bfd8d989STimothy Pearson #endif
1427a9409044SAlexey Kardashevskiy
14284e13c1acSAlexey Kardashevskiy #endif /* CONFIG_IOMMU_API */
1429