blob: 70c748a5fbcc29fe1a285e0416e86852a2e5bc90 [file] [log] [blame]
Alexey Kardashevskiy5ffd2292013-05-21 13:33:10 +10001/*
2 * VFIO: IOMMU DMA mapping support for TCE on POWER
3 *
4 * Copyright (C) 2013 IBM Corp. All rights reserved.
5 * Author: Alexey Kardashevskiy <aik@ozlabs.ru>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 * Derived from original vfio_iommu_type1.c:
12 * Copyright (C) 2012 Red Hat, Inc. All rights reserved.
13 * Author: Alex Williamson <alex.williamson@redhat.com>
14 */
15
16#include <linux/module.h>
17#include <linux/pci.h>
18#include <linux/slab.h>
19#include <linux/uaccess.h>
20#include <linux/err.h>
21#include <linux/vfio.h>
Alexey Kardashevskiy2157e7b2015-06-05 16:35:25 +100022#include <linux/vmalloc.h>
Alexey Kardashevskiy5ffd2292013-05-21 13:33:10 +100023#include <asm/iommu.h>
24#include <asm/tce.h>
Alexey Kardashevskiy2157e7b2015-06-05 16:35:25 +100025#include <asm/mmu_context.h>
Alexey Kardashevskiy5ffd2292013-05-21 13:33:10 +100026
27#define DRIVER_VERSION "0.1"
28#define DRIVER_AUTHOR "aik@ozlabs.ru"
29#define DRIVER_DESC "VFIO IOMMU SPAPR TCE"
30
31static void tce_iommu_detach_group(void *iommu_data,
32 struct iommu_group *iommu_group);
33
Alexey Kardashevskiy92e44bc2017-03-17 00:48:27 +000034static long try_increment_locked_vm(struct mm_struct *mm, long npages)
Alexey Kardashevskiy2d270df2015-06-05 16:35:01 +100035{
36 long ret = 0, locked, lock_limit;
37
Alexey Kardashevskiy92e44bc2017-03-17 00:48:27 +000038 if (WARN_ON_ONCE(!mm))
39 return -EPERM;
Alexey Kardashevskiy2d270df2015-06-05 16:35:01 +100040
41 if (!npages)
42 return 0;
43
Alexey Kardashevskiy92e44bc2017-03-17 00:48:27 +000044 down_write(&mm->mmap_sem);
45 locked = mm->locked_vm + npages;
Alexey Kardashevskiy2d270df2015-06-05 16:35:01 +100046 lock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
47 if (locked > lock_limit && !capable(CAP_IPC_LOCK))
48 ret = -ENOMEM;
49 else
Alexey Kardashevskiy92e44bc2017-03-17 00:48:27 +000050 mm->locked_vm += npages;
Alexey Kardashevskiy2d270df2015-06-05 16:35:01 +100051
52 pr_debug("[%d] RLIMIT_MEMLOCK +%ld %ld/%ld%s\n", current->pid,
53 npages << PAGE_SHIFT,
Alexey Kardashevskiy92e44bc2017-03-17 00:48:27 +000054 mm->locked_vm << PAGE_SHIFT,
Alexey Kardashevskiy2d270df2015-06-05 16:35:01 +100055 rlimit(RLIMIT_MEMLOCK),
56 ret ? " - exceeded" : "");
57
Alexey Kardashevskiy92e44bc2017-03-17 00:48:27 +000058 up_write(&mm->mmap_sem);
Alexey Kardashevskiy2d270df2015-06-05 16:35:01 +100059
60 return ret;
61}
62
Alexey Kardashevskiy92e44bc2017-03-17 00:48:27 +000063static void decrement_locked_vm(struct mm_struct *mm, long npages)
Alexey Kardashevskiy2d270df2015-06-05 16:35:01 +100064{
Alexey Kardashevskiy92e44bc2017-03-17 00:48:27 +000065 if (!mm || !npages)
66 return;
Alexey Kardashevskiy2d270df2015-06-05 16:35:01 +100067
Alexey Kardashevskiy92e44bc2017-03-17 00:48:27 +000068 down_write(&mm->mmap_sem);
69 if (WARN_ON_ONCE(npages > mm->locked_vm))
70 npages = mm->locked_vm;
71 mm->locked_vm -= npages;
Alexey Kardashevskiy2d270df2015-06-05 16:35:01 +100072 pr_debug("[%d] RLIMIT_MEMLOCK -%ld %ld/%ld\n", current->pid,
73 npages << PAGE_SHIFT,
Alexey Kardashevskiy92e44bc2017-03-17 00:48:27 +000074 mm->locked_vm << PAGE_SHIFT,
Alexey Kardashevskiy2d270df2015-06-05 16:35:01 +100075 rlimit(RLIMIT_MEMLOCK));
Alexey Kardashevskiy92e44bc2017-03-17 00:48:27 +000076 up_write(&mm->mmap_sem);
Alexey Kardashevskiy2d270df2015-06-05 16:35:01 +100077}
78
Alexey Kardashevskiy5ffd2292013-05-21 13:33:10 +100079/*
80 * VFIO IOMMU fd for SPAPR_TCE IOMMU implementation
81 *
82 * This code handles mapping and unmapping of user data buffers
83 * into DMA'ble space using the IOMMU
84 */
85
Alexey Kardashevskiy2157e7b2015-06-05 16:35:25 +100086struct tce_iommu_group {
87 struct list_head next;
88 struct iommu_group *grp;
89};
90
Alexey Kardashevskiy5ffd2292013-05-21 13:33:10 +100091/*
Alexey Kardashevskiy080eb132017-03-17 00:48:27 +000092 * A container needs to remember which preregistered region it has
93 * referenced to do proper cleanup at the userspace process exit.
94 */
95struct tce_iommu_prereg {
96 struct list_head next;
97 struct mm_iommu_table_group_mem_t *mem;
98};
99
100/*
Alexey Kardashevskiy5ffd2292013-05-21 13:33:10 +1000101 * The container descriptor supports only a single group per container.
102 * Required by the API as the container is not supplied with the IOMMU group
103 * at the moment of initialization.
104 */
105struct tce_container {
106 struct mutex lock;
Alexey Kardashevskiy5ffd2292013-05-21 13:33:10 +1000107 bool enabled;
Alexey Kardashevskiy2157e7b2015-06-05 16:35:25 +1000108 bool v2;
Alexey Kardashevskiy53e18962017-03-17 00:48:29 +0000109 bool def_window_pending;
Alexey Kardashevskiy2d270df2015-06-05 16:35:01 +1000110 unsigned long locked_pages;
Alexey Kardashevskiy92e44bc2017-03-17 00:48:27 +0000111 struct mm_struct *mm;
Alexey Kardashevskiy2157e7b2015-06-05 16:35:25 +1000112 struct iommu_table *tables[IOMMU_TABLE_GROUP_MAX_TABLES];
113 struct list_head group_list;
Alexey Kardashevskiy080eb132017-03-17 00:48:27 +0000114 struct list_head prereg_list;
Alexey Kardashevskiy5ffd2292013-05-21 13:33:10 +1000115};
116
Alexey Kardashevskiy92e44bc2017-03-17 00:48:27 +0000117static long tce_iommu_mm_set(struct tce_container *container)
118{
119 if (container->mm) {
120 if (container->mm == current->mm)
121 return 0;
122 return -EPERM;
123 }
124 BUG_ON(!current->mm);
125 container->mm = current->mm;
126 atomic_inc(&container->mm->mm_count);
127
128 return 0;
129}
130
Alexey Kardashevskiy080eb132017-03-17 00:48:27 +0000131static long tce_iommu_prereg_free(struct tce_container *container,
132 struct tce_iommu_prereg *tcemem)
133{
134 long ret;
135
136 ret = mm_iommu_put(container->mm, tcemem->mem);
137 if (ret)
138 return ret;
139
140 list_del(&tcemem->next);
141 kfree(tcemem);
142
143 return 0;
144}
145
Alexey Kardashevskiy2157e7b2015-06-05 16:35:25 +1000146static long tce_iommu_unregister_pages(struct tce_container *container,
147 __u64 vaddr, __u64 size)
148{
149 struct mm_iommu_table_group_mem_t *mem;
Alexey Kardashevskiy080eb132017-03-17 00:48:27 +0000150 struct tce_iommu_prereg *tcemem;
151 bool found = false;
Alexey Kardashevskiy2157e7b2015-06-05 16:35:25 +1000152
153 if ((vaddr & ~PAGE_MASK) || (size & ~PAGE_MASK))
154 return -EINVAL;
155
Alexey Kardashevskiy92e44bc2017-03-17 00:48:27 +0000156 mem = mm_iommu_find(container->mm, vaddr, size >> PAGE_SHIFT);
Alexey Kardashevskiy2157e7b2015-06-05 16:35:25 +1000157 if (!mem)
158 return -ENOENT;
159
Alexey Kardashevskiy080eb132017-03-17 00:48:27 +0000160 list_for_each_entry(tcemem, &container->prereg_list, next) {
161 if (tcemem->mem == mem) {
162 found = true;
163 break;
164 }
165 }
166
167 if (!found)
168 return -ENOENT;
169
170 return tce_iommu_prereg_free(container, tcemem);
Alexey Kardashevskiy2157e7b2015-06-05 16:35:25 +1000171}
172
173static long tce_iommu_register_pages(struct tce_container *container,
174 __u64 vaddr, __u64 size)
175{
176 long ret = 0;
177 struct mm_iommu_table_group_mem_t *mem = NULL;
Alexey Kardashevskiy080eb132017-03-17 00:48:27 +0000178 struct tce_iommu_prereg *tcemem;
Alexey Kardashevskiy2157e7b2015-06-05 16:35:25 +1000179 unsigned long entries = size >> PAGE_SHIFT;
180
181 if ((vaddr & ~PAGE_MASK) || (size & ~PAGE_MASK) ||
182 ((vaddr + size) < vaddr))
183 return -EINVAL;
184
Alexey Kardashevskiy080eb132017-03-17 00:48:27 +0000185 mem = mm_iommu_find(container->mm, vaddr, entries);
186 if (mem) {
187 list_for_each_entry(tcemem, &container->prereg_list, next) {
188 if (tcemem->mem == mem)
189 return -EBUSY;
190 }
191 }
192
Alexey Kardashevskiy92e44bc2017-03-17 00:48:27 +0000193 ret = mm_iommu_get(container->mm, vaddr, entries, &mem);
Alexey Kardashevskiy2157e7b2015-06-05 16:35:25 +1000194 if (ret)
195 return ret;
196
Alexey Kardashevskiy080eb132017-03-17 00:48:27 +0000197 tcemem = kzalloc(sizeof(*tcemem), GFP_KERNEL);
Alexey Kardashevskiybab8ac12017-03-27 14:23:40 +1100198 if (!tcemem) {
199 mm_iommu_put(container->mm, mem);
200 return -ENOMEM;
201 }
202
Alexey Kardashevskiy080eb132017-03-17 00:48:27 +0000203 tcemem->mem = mem;
204 list_add(&tcemem->next, &container->prereg_list);
205
Alexey Kardashevskiy2157e7b2015-06-05 16:35:25 +1000206 container->enabled = true;
207
208 return 0;
209}
210
Alexey Kardashevskiy92e44bc2017-03-17 00:48:27 +0000211static long tce_iommu_userspace_view_alloc(struct iommu_table *tbl,
212 struct mm_struct *mm)
Alexey Kardashevskiy2157e7b2015-06-05 16:35:25 +1000213{
214 unsigned long cb = _ALIGN_UP(sizeof(tbl->it_userspace[0]) *
215 tbl->it_size, PAGE_SIZE);
216 unsigned long *uas;
217 long ret;
218
219 BUG_ON(tbl->it_userspace);
220
Alexey Kardashevskiy92e44bc2017-03-17 00:48:27 +0000221 ret = try_increment_locked_vm(mm, cb >> PAGE_SHIFT);
Alexey Kardashevskiy2157e7b2015-06-05 16:35:25 +1000222 if (ret)
223 return ret;
224
225 uas = vzalloc(cb);
226 if (!uas) {
Alexey Kardashevskiy92e44bc2017-03-17 00:48:27 +0000227 decrement_locked_vm(mm, cb >> PAGE_SHIFT);
Alexey Kardashevskiy2157e7b2015-06-05 16:35:25 +1000228 return -ENOMEM;
229 }
230 tbl->it_userspace = uas;
231
232 return 0;
233}
234
Alexey Kardashevskiy92e44bc2017-03-17 00:48:27 +0000235static void tce_iommu_userspace_view_free(struct iommu_table *tbl,
236 struct mm_struct *mm)
Alexey Kardashevskiy2157e7b2015-06-05 16:35:25 +1000237{
238 unsigned long cb = _ALIGN_UP(sizeof(tbl->it_userspace[0]) *
239 tbl->it_size, PAGE_SIZE);
240
241 if (!tbl->it_userspace)
242 return;
243
244 vfree(tbl->it_userspace);
245 tbl->it_userspace = NULL;
Alexey Kardashevskiy92e44bc2017-03-17 00:48:27 +0000246 decrement_locked_vm(mm, cb >> PAGE_SHIFT);
Alexey Kardashevskiy2157e7b2015-06-05 16:35:25 +1000247}
248
Alexey Kardashevskiye432bc72015-06-05 16:34:59 +1000249static bool tce_page_is_contained(struct page *page, unsigned page_shift)
250{
251 /*
252 * Check that the TCE table granularity is not bigger than the size of
253 * a page we just found. Otherwise the hardware can get access to
254 * a bigger memory chunk that it should.
255 */
256 return (PAGE_SHIFT + compound_order(compound_head(page))) >= page_shift;
257}
258
Alexey Kardashevskiy2157e7b2015-06-05 16:35:25 +1000259static inline bool tce_groups_attached(struct tce_container *container)
260{
261 return !list_empty(&container->group_list);
262}
263
Alexey Kardashevskiy0eaf4de2015-06-05 16:35:09 +1000264static long tce_iommu_find_table(struct tce_container *container,
265 phys_addr_t ioba, struct iommu_table **ptbl)
266{
267 long i;
Alexey Kardashevskiy0eaf4de2015-06-05 16:35:09 +1000268
269 for (i = 0; i < IOMMU_TABLE_GROUP_MAX_TABLES; ++i) {
Alexey Kardashevskiy2157e7b2015-06-05 16:35:25 +1000270 struct iommu_table *tbl = container->tables[i];
Alexey Kardashevskiy0eaf4de2015-06-05 16:35:09 +1000271
272 if (tbl) {
273 unsigned long entry = ioba >> tbl->it_page_shift;
274 unsigned long start = tbl->it_offset;
275 unsigned long end = start + tbl->it_size;
276
277 if ((start <= entry) && (entry < end)) {
278 *ptbl = tbl;
279 return i;
280 }
281 }
282 }
283
284 return -1;
285}
286
Alexey Kardashevskiye633bc82015-06-05 16:35:26 +1000287static int tce_iommu_find_free_table(struct tce_container *container)
288{
289 int i;
290
291 for (i = 0; i < IOMMU_TABLE_GROUP_MAX_TABLES; ++i) {
292 if (!container->tables[i])
293 return i;
294 }
295
296 return -ENOSPC;
297}
298
Alexey Kardashevskiy5ffd2292013-05-21 13:33:10 +1000299static int tce_iommu_enable(struct tce_container *container)
300{
301 int ret = 0;
Alexey Kardashevskiy2d270df2015-06-05 16:35:01 +1000302 unsigned long locked;
Alexey Kardashevskiy0eaf4de2015-06-05 16:35:09 +1000303 struct iommu_table_group *table_group;
Alexey Kardashevskiy2157e7b2015-06-05 16:35:25 +1000304 struct tce_iommu_group *tcegrp;
Alexey Kardashevskiy5ffd2292013-05-21 13:33:10 +1000305
Alexey Kardashevskiy5ffd2292013-05-21 13:33:10 +1000306 if (container->enabled)
307 return -EBUSY;
308
309 /*
310 * When userspace pages are mapped into the IOMMU, they are effectively
311 * locked memory, so, theoretically, we need to update the accounting
312 * of locked pages on each map and unmap. For powerpc, the map unmap
313 * paths can be very hot, though, and the accounting would kill
314 * performance, especially since it would be difficult to impossible
315 * to handle the accounting in real mode only.
316 *
317 * To address that, rather than precisely accounting every page, we
318 * instead account for a worst case on locked memory when the iommu is
319 * enabled and disabled. The worst case upper bound on locked memory
320 * is the size of the whole iommu window, which is usually relatively
321 * small (compared to total memory sizes) on POWER hardware.
322 *
323 * Also we don't have a nice way to fail on H_PUT_TCE due to ulimits,
324 * that would effectively kill the guest at random points, much better
325 * enforcing the limit based on the max that the guest can map.
Alexey Kardashevskiy2d270df2015-06-05 16:35:01 +1000326 *
327 * Unfortunately at the moment it counts whole tables, no matter how
328 * much memory the guest has. I.e. for 4GB guest and 4 IOMMU groups
329 * each with 2GB DMA window, 8GB will be counted here. The reason for
330 * this is that we cannot tell here the amount of RAM used by the guest
331 * as this information is only available from KVM and VFIO is
332 * KVM agnostic.
Alexey Kardashevskiy4793d652015-06-05 16:35:20 +1000333 *
334 * So we do not allow enabling a container without a group attached
335 * as there is no way to know how much we should increment
336 * the locked_vm counter.
Alexey Kardashevskiy5ffd2292013-05-21 13:33:10 +1000337 */
Alexey Kardashevskiy2157e7b2015-06-05 16:35:25 +1000338 if (!tce_groups_attached(container))
339 return -ENODEV;
340
341 tcegrp = list_first_entry(&container->group_list,
342 struct tce_iommu_group, next);
343 table_group = iommu_group_get_iommudata(tcegrp->grp);
Alexey Kardashevskiy0eaf4de2015-06-05 16:35:09 +1000344 if (!table_group)
345 return -ENODEV;
346
Alexey Kardashevskiy4793d652015-06-05 16:35:20 +1000347 if (!table_group->tce32_size)
348 return -EPERM;
349
Alexey Kardashevskiy92e44bc2017-03-17 00:48:27 +0000350 ret = tce_iommu_mm_set(container);
351 if (ret)
352 return ret;
353
Alexey Kardashevskiy4793d652015-06-05 16:35:20 +1000354 locked = table_group->tce32_size >> PAGE_SHIFT;
Alexey Kardashevskiy92e44bc2017-03-17 00:48:27 +0000355 ret = try_increment_locked_vm(container->mm, locked);
Alexey Kardashevskiy2d270df2015-06-05 16:35:01 +1000356 if (ret)
357 return ret;
Alexey Kardashevskiy5ffd2292013-05-21 13:33:10 +1000358
Alexey Kardashevskiy2d270df2015-06-05 16:35:01 +1000359 container->locked_pages = locked;
360
361 container->enabled = true;
Alexey Kardashevskiy5ffd2292013-05-21 13:33:10 +1000362
363 return ret;
364}
365
366static void tce_iommu_disable(struct tce_container *container)
367{
368 if (!container->enabled)
369 return;
370
371 container->enabled = false;
372
Alexey Kardashevskiy92e44bc2017-03-17 00:48:27 +0000373 BUG_ON(!container->mm);
374 decrement_locked_vm(container->mm, container->locked_pages);
Alexey Kardashevskiy5ffd2292013-05-21 13:33:10 +1000375}
376
377static void *tce_iommu_open(unsigned long arg)
378{
379 struct tce_container *container;
380
Alexey Kardashevskiy2157e7b2015-06-05 16:35:25 +1000381 if ((arg != VFIO_SPAPR_TCE_IOMMU) && (arg != VFIO_SPAPR_TCE_v2_IOMMU)) {
Alexey Kardashevskiy5ffd2292013-05-21 13:33:10 +1000382 pr_err("tce_vfio: Wrong IOMMU type\n");
383 return ERR_PTR(-EINVAL);
384 }
385
386 container = kzalloc(sizeof(*container), GFP_KERNEL);
387 if (!container)
388 return ERR_PTR(-ENOMEM);
389
390 mutex_init(&container->lock);
Alexey Kardashevskiy2157e7b2015-06-05 16:35:25 +1000391 INIT_LIST_HEAD_RCU(&container->group_list);
Alexey Kardashevskiy080eb132017-03-17 00:48:27 +0000392 INIT_LIST_HEAD_RCU(&container->prereg_list);
Alexey Kardashevskiy2157e7b2015-06-05 16:35:25 +1000393
394 container->v2 = arg == VFIO_SPAPR_TCE_v2_IOMMU;
Alexey Kardashevskiy5ffd2292013-05-21 13:33:10 +1000395
396 return container;
397}
398
Alexey Kardashevskiy2157e7b2015-06-05 16:35:25 +1000399static int tce_iommu_clear(struct tce_container *container,
400 struct iommu_table *tbl,
401 unsigned long entry, unsigned long pages);
Alexey Kardashevskiy92e44bc2017-03-17 00:48:27 +0000402static void tce_iommu_free_table(struct tce_container *container,
403 struct iommu_table *tbl);
Alexey Kardashevskiy2157e7b2015-06-05 16:35:25 +1000404
Alexey Kardashevskiy5ffd2292013-05-21 13:33:10 +1000405static void tce_iommu_release(void *iommu_data)
406{
407 struct tce_container *container = iommu_data;
Alexey Kardashevskiy2157e7b2015-06-05 16:35:25 +1000408 struct tce_iommu_group *tcegrp;
409 long i;
Alexey Kardashevskiy5ffd2292013-05-21 13:33:10 +1000410
Alexey Kardashevskiy2157e7b2015-06-05 16:35:25 +1000411 while (tce_groups_attached(container)) {
412 tcegrp = list_first_entry(&container->group_list,
413 struct tce_iommu_group, next);
Alexey Kardashevskiy2157e7b2015-06-05 16:35:25 +1000414 tce_iommu_detach_group(iommu_data, tcegrp->grp);
415 }
Alexey Kardashevskiy5ffd2292013-05-21 13:33:10 +1000416
Alexey Kardashevskiy2157e7b2015-06-05 16:35:25 +1000417 /*
418 * If VFIO created a table, it was not disposed
419 * by tce_iommu_detach_group() so do it now.
420 */
421 for (i = 0; i < IOMMU_TABLE_GROUP_MAX_TABLES; ++i) {
422 struct iommu_table *tbl = container->tables[i];
423
424 if (!tbl)
425 continue;
426
427 tce_iommu_clear(container, tbl, tbl->it_offset, tbl->it_size);
Alexey Kardashevskiy92e44bc2017-03-17 00:48:27 +0000428 tce_iommu_free_table(container, tbl);
Alexey Kardashevskiy2157e7b2015-06-05 16:35:25 +1000429 }
Alexey Kardashevskiy5ffd2292013-05-21 13:33:10 +1000430
Alexey Kardashevskiy080eb132017-03-17 00:48:27 +0000431 while (!list_empty(&container->prereg_list)) {
432 struct tce_iommu_prereg *tcemem;
433
434 tcemem = list_first_entry(&container->prereg_list,
435 struct tce_iommu_prereg, next);
436 WARN_ON_ONCE(tce_iommu_prereg_free(container, tcemem));
437 }
438
Alexey Kardashevskiy649354b2015-06-05 16:35:03 +1000439 tce_iommu_disable(container);
Alexey Kardashevskiy92e44bc2017-03-17 00:48:27 +0000440 if (container->mm)
441 mmdrop(container->mm);
Alexey Kardashevskiy5ffd2292013-05-21 13:33:10 +1000442 mutex_destroy(&container->lock);
443
444 kfree(container);
445}
446
Alexey Kardashevskiy649354b2015-06-05 16:35:03 +1000447static void tce_iommu_unuse_page(struct tce_container *container,
Alexey Kardashevskiy05c6cfb2015-06-05 16:35:15 +1000448 unsigned long hpa)
Alexey Kardashevskiy649354b2015-06-05 16:35:03 +1000449{
450 struct page *page;
451
Alexey Kardashevskiy05c6cfb2015-06-05 16:35:15 +1000452 page = pfn_to_page(hpa >> PAGE_SHIFT);
Alexey Kardashevskiy649354b2015-06-05 16:35:03 +1000453 put_page(page);
454}
455
Alexey Kardashevskiy92e44bc2017-03-17 00:48:27 +0000456static int tce_iommu_prereg_ua_to_hpa(struct tce_container *container,
457 unsigned long tce, unsigned long size,
Alexey Kardashevskiy2157e7b2015-06-05 16:35:25 +1000458 unsigned long *phpa, struct mm_iommu_table_group_mem_t **pmem)
459{
460 long ret = 0;
461 struct mm_iommu_table_group_mem_t *mem;
462
Alexey Kardashevskiy92e44bc2017-03-17 00:48:27 +0000463 mem = mm_iommu_lookup(container->mm, tce, size);
Alexey Kardashevskiy2157e7b2015-06-05 16:35:25 +1000464 if (!mem)
465 return -EINVAL;
466
467 ret = mm_iommu_ua_to_hpa(mem, tce, phpa);
468 if (ret)
469 return -EINVAL;
470
471 *pmem = mem;
472
473 return 0;
474}
475
Alexey Kardashevskiy92e44bc2017-03-17 00:48:27 +0000476static void tce_iommu_unuse_page_v2(struct tce_container *container,
477 struct iommu_table *tbl, unsigned long entry)
Alexey Kardashevskiy2157e7b2015-06-05 16:35:25 +1000478{
479 struct mm_iommu_table_group_mem_t *mem = NULL;
480 int ret;
481 unsigned long hpa = 0;
482 unsigned long *pua = IOMMU_TABLE_USERSPACE_ENTRY(tbl, entry);
483
Alexey Kardashevskiy92e44bc2017-03-17 00:48:27 +0000484 if (!pua)
Alexey Kardashevskiy2157e7b2015-06-05 16:35:25 +1000485 return;
486
Alexey Kardashevskiy92e44bc2017-03-17 00:48:27 +0000487 ret = tce_iommu_prereg_ua_to_hpa(container, *pua, IOMMU_PAGE_SIZE(tbl),
Alexey Kardashevskiy2157e7b2015-06-05 16:35:25 +1000488 &hpa, &mem);
489 if (ret)
490 pr_debug("%s: tce %lx at #%lx was not cached, ret=%d\n",
491 __func__, *pua, entry, ret);
492 if (mem)
493 mm_iommu_mapped_dec(mem);
494
495 *pua = 0;
496}
497
Alexey Kardashevskiy9b14a1f2015-06-05 16:34:58 +1000498static int tce_iommu_clear(struct tce_container *container,
499 struct iommu_table *tbl,
500 unsigned long entry, unsigned long pages)
501{
Alexey Kardashevskiy05c6cfb2015-06-05 16:35:15 +1000502 unsigned long oldhpa;
503 long ret;
504 enum dma_data_direction direction;
Alexey Kardashevskiy9b14a1f2015-06-05 16:34:58 +1000505
506 for ( ; pages; --pages, ++entry) {
Alexey Kardashevskiy05c6cfb2015-06-05 16:35:15 +1000507 direction = DMA_NONE;
508 oldhpa = 0;
509 ret = iommu_tce_xchg(tbl, entry, &oldhpa, &direction);
510 if (ret)
Alexey Kardashevskiy9b14a1f2015-06-05 16:34:58 +1000511 continue;
512
Alexey Kardashevskiy05c6cfb2015-06-05 16:35:15 +1000513 if (direction == DMA_NONE)
514 continue;
515
Alexey Kardashevskiy2157e7b2015-06-05 16:35:25 +1000516 if (container->v2) {
Alexey Kardashevskiy92e44bc2017-03-17 00:48:27 +0000517 tce_iommu_unuse_page_v2(container, tbl, entry);
Alexey Kardashevskiy2157e7b2015-06-05 16:35:25 +1000518 continue;
519 }
520
Alexey Kardashevskiy05c6cfb2015-06-05 16:35:15 +1000521 tce_iommu_unuse_page(container, oldhpa);
Alexey Kardashevskiy9b14a1f2015-06-05 16:34:58 +1000522 }
523
524 return 0;
525}
526
Alexey Kardashevskiy649354b2015-06-05 16:35:03 +1000527static int tce_iommu_use_page(unsigned long tce, unsigned long *hpa)
528{
529 struct page *page = NULL;
530 enum dma_data_direction direction = iommu_tce_direction(tce);
531
532 if (get_user_pages_fast(tce & PAGE_MASK, 1,
533 direction != DMA_TO_DEVICE, &page) != 1)
534 return -EFAULT;
535
536 *hpa = __pa((unsigned long) page_address(page));
537
538 return 0;
539}
540
Alexey Kardashevskiy9b14a1f2015-06-05 16:34:58 +1000541static long tce_iommu_build(struct tce_container *container,
542 struct iommu_table *tbl,
Alexey Kardashevskiy05c6cfb2015-06-05 16:35:15 +1000543 unsigned long entry, unsigned long tce, unsigned long pages,
544 enum dma_data_direction direction)
Alexey Kardashevskiy9b14a1f2015-06-05 16:34:58 +1000545{
546 long i, ret = 0;
Alexey Kardashevskiy649354b2015-06-05 16:35:03 +1000547 struct page *page;
548 unsigned long hpa;
Alexey Kardashevskiy05c6cfb2015-06-05 16:35:15 +1000549 enum dma_data_direction dirtmp;
Alexey Kardashevskiy9b14a1f2015-06-05 16:34:58 +1000550
551 for (i = 0; i < pages; ++i) {
552 unsigned long offset = tce & IOMMU_PAGE_MASK(tbl) & ~PAGE_MASK;
553
Alexey Kardashevskiy649354b2015-06-05 16:35:03 +1000554 ret = tce_iommu_use_page(tce, &hpa);
555 if (ret)
Alexey Kardashevskiy9b14a1f2015-06-05 16:34:58 +1000556 break;
Alexey Kardashevskiye432bc72015-06-05 16:34:59 +1000557
Alexey Kardashevskiy649354b2015-06-05 16:35:03 +1000558 page = pfn_to_page(hpa >> PAGE_SHIFT);
Alexey Kardashevskiye432bc72015-06-05 16:34:59 +1000559 if (!tce_page_is_contained(page, tbl->it_page_shift)) {
560 ret = -EPERM;
561 break;
562 }
563
Alexey Kardashevskiy649354b2015-06-05 16:35:03 +1000564 hpa |= offset;
Alexey Kardashevskiy05c6cfb2015-06-05 16:35:15 +1000565 dirtmp = direction;
566 ret = iommu_tce_xchg(tbl, entry + i, &hpa, &dirtmp);
Alexey Kardashevskiy9b14a1f2015-06-05 16:34:58 +1000567 if (ret) {
Alexey Kardashevskiy649354b2015-06-05 16:35:03 +1000568 tce_iommu_unuse_page(container, hpa);
Alexey Kardashevskiy9b14a1f2015-06-05 16:34:58 +1000569 pr_err("iommu_tce: %s failed ioba=%lx, tce=%lx, ret=%ld\n",
570 __func__, entry << tbl->it_page_shift,
571 tce, ret);
572 break;
573 }
Alexey Kardashevskiy05c6cfb2015-06-05 16:35:15 +1000574
575 if (dirtmp != DMA_NONE)
576 tce_iommu_unuse_page(container, hpa);
577
Alexey Kardashevskiy00663d42015-06-05 16:35:00 +1000578 tce += IOMMU_PAGE_SIZE(tbl);
Alexey Kardashevskiy9b14a1f2015-06-05 16:34:58 +1000579 }
580
581 if (ret)
582 tce_iommu_clear(container, tbl, entry, i);
583
584 return ret;
585}
586
Alexey Kardashevskiy2157e7b2015-06-05 16:35:25 +1000587static long tce_iommu_build_v2(struct tce_container *container,
588 struct iommu_table *tbl,
589 unsigned long entry, unsigned long tce, unsigned long pages,
590 enum dma_data_direction direction)
591{
592 long i, ret = 0;
593 struct page *page;
594 unsigned long hpa;
595 enum dma_data_direction dirtmp;
596
Alexey Kardashevskiy5d8b3e72017-03-17 00:48:26 +0000597 if (!tbl->it_userspace) {
Alexey Kardashevskiy92e44bc2017-03-17 00:48:27 +0000598 ret = tce_iommu_userspace_view_alloc(tbl, container->mm);
Alexey Kardashevskiy5d8b3e72017-03-17 00:48:26 +0000599 if (ret)
600 return ret;
601 }
602
Alexey Kardashevskiy2157e7b2015-06-05 16:35:25 +1000603 for (i = 0; i < pages; ++i) {
604 struct mm_iommu_table_group_mem_t *mem = NULL;
605 unsigned long *pua = IOMMU_TABLE_USERSPACE_ENTRY(tbl,
606 entry + i);
607
Alexey Kardashevskiy92e44bc2017-03-17 00:48:27 +0000608 ret = tce_iommu_prereg_ua_to_hpa(container,
609 tce, IOMMU_PAGE_SIZE(tbl), &hpa, &mem);
Alexey Kardashevskiy2157e7b2015-06-05 16:35:25 +1000610 if (ret)
611 break;
612
613 page = pfn_to_page(hpa >> PAGE_SHIFT);
614 if (!tce_page_is_contained(page, tbl->it_page_shift)) {
615 ret = -EPERM;
616 break;
617 }
618
619 /* Preserve offset within IOMMU page */
620 hpa |= tce & IOMMU_PAGE_MASK(tbl) & ~PAGE_MASK;
621 dirtmp = direction;
622
623 /* The registered region is being unregistered */
624 if (mm_iommu_mapped_inc(mem))
625 break;
626
627 ret = iommu_tce_xchg(tbl, entry + i, &hpa, &dirtmp);
628 if (ret) {
629 /* dirtmp cannot be DMA_NONE here */
Alexey Kardashevskiy92e44bc2017-03-17 00:48:27 +0000630 tce_iommu_unuse_page_v2(container, tbl, entry + i);
Alexey Kardashevskiy2157e7b2015-06-05 16:35:25 +1000631 pr_err("iommu_tce: %s failed ioba=%lx, tce=%lx, ret=%ld\n",
632 __func__, entry << tbl->it_page_shift,
633 tce, ret);
634 break;
635 }
636
637 if (dirtmp != DMA_NONE)
Alexey Kardashevskiy92e44bc2017-03-17 00:48:27 +0000638 tce_iommu_unuse_page_v2(container, tbl, entry + i);
Alexey Kardashevskiy2157e7b2015-06-05 16:35:25 +1000639
640 *pua = tce;
641
642 tce += IOMMU_PAGE_SIZE(tbl);
643 }
644
645 if (ret)
646 tce_iommu_clear(container, tbl, entry, i);
647
648 return ret;
649}
650
Alexey Kardashevskiy46d3e1e2015-06-05 16:35:23 +1000651static long tce_iommu_create_table(struct tce_container *container,
652 struct iommu_table_group *table_group,
653 int num,
654 __u32 page_shift,
655 __u64 window_size,
656 __u32 levels,
657 struct iommu_table **ptbl)
658{
659 long ret, table_size;
660
661 table_size = table_group->ops->get_table_size(page_shift, window_size,
662 levels);
663 if (!table_size)
664 return -EINVAL;
665
Alexey Kardashevskiy92e44bc2017-03-17 00:48:27 +0000666 ret = try_increment_locked_vm(container->mm, table_size >> PAGE_SHIFT);
Alexey Kardashevskiy46d3e1e2015-06-05 16:35:23 +1000667 if (ret)
668 return ret;
669
670 ret = table_group->ops->create_table(table_group, num,
671 page_shift, window_size, levels, ptbl);
672
673 WARN_ON(!ret && !(*ptbl)->it_ops->free);
674 WARN_ON(!ret && ((*ptbl)->it_allocated_size != table_size));
675
Alexey Kardashevskiy46d3e1e2015-06-05 16:35:23 +1000676 return ret;
677}
678
Alexey Kardashevskiy92e44bc2017-03-17 00:48:27 +0000679static void tce_iommu_free_table(struct tce_container *container,
680 struct iommu_table *tbl)
Alexey Kardashevskiy46d3e1e2015-06-05 16:35:23 +1000681{
682 unsigned long pages = tbl->it_allocated_size >> PAGE_SHIFT;
683
Alexey Kardashevskiy92e44bc2017-03-17 00:48:27 +0000684 tce_iommu_userspace_view_free(tbl, container->mm);
Alexey Kardashevskiy46d3e1e2015-06-05 16:35:23 +1000685 tbl->it_ops->free(tbl);
Alexey Kardashevskiy92e44bc2017-03-17 00:48:27 +0000686 decrement_locked_vm(container->mm, pages);
Alexey Kardashevskiy46d3e1e2015-06-05 16:35:23 +1000687}
688
Alexey Kardashevskiye633bc82015-06-05 16:35:26 +1000689static long tce_iommu_create_window(struct tce_container *container,
690 __u32 page_shift, __u64 window_size, __u32 levels,
691 __u64 *start_addr)
692{
693 struct tce_iommu_group *tcegrp;
694 struct iommu_table_group *table_group;
695 struct iommu_table *tbl = NULL;
696 long ret, num;
697
698 num = tce_iommu_find_free_table(container);
699 if (num < 0)
700 return num;
701
702 /* Get the first group for ops::create_table */
703 tcegrp = list_first_entry(&container->group_list,
704 struct tce_iommu_group, next);
705 table_group = iommu_group_get_iommudata(tcegrp->grp);
706 if (!table_group)
707 return -EFAULT;
708
709 if (!(table_group->pgsizes & (1ULL << page_shift)))
710 return -EINVAL;
711
712 if (!table_group->ops->set_window || !table_group->ops->unset_window ||
713 !table_group->ops->get_table_size ||
714 !table_group->ops->create_table)
715 return -EPERM;
716
717 /* Create TCE table */
718 ret = tce_iommu_create_table(container, table_group, num,
719 page_shift, window_size, levels, &tbl);
720 if (ret)
721 return ret;
722
723 BUG_ON(!tbl->it_ops->free);
724
725 /*
726 * Program the table to every group.
727 * Groups have been tested for compatibility at the attach time.
728 */
729 list_for_each_entry(tcegrp, &container->group_list, next) {
730 table_group = iommu_group_get_iommudata(tcegrp->grp);
731
732 ret = table_group->ops->set_window(table_group, num, tbl);
733 if (ret)
734 goto unset_exit;
735 }
736
737 container->tables[num] = tbl;
738
739 /* Return start address assigned by platform in create_table() */
740 *start_addr = tbl->it_offset << tbl->it_page_shift;
741
742 return 0;
743
744unset_exit:
745 list_for_each_entry(tcegrp, &container->group_list, next) {
746 table_group = iommu_group_get_iommudata(tcegrp->grp);
747 table_group->ops->unset_window(table_group, num);
748 }
Alexey Kardashevskiy92e44bc2017-03-17 00:48:27 +0000749 tce_iommu_free_table(container, tbl);
Alexey Kardashevskiye633bc82015-06-05 16:35:26 +1000750
751 return ret;
752}
753
754static long tce_iommu_remove_window(struct tce_container *container,
755 __u64 start_addr)
756{
757 struct iommu_table_group *table_group = NULL;
758 struct iommu_table *tbl;
759 struct tce_iommu_group *tcegrp;
760 int num;
761
762 num = tce_iommu_find_table(container, start_addr, &tbl);
763 if (num < 0)
764 return -EINVAL;
765
766 BUG_ON(!tbl->it_size);
767
768 /* Detach groups from IOMMUs */
769 list_for_each_entry(tcegrp, &container->group_list, next) {
770 table_group = iommu_group_get_iommudata(tcegrp->grp);
771
772 /*
773 * SPAPR TCE IOMMU exposes the default DMA window to
774 * the guest via dma32_window_start/size of
775 * VFIO_IOMMU_SPAPR_TCE_GET_INFO. Some platforms allow
776 * the userspace to remove this window, some do not so
777 * here we check for the platform capability.
778 */
779 if (!table_group->ops || !table_group->ops->unset_window)
780 return -EPERM;
781
782 table_group->ops->unset_window(table_group, num);
783 }
784
785 /* Free table */
786 tce_iommu_clear(container, tbl, tbl->it_offset, tbl->it_size);
Alexey Kardashevskiy92e44bc2017-03-17 00:48:27 +0000787 tce_iommu_free_table(container, tbl);
Alexey Kardashevskiye633bc82015-06-05 16:35:26 +1000788 container->tables[num] = NULL;
789
790 return 0;
791}
792
Alexey Kardashevskiy2e60bac2017-03-17 00:48:28 +0000793static long tce_iommu_create_default_window(struct tce_container *container)
794{
795 long ret;
796 __u64 start_addr = 0;
797 struct tce_iommu_group *tcegrp;
798 struct iommu_table_group *table_group;
799
Alexey Kardashevskiy53e18962017-03-17 00:48:29 +0000800 if (!container->def_window_pending)
801 return 0;
802
Alexey Kardashevskiy2e60bac2017-03-17 00:48:28 +0000803 if (!tce_groups_attached(container))
804 return -ENODEV;
805
806 tcegrp = list_first_entry(&container->group_list,
807 struct tce_iommu_group, next);
808 table_group = iommu_group_get_iommudata(tcegrp->grp);
809 if (!table_group)
810 return -ENODEV;
811
812 ret = tce_iommu_create_window(container, IOMMU_PAGE_SHIFT_4K,
813 table_group->tce32_size, 1, &start_addr);
814 WARN_ON_ONCE(!ret && start_addr);
815
Alexey Kardashevskiy53e18962017-03-17 00:48:29 +0000816 if (!ret)
817 container->def_window_pending = false;
818
Alexey Kardashevskiy2e60bac2017-03-17 00:48:28 +0000819 return ret;
820}
821
Alexey Kardashevskiy5ffd2292013-05-21 13:33:10 +1000822static long tce_iommu_ioctl(void *iommu_data,
823 unsigned int cmd, unsigned long arg)
824{
825 struct tce_container *container = iommu_data;
Alexey Kardashevskiye633bc82015-06-05 16:35:26 +1000826 unsigned long minsz, ddwsz;
Alexey Kardashevskiy5ffd2292013-05-21 13:33:10 +1000827 long ret;
828
829 switch (cmd) {
830 case VFIO_CHECK_EXTENSION:
Gavin Shan1b69be52014-06-10 11:41:57 +1000831 switch (arg) {
832 case VFIO_SPAPR_TCE_IOMMU:
Alexey Kardashevskiy2157e7b2015-06-05 16:35:25 +1000833 case VFIO_SPAPR_TCE_v2_IOMMU:
Gavin Shan1b69be52014-06-10 11:41:57 +1000834 ret = 1;
835 break;
836 default:
837 ret = vfio_spapr_iommu_eeh_ioctl(NULL, cmd, arg);
838 break;
839 }
840
841 return (ret < 0) ? 0 : ret;
Alexey Kardashevskiy92e44bc2017-03-17 00:48:27 +0000842 }
Alexey Kardashevskiy5ffd2292013-05-21 13:33:10 +1000843
Alexey Kardashevskiy92e44bc2017-03-17 00:48:27 +0000844 /*
845 * Sanity check to prevent one userspace from manipulating
846 * another userspace mm.
847 */
848 BUG_ON(!container);
849 if (container->mm && container->mm != current->mm)
850 return -EPERM;
851
852 switch (cmd) {
Alexey Kardashevskiy5ffd2292013-05-21 13:33:10 +1000853 case VFIO_IOMMU_SPAPR_TCE_GET_INFO: {
854 struct vfio_iommu_spapr_tce_info info;
Alexey Kardashevskiy2157e7b2015-06-05 16:35:25 +1000855 struct tce_iommu_group *tcegrp;
Alexey Kardashevskiy0eaf4de2015-06-05 16:35:09 +1000856 struct iommu_table_group *table_group;
Alexey Kardashevskiy5ffd2292013-05-21 13:33:10 +1000857
Alexey Kardashevskiy2157e7b2015-06-05 16:35:25 +1000858 if (!tce_groups_attached(container))
Alexey Kardashevskiy0eaf4de2015-06-05 16:35:09 +1000859 return -ENXIO;
860
Alexey Kardashevskiy2157e7b2015-06-05 16:35:25 +1000861 tcegrp = list_first_entry(&container->group_list,
862 struct tce_iommu_group, next);
863 table_group = iommu_group_get_iommudata(tcegrp->grp);
Alexey Kardashevskiy0eaf4de2015-06-05 16:35:09 +1000864
Alexey Kardashevskiy4793d652015-06-05 16:35:20 +1000865 if (!table_group)
Alexey Kardashevskiy5ffd2292013-05-21 13:33:10 +1000866 return -ENXIO;
867
868 minsz = offsetofend(struct vfio_iommu_spapr_tce_info,
869 dma32_window_size);
870
871 if (copy_from_user(&info, (void __user *)arg, minsz))
872 return -EFAULT;
873
874 if (info.argsz < minsz)
875 return -EINVAL;
876
Alexey Kardashevskiy4793d652015-06-05 16:35:20 +1000877 info.dma32_window_start = table_group->tce32_start;
878 info.dma32_window_size = table_group->tce32_size;
Alexey Kardashevskiy5ffd2292013-05-21 13:33:10 +1000879 info.flags = 0;
Alexey Kardashevskiye633bc82015-06-05 16:35:26 +1000880 memset(&info.ddw, 0, sizeof(info.ddw));
881
882 if (table_group->max_dynamic_windows_supported &&
883 container->v2) {
884 info.flags |= VFIO_IOMMU_SPAPR_INFO_DDW;
885 info.ddw.pgsizes = table_group->pgsizes;
886 info.ddw.max_dynamic_windows_supported =
887 table_group->max_dynamic_windows_supported;
888 info.ddw.levels = table_group->max_levels;
889 }
890
891 ddwsz = offsetofend(struct vfio_iommu_spapr_tce_info, ddw);
892
893 if (info.argsz >= ddwsz)
894 minsz = ddwsz;
Alexey Kardashevskiy5ffd2292013-05-21 13:33:10 +1000895
896 if (copy_to_user((void __user *)arg, &info, minsz))
897 return -EFAULT;
898
899 return 0;
900 }
901 case VFIO_IOMMU_MAP_DMA: {
902 struct vfio_iommu_type1_dma_map param;
Alexey Kardashevskiy0eaf4de2015-06-05 16:35:09 +1000903 struct iommu_table *tbl = NULL;
Alexey Kardashevskiy0eaf4de2015-06-05 16:35:09 +1000904 long num;
Alexey Kardashevskiy05c6cfb2015-06-05 16:35:15 +1000905 enum dma_data_direction direction;
Alexey Kardashevskiy5ffd2292013-05-21 13:33:10 +1000906
Alexey Kardashevskiy3c56e822015-06-05 16:35:02 +1000907 if (!container->enabled)
908 return -EPERM;
909
Alexey Kardashevskiy5ffd2292013-05-21 13:33:10 +1000910 minsz = offsetofend(struct vfio_iommu_type1_dma_map, size);
911
912 if (copy_from_user(&param, (void __user *)arg, minsz))
913 return -EFAULT;
914
915 if (param.argsz < minsz)
916 return -EINVAL;
917
918 if (param.flags & ~(VFIO_DMA_MAP_FLAG_READ |
919 VFIO_DMA_MAP_FLAG_WRITE))
920 return -EINVAL;
921
Alexey Kardashevskiy53e18962017-03-17 00:48:29 +0000922 ret = tce_iommu_create_default_window(container);
923 if (ret)
924 return ret;
925
Alexey Kardashevskiy0eaf4de2015-06-05 16:35:09 +1000926 num = tce_iommu_find_table(container, param.iova, &tbl);
927 if (num < 0)
928 return -ENXIO;
929
Alexey Kardashevskiy00663d42015-06-05 16:35:00 +1000930 if ((param.size & ~IOMMU_PAGE_MASK(tbl)) ||
931 (param.vaddr & ~IOMMU_PAGE_MASK(tbl)))
Alexey Kardashevskiy5ffd2292013-05-21 13:33:10 +1000932 return -EINVAL;
933
934 /* iova is checked by the IOMMU API */
Alexey Kardashevskiy05c6cfb2015-06-05 16:35:15 +1000935 if (param.flags & VFIO_DMA_MAP_FLAG_READ) {
936 if (param.flags & VFIO_DMA_MAP_FLAG_WRITE)
937 direction = DMA_BIDIRECTIONAL;
938 else
939 direction = DMA_TO_DEVICE;
940 } else {
941 if (param.flags & VFIO_DMA_MAP_FLAG_WRITE)
942 direction = DMA_FROM_DEVICE;
943 else
944 return -EINVAL;
945 }
Alexey Kardashevskiy5ffd2292013-05-21 13:33:10 +1000946
Alexey Kardashevskiy05c6cfb2015-06-05 16:35:15 +1000947 ret = iommu_tce_put_param_check(tbl, param.iova, param.vaddr);
Alexey Kardashevskiy5ffd2292013-05-21 13:33:10 +1000948 if (ret)
949 return ret;
950
Alexey Kardashevskiy2157e7b2015-06-05 16:35:25 +1000951 if (container->v2)
952 ret = tce_iommu_build_v2(container, tbl,
953 param.iova >> tbl->it_page_shift,
954 param.vaddr,
955 param.size >> tbl->it_page_shift,
956 direction);
957 else
958 ret = tce_iommu_build(container, tbl,
959 param.iova >> tbl->it_page_shift,
960 param.vaddr,
961 param.size >> tbl->it_page_shift,
962 direction);
Alexey Kardashevskiy5ffd2292013-05-21 13:33:10 +1000963
964 iommu_flush_tce(tbl);
965
966 return ret;
967 }
968 case VFIO_IOMMU_UNMAP_DMA: {
969 struct vfio_iommu_type1_dma_unmap param;
Alexey Kardashevskiy0eaf4de2015-06-05 16:35:09 +1000970 struct iommu_table *tbl = NULL;
971 long num;
Alexey Kardashevskiy5ffd2292013-05-21 13:33:10 +1000972
Alexey Kardashevskiy3c56e822015-06-05 16:35:02 +1000973 if (!container->enabled)
974 return -EPERM;
975
Alexey Kardashevskiy5ffd2292013-05-21 13:33:10 +1000976 minsz = offsetofend(struct vfio_iommu_type1_dma_unmap,
977 size);
978
979 if (copy_from_user(&param, (void __user *)arg, minsz))
980 return -EFAULT;
981
982 if (param.argsz < minsz)
983 return -EINVAL;
984
985 /* No flag is supported now */
986 if (param.flags)
987 return -EINVAL;
988
Alexey Kardashevskiy53e18962017-03-17 00:48:29 +0000989 ret = tce_iommu_create_default_window(container);
990 if (ret)
991 return ret;
992
Alexey Kardashevskiy0eaf4de2015-06-05 16:35:09 +1000993 num = tce_iommu_find_table(container, param.iova, &tbl);
994 if (num < 0)
995 return -ENXIO;
996
Alexey Kardashevskiy00663d42015-06-05 16:35:00 +1000997 if (param.size & ~IOMMU_PAGE_MASK(tbl))
Alexey Kardashevskiy5ffd2292013-05-21 13:33:10 +1000998 return -EINVAL;
999
1000 ret = iommu_tce_clear_param_check(tbl, param.iova, 0,
Alexey Kardashevskiy00663d42015-06-05 16:35:00 +10001001 param.size >> tbl->it_page_shift);
Alexey Kardashevskiy5ffd2292013-05-21 13:33:10 +10001002 if (ret)
1003 return ret;
1004
Alexey Kardashevskiy9b14a1f2015-06-05 16:34:58 +10001005 ret = tce_iommu_clear(container, tbl,
Alexey Kardashevskiy00663d42015-06-05 16:35:00 +10001006 param.iova >> tbl->it_page_shift,
1007 param.size >> tbl->it_page_shift);
Alexey Kardashevskiy5ffd2292013-05-21 13:33:10 +10001008 iommu_flush_tce(tbl);
1009
1010 return ret;
1011 }
Alexey Kardashevskiy2157e7b2015-06-05 16:35:25 +10001012 case VFIO_IOMMU_SPAPR_REGISTER_MEMORY: {
1013 struct vfio_iommu_spapr_register_memory param;
1014
1015 if (!container->v2)
1016 break;
1017
1018 minsz = offsetofend(struct vfio_iommu_spapr_register_memory,
1019 size);
1020
Alexey Kardashevskiy92e44bc2017-03-17 00:48:27 +00001021 ret = tce_iommu_mm_set(container);
1022 if (ret)
1023 return ret;
1024
Alexey Kardashevskiy2157e7b2015-06-05 16:35:25 +10001025 if (copy_from_user(&param, (void __user *)arg, minsz))
1026 return -EFAULT;
1027
1028 if (param.argsz < minsz)
1029 return -EINVAL;
1030
1031 /* No flag is supported now */
1032 if (param.flags)
1033 return -EINVAL;
1034
1035 mutex_lock(&container->lock);
1036 ret = tce_iommu_register_pages(container, param.vaddr,
1037 param.size);
1038 mutex_unlock(&container->lock);
1039
1040 return ret;
1041 }
1042 case VFIO_IOMMU_SPAPR_UNREGISTER_MEMORY: {
1043 struct vfio_iommu_spapr_register_memory param;
1044
1045 if (!container->v2)
1046 break;
1047
Alexey Kardashevskiy92e44bc2017-03-17 00:48:27 +00001048 if (!container->mm)
1049 return -EPERM;
1050
Alexey Kardashevskiy2157e7b2015-06-05 16:35:25 +10001051 minsz = offsetofend(struct vfio_iommu_spapr_register_memory,
1052 size);
1053
1054 if (copy_from_user(&param, (void __user *)arg, minsz))
1055 return -EFAULT;
1056
1057 if (param.argsz < minsz)
1058 return -EINVAL;
1059
1060 /* No flag is supported now */
1061 if (param.flags)
1062 return -EINVAL;
1063
1064 mutex_lock(&container->lock);
1065 ret = tce_iommu_unregister_pages(container, param.vaddr,
1066 param.size);
1067 mutex_unlock(&container->lock);
1068
1069 return ret;
1070 }
Alexey Kardashevskiy5ffd2292013-05-21 13:33:10 +10001071 case VFIO_IOMMU_ENABLE:
Alexey Kardashevskiy2157e7b2015-06-05 16:35:25 +10001072 if (container->v2)
1073 break;
1074
Alexey Kardashevskiy5ffd2292013-05-21 13:33:10 +10001075 mutex_lock(&container->lock);
1076 ret = tce_iommu_enable(container);
1077 mutex_unlock(&container->lock);
1078 return ret;
1079
1080
1081 case VFIO_IOMMU_DISABLE:
Alexey Kardashevskiy2157e7b2015-06-05 16:35:25 +10001082 if (container->v2)
1083 break;
1084
Alexey Kardashevskiy5ffd2292013-05-21 13:33:10 +10001085 mutex_lock(&container->lock);
1086 tce_iommu_disable(container);
1087 mutex_unlock(&container->lock);
1088 return 0;
Gavin Shan1b69be52014-06-10 11:41:57 +10001089
Alexey Kardashevskiy2157e7b2015-06-05 16:35:25 +10001090 case VFIO_EEH_PE_OP: {
1091 struct tce_iommu_group *tcegrp;
1092
1093 ret = 0;
1094 list_for_each_entry(tcegrp, &container->group_list, next) {
1095 ret = vfio_spapr_iommu_eeh_ioctl(tcegrp->grp,
1096 cmd, arg);
1097 if (ret)
1098 return ret;
1099 }
1100 return ret;
1101 }
1102
Alexey Kardashevskiye633bc82015-06-05 16:35:26 +10001103 case VFIO_IOMMU_SPAPR_TCE_CREATE: {
1104 struct vfio_iommu_spapr_tce_create create;
1105
1106 if (!container->v2)
1107 break;
1108
Alexey Kardashevskiy92e44bc2017-03-17 00:48:27 +00001109 ret = tce_iommu_mm_set(container);
1110 if (ret)
1111 return ret;
1112
Alexey Kardashevskiye633bc82015-06-05 16:35:26 +10001113 if (!tce_groups_attached(container))
1114 return -ENXIO;
1115
1116 minsz = offsetofend(struct vfio_iommu_spapr_tce_create,
1117 start_addr);
1118
1119 if (copy_from_user(&create, (void __user *)arg, minsz))
1120 return -EFAULT;
1121
1122 if (create.argsz < minsz)
1123 return -EINVAL;
1124
1125 if (create.flags)
1126 return -EINVAL;
1127
1128 mutex_lock(&container->lock);
1129
Alexey Kardashevskiy53e18962017-03-17 00:48:29 +00001130 ret = tce_iommu_create_default_window(container);
Alexey Kardashevskiy3e550de2017-02-01 14:26:16 +11001131 if (!ret)
1132 ret = tce_iommu_create_window(container,
1133 create.page_shift,
1134 create.window_size, create.levels,
1135 &create.start_addr);
Alexey Kardashevskiye633bc82015-06-05 16:35:26 +10001136
1137 mutex_unlock(&container->lock);
1138
1139 if (!ret && copy_to_user((void __user *)arg, &create, minsz))
1140 ret = -EFAULT;
1141
1142 return ret;
1143 }
1144 case VFIO_IOMMU_SPAPR_TCE_REMOVE: {
1145 struct vfio_iommu_spapr_tce_remove remove;
1146
1147 if (!container->v2)
1148 break;
1149
Alexey Kardashevskiy92e44bc2017-03-17 00:48:27 +00001150 ret = tce_iommu_mm_set(container);
1151 if (ret)
1152 return ret;
1153
Alexey Kardashevskiye633bc82015-06-05 16:35:26 +10001154 if (!tce_groups_attached(container))
1155 return -ENXIO;
1156
1157 minsz = offsetofend(struct vfio_iommu_spapr_tce_remove,
1158 start_addr);
1159
1160 if (copy_from_user(&remove, (void __user *)arg, minsz))
1161 return -EFAULT;
1162
1163 if (remove.argsz < minsz)
1164 return -EINVAL;
1165
1166 if (remove.flags)
1167 return -EINVAL;
1168
Alexey Kardashevskiy53e18962017-03-17 00:48:29 +00001169 if (container->def_window_pending && !remove.start_addr) {
1170 container->def_window_pending = false;
1171 return 0;
1172 }
1173
Alexey Kardashevskiye633bc82015-06-05 16:35:26 +10001174 mutex_lock(&container->lock);
1175
1176 ret = tce_iommu_remove_window(container, remove.start_addr);
1177
1178 mutex_unlock(&container->lock);
1179
1180 return ret;
1181 }
Alexey Kardashevskiy5ffd2292013-05-21 13:33:10 +10001182 }
1183
1184 return -ENOTTY;
1185}
1186
Alexey Kardashevskiyf87a8862015-06-05 16:35:10 +10001187static void tce_iommu_release_ownership(struct tce_container *container,
1188 struct iommu_table_group *table_group)
1189{
1190 int i;
1191
1192 for (i = 0; i < IOMMU_TABLE_GROUP_MAX_TABLES; ++i) {
Alexey Kardashevskiy2157e7b2015-06-05 16:35:25 +10001193 struct iommu_table *tbl = container->tables[i];
Alexey Kardashevskiyf87a8862015-06-05 16:35:10 +10001194
1195 if (!tbl)
1196 continue;
1197
1198 tce_iommu_clear(container, tbl, tbl->it_offset, tbl->it_size);
Alexey Kardashevskiy92e44bc2017-03-17 00:48:27 +00001199 tce_iommu_userspace_view_free(tbl, container->mm);
Alexey Kardashevskiyf87a8862015-06-05 16:35:10 +10001200 if (tbl->it_map)
1201 iommu_release_ownership(tbl);
Alexey Kardashevskiy2157e7b2015-06-05 16:35:25 +10001202
1203 container->tables[i] = NULL;
Alexey Kardashevskiyf87a8862015-06-05 16:35:10 +10001204 }
1205}
1206
1207static int tce_iommu_take_ownership(struct tce_container *container,
1208 struct iommu_table_group *table_group)
1209{
1210 int i, j, rc = 0;
1211
1212 for (i = 0; i < IOMMU_TABLE_GROUP_MAX_TABLES; ++i) {
1213 struct iommu_table *tbl = table_group->tables[i];
1214
1215 if (!tbl || !tbl->it_map)
1216 continue;
1217
Alexey Kardashevskiy5d8b3e72017-03-17 00:48:26 +00001218 rc = iommu_take_ownership(tbl);
Alexey Kardashevskiyf87a8862015-06-05 16:35:10 +10001219 if (rc) {
1220 for (j = 0; j < i; ++j)
1221 iommu_release_ownership(
1222 table_group->tables[j]);
1223
1224 return rc;
1225 }
1226 }
1227
Alexey Kardashevskiy2157e7b2015-06-05 16:35:25 +10001228 for (i = 0; i < IOMMU_TABLE_GROUP_MAX_TABLES; ++i)
1229 container->tables[i] = table_group->tables[i];
1230
Alexey Kardashevskiyf87a8862015-06-05 16:35:10 +10001231 return 0;
1232}
1233
1234static void tce_iommu_release_ownership_ddw(struct tce_container *container,
1235 struct iommu_table_group *table_group)
1236{
Alexey Kardashevskiy46d3e1e2015-06-05 16:35:23 +10001237 long i;
1238
1239 if (!table_group->ops->unset_window) {
1240 WARN_ON_ONCE(1);
1241 return;
1242 }
1243
Alexey Kardashevskiy2157e7b2015-06-05 16:35:25 +10001244 for (i = 0; i < IOMMU_TABLE_GROUP_MAX_TABLES; ++i)
Alexey Kardashevskiy46d3e1e2015-06-05 16:35:23 +10001245 table_group->ops->unset_window(table_group, i);
Alexey Kardashevskiy46d3e1e2015-06-05 16:35:23 +10001246
Alexey Kardashevskiyf87a8862015-06-05 16:35:10 +10001247 table_group->ops->release_ownership(table_group);
1248}
1249
1250static long tce_iommu_take_ownership_ddw(struct tce_container *container,
1251 struct iommu_table_group *table_group)
1252{
Alexey Kardashevskiyd5362022017-05-23 21:53:51 -04001253 long i, ret = 0;
1254
Alexey Kardashevskiy46d3e1e2015-06-05 16:35:23 +10001255 if (!table_group->ops->create_table || !table_group->ops->set_window ||
1256 !table_group->ops->release_ownership) {
1257 WARN_ON_ONCE(1);
1258 return -EFAULT;
1259 }
1260
Alexey Kardashevskiyf87a8862015-06-05 16:35:10 +10001261 table_group->ops->take_ownership(table_group);
1262
Alexey Kardashevskiyd5362022017-05-23 21:53:51 -04001263 /* Set all windows to the new group */
1264 for (i = 0; i < IOMMU_TABLE_GROUP_MAX_TABLES; ++i) {
1265 struct iommu_table *tbl = container->tables[i];
1266
1267 if (!tbl)
1268 continue;
1269
1270 ret = table_group->ops->set_window(table_group, i, tbl);
1271 if (ret)
1272 goto release_exit;
1273 }
1274
Alexey Kardashevskiy2157e7b2015-06-05 16:35:25 +10001275 return 0;
Alexey Kardashevskiyd5362022017-05-23 21:53:51 -04001276
1277release_exit:
1278 for (i = 0; i < IOMMU_TABLE_GROUP_MAX_TABLES; ++i)
1279 table_group->ops->unset_window(table_group, i);
1280
1281 table_group->ops->release_ownership(table_group);
1282
1283 return ret;
Alexey Kardashevskiyf87a8862015-06-05 16:35:10 +10001284}
1285
Alexey Kardashevskiy5ffd2292013-05-21 13:33:10 +10001286static int tce_iommu_attach_group(void *iommu_data,
1287 struct iommu_group *iommu_group)
1288{
1289 int ret;
1290 struct tce_container *container = iommu_data;
Alexey Kardashevskiy0eaf4de2015-06-05 16:35:09 +10001291 struct iommu_table_group *table_group;
Alexey Kardashevskiy2157e7b2015-06-05 16:35:25 +10001292 struct tce_iommu_group *tcegrp = NULL;
Alexey Kardashevskiy5ffd2292013-05-21 13:33:10 +10001293
Alexey Kardashevskiy5ffd2292013-05-21 13:33:10 +10001294 mutex_lock(&container->lock);
1295
1296 /* pr_debug("tce_vfio: Attaching group #%u to iommu %p\n",
1297 iommu_group_id(iommu_group), iommu_group); */
Alexey Kardashevskiy0eaf4de2015-06-05 16:35:09 +10001298 table_group = iommu_group_get_iommudata(iommu_group);
Greg Kurzff3b1dd2017-01-24 17:50:26 +01001299 if (!table_group) {
1300 ret = -ENODEV;
1301 goto unlock_exit;
1302 }
Alexey Kardashevskiy2157e7b2015-06-05 16:35:25 +10001303
1304 if (tce_groups_attached(container) && (!table_group->ops ||
1305 !table_group->ops->take_ownership ||
1306 !table_group->ops->release_ownership)) {
1307 ret = -EBUSY;
1308 goto unlock_exit;
1309 }
1310
1311 /* Check if new group has the same iommu_ops (i.e. compatible) */
1312 list_for_each_entry(tcegrp, &container->group_list, next) {
1313 struct iommu_table_group *table_group_tmp;
1314
1315 if (tcegrp->grp == iommu_group) {
1316 pr_warn("tce_vfio: Group %d is already attached\n",
1317 iommu_group_id(iommu_group));
1318 ret = -EBUSY;
1319 goto unlock_exit;
1320 }
1321 table_group_tmp = iommu_group_get_iommudata(tcegrp->grp);
Alexey Kardashevskiy54de2852016-04-29 18:55:15 +10001322 if (table_group_tmp->ops->create_table !=
1323 table_group->ops->create_table) {
Alexey Kardashevskiy2157e7b2015-06-05 16:35:25 +10001324 pr_warn("tce_vfio: Group %d is incompatible with group %d\n",
1325 iommu_group_id(iommu_group),
1326 iommu_group_id(tcegrp->grp));
1327 ret = -EPERM;
1328 goto unlock_exit;
1329 }
1330 }
1331
1332 tcegrp = kzalloc(sizeof(*tcegrp), GFP_KERNEL);
1333 if (!tcegrp) {
1334 ret = -ENOMEM;
Alexey Kardashevskiy0eaf4de2015-06-05 16:35:09 +10001335 goto unlock_exit;
1336 }
1337
Alexey Kardashevskiyf87a8862015-06-05 16:35:10 +10001338 if (!table_group->ops || !table_group->ops->take_ownership ||
Alexey Kardashevskiy2e60bac2017-03-17 00:48:28 +00001339 !table_group->ops->release_ownership) {
Alexey Kardashevskiy5d7601d2017-03-24 17:44:06 +11001340 if (container->v2) {
1341 ret = -EPERM;
1342 goto unlock_exit;
1343 }
Alexey Kardashevskiyf87a8862015-06-05 16:35:10 +10001344 ret = tce_iommu_take_ownership(container, table_group);
Alexey Kardashevskiy2e60bac2017-03-17 00:48:28 +00001345 } else {
Alexey Kardashevskiy5d7601d2017-03-24 17:44:06 +11001346 if (!container->v2) {
1347 ret = -EPERM;
1348 goto unlock_exit;
1349 }
Alexey Kardashevskiyf87a8862015-06-05 16:35:10 +10001350 ret = tce_iommu_take_ownership_ddw(container, table_group);
Alexey Kardashevskiy2e60bac2017-03-17 00:48:28 +00001351 if (!tce_groups_attached(container) && !container->tables[0])
Alexey Kardashevskiy53e18962017-03-17 00:48:29 +00001352 container->def_window_pending = true;
Alexey Kardashevskiy2e60bac2017-03-17 00:48:28 +00001353 }
Alexey Kardashevskiyf87a8862015-06-05 16:35:10 +10001354
Alexey Kardashevskiy2157e7b2015-06-05 16:35:25 +10001355 if (!ret) {
1356 tcegrp->grp = iommu_group;
1357 list_add(&tcegrp->next, &container->group_list);
1358 }
Alexey Kardashevskiy22af4852015-06-05 16:35:04 +10001359
1360unlock_exit:
Alexey Kardashevskiy2157e7b2015-06-05 16:35:25 +10001361 if (ret && tcegrp)
1362 kfree(tcegrp);
1363
Alexey Kardashevskiy5ffd2292013-05-21 13:33:10 +10001364 mutex_unlock(&container->lock);
1365
1366 return ret;
1367}
1368
1369static void tce_iommu_detach_group(void *iommu_data,
1370 struct iommu_group *iommu_group)
1371{
1372 struct tce_container *container = iommu_data;
Alexey Kardashevskiy0eaf4de2015-06-05 16:35:09 +10001373 struct iommu_table_group *table_group;
Alexey Kardashevskiy2157e7b2015-06-05 16:35:25 +10001374 bool found = false;
1375 struct tce_iommu_group *tcegrp;
Alexey Kardashevskiy5ffd2292013-05-21 13:33:10 +10001376
Alexey Kardashevskiy5ffd2292013-05-21 13:33:10 +10001377 mutex_lock(&container->lock);
Alexey Kardashevskiy2157e7b2015-06-05 16:35:25 +10001378
1379 list_for_each_entry(tcegrp, &container->group_list, next) {
1380 if (tcegrp->grp == iommu_group) {
1381 found = true;
1382 break;
1383 }
1384 }
1385
1386 if (!found) {
1387 pr_warn("tce_vfio: detaching unattached group #%u\n",
1388 iommu_group_id(iommu_group));
Alexey Kardashevskiy22af4852015-06-05 16:35:04 +10001389 goto unlock_exit;
Alexey Kardashevskiy5ffd2292013-05-21 13:33:10 +10001390 }
Alexey Kardashevskiy22af4852015-06-05 16:35:04 +10001391
Alexey Kardashevskiy2157e7b2015-06-05 16:35:25 +10001392 list_del(&tcegrp->next);
1393 kfree(tcegrp);
Alexey Kardashevskiy0eaf4de2015-06-05 16:35:09 +10001394
1395 table_group = iommu_group_get_iommudata(iommu_group);
1396 BUG_ON(!table_group);
1397
Alexey Kardashevskiyf87a8862015-06-05 16:35:10 +10001398 if (!table_group->ops || !table_group->ops->release_ownership)
1399 tce_iommu_release_ownership(container, table_group);
1400 else
1401 tce_iommu_release_ownership_ddw(container, table_group);
Alexey Kardashevskiy22af4852015-06-05 16:35:04 +10001402
1403unlock_exit:
Alexey Kardashevskiy5ffd2292013-05-21 13:33:10 +10001404 mutex_unlock(&container->lock);
1405}
1406
1407const struct vfio_iommu_driver_ops tce_iommu_driver_ops = {
1408 .name = "iommu-vfio-powerpc",
1409 .owner = THIS_MODULE,
1410 .open = tce_iommu_open,
1411 .release = tce_iommu_release,
1412 .ioctl = tce_iommu_ioctl,
1413 .attach_group = tce_iommu_attach_group,
1414 .detach_group = tce_iommu_detach_group,
1415};
1416
1417static int __init tce_iommu_init(void)
1418{
1419 return vfio_register_iommu_driver(&tce_iommu_driver_ops);
1420}
1421
1422static void __exit tce_iommu_cleanup(void)
1423{
1424 vfio_unregister_iommu_driver(&tce_iommu_driver_ops);
1425}
1426
1427module_init(tce_iommu_init);
1428module_exit(tce_iommu_cleanup);
1429
1430MODULE_VERSION(DRIVER_VERSION);
1431MODULE_LICENSE("GPL v2");
1432MODULE_AUTHOR(DRIVER_AUTHOR);
1433MODULE_DESCRIPTION(DRIVER_DESC);
1434