1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * MMU-based software IOTLB.
4 *
5 * Copyright (C) 2020-2021 Bytedance Inc. and/or its affiliates. All rights reserved.
6 *
7 * Author: Xie Yongji <xieyongji@bytedance.com>
8 *
9 */
10
11 #include <linux/slab.h>
12 #include <linux/file.h>
13 #include <linux/anon_inodes.h>
14 #include <linux/highmem.h>
15 #include <linux/vmalloc.h>
16 #include <linux/vdpa.h>
17
18 #include "iova_domain.h"
19
vduse_iotlb_add_range(struct vduse_iova_domain * domain,u64 start,u64 last,u64 addr,unsigned int perm,struct file * file,u64 offset)20 static int vduse_iotlb_add_range(struct vduse_iova_domain *domain,
21 u64 start, u64 last,
22 u64 addr, unsigned int perm,
23 struct file *file, u64 offset)
24 {
25 struct vdpa_map_file *map_file;
26 int ret;
27
28 map_file = kmalloc_obj(*map_file, GFP_ATOMIC);
29 if (!map_file)
30 return -ENOMEM;
31
32 map_file->file = get_file(file);
33 map_file->offset = offset;
34
35 ret = vhost_iotlb_add_range_ctx(domain->iotlb, start, last,
36 addr, perm, map_file);
37 if (ret) {
38 fput(map_file->file);
39 kfree(map_file);
40 return ret;
41 }
42 return 0;
43 }
44
vduse_iotlb_del_range(struct vduse_iova_domain * domain,u64 start,u64 last)45 static void vduse_iotlb_del_range(struct vduse_iova_domain *domain,
46 u64 start, u64 last)
47 {
48 struct vdpa_map_file *map_file;
49 struct vhost_iotlb_map *map;
50
51 while ((map = vhost_iotlb_itree_first(domain->iotlb, start, last))) {
52 map_file = (struct vdpa_map_file *)map->opaque;
53 fput(map_file->file);
54 kfree(map_file);
55 vhost_iotlb_map_free(domain->iotlb, map);
56 }
57 }
58
vduse_domain_set_map(struct vduse_iova_domain * domain,struct vhost_iotlb * iotlb)59 int vduse_domain_set_map(struct vduse_iova_domain *domain,
60 struct vhost_iotlb *iotlb)
61 {
62 struct vdpa_map_file *map_file;
63 struct vhost_iotlb_map *map;
64 u64 start = 0ULL, last = ULLONG_MAX;
65 int ret;
66
67 spin_lock(&domain->iotlb_lock);
68 vduse_iotlb_del_range(domain, start, last);
69
70 for (map = vhost_iotlb_itree_first(iotlb, start, last); map;
71 map = vhost_iotlb_itree_next(map, start, last)) {
72 map_file = (struct vdpa_map_file *)map->opaque;
73 ret = vduse_iotlb_add_range(domain, map->start, map->last,
74 map->addr, map->perm,
75 map_file->file,
76 map_file->offset);
77 if (ret)
78 goto err;
79 }
80 spin_unlock(&domain->iotlb_lock);
81
82 return 0;
83 err:
84 vduse_iotlb_del_range(domain, start, last);
85 spin_unlock(&domain->iotlb_lock);
86 return ret;
87 }
88
vduse_domain_clear_map(struct vduse_iova_domain * domain,struct vhost_iotlb * iotlb)89 void vduse_domain_clear_map(struct vduse_iova_domain *domain,
90 struct vhost_iotlb *iotlb)
91 {
92 struct vhost_iotlb_map *map;
93 u64 start = 0ULL, last = ULLONG_MAX;
94
95 spin_lock(&domain->iotlb_lock);
96 for (map = vhost_iotlb_itree_first(iotlb, start, last); map;
97 map = vhost_iotlb_itree_next(map, start, last)) {
98 vduse_iotlb_del_range(domain, map->start, map->last);
99 }
100 spin_unlock(&domain->iotlb_lock);
101 }
102
vduse_domain_map_bounce_page(struct vduse_iova_domain * domain,u64 iova,u64 size,u64 paddr)103 static int vduse_domain_map_bounce_page(struct vduse_iova_domain *domain,
104 u64 iova, u64 size, u64 paddr)
105 {
106 struct vduse_bounce_map *map, *head_map;
107 struct page *tmp_page;
108 u64 last = iova + size - 1;
109
110 while (iova <= last) {
111 /*
112 * When PAGE_SIZE is larger than 4KB, multiple adjacent bounce_maps will
113 * point to the same memory page of PAGE_SIZE. Since bounce_maps originate
114 * from IO requests, we may not be able to guarantee that the orig_phys
115 * values of all IO requests within the same 64KB memory page are contiguous.
116 * Therefore, we need to store them separately.
117 *
118 * Bounce pages are allocated on demand. As a result, it may occur that
119 * multiple bounce pages corresponding to the same 64KB memory page attempt
120 * to allocate memory simultaneously, so we use cmpxchg to handle this
121 * concurrency.
122 */
123 map = &domain->bounce_maps[iova >> BOUNCE_MAP_SHIFT];
124 if (!map->bounce_page) {
125 head_map = &domain->bounce_maps[(iova & PAGE_MASK) >> BOUNCE_MAP_SHIFT];
126 if (!head_map->bounce_page) {
127 tmp_page = alloc_page(GFP_ATOMIC);
128 if (!tmp_page)
129 return -ENOMEM;
130 if (cmpxchg(&head_map->bounce_page, NULL, tmp_page))
131 __free_page(tmp_page);
132 }
133 map->bounce_page = head_map->bounce_page;
134 }
135 map->orig_phys = paddr;
136 paddr += BOUNCE_MAP_SIZE;
137 iova += BOUNCE_MAP_SIZE;
138 }
139 return 0;
140 }
141
vduse_domain_unmap_bounce_page(struct vduse_iova_domain * domain,u64 iova,u64 size)142 static void vduse_domain_unmap_bounce_page(struct vduse_iova_domain *domain,
143 u64 iova, u64 size)
144 {
145 struct vduse_bounce_map *map;
146 u64 last = iova + size - 1;
147
148 while (iova <= last) {
149 map = &domain->bounce_maps[iova >> BOUNCE_MAP_SHIFT];
150 map->orig_phys = INVALID_PHYS_ADDR;
151 iova += BOUNCE_MAP_SIZE;
152 }
153 }
154
offset_in_bounce_page(dma_addr_t addr)155 static unsigned int offset_in_bounce_page(dma_addr_t addr)
156 {
157 return (addr & ~BOUNCE_MAP_MASK);
158 }
159
do_bounce(phys_addr_t orig,void * addr,size_t size,enum dma_data_direction dir)160 static void do_bounce(phys_addr_t orig, void *addr, size_t size,
161 enum dma_data_direction dir)
162 {
163 unsigned long pfn = PFN_DOWN(orig);
164 unsigned int offset = offset_in_page(orig);
165 struct page *page;
166 unsigned int sz = 0;
167
168 while (size) {
169 sz = min_t(size_t, PAGE_SIZE - offset, size);
170
171 page = pfn_to_page(pfn);
172 if (dir == DMA_TO_DEVICE)
173 memcpy_from_page(addr, page, offset, sz);
174 else
175 memcpy_to_page(page, offset, addr, sz);
176
177 size -= sz;
178 pfn++;
179 addr += sz;
180 offset = 0;
181 }
182 }
183
vduse_domain_bounce(struct vduse_iova_domain * domain,dma_addr_t iova,size_t size,enum dma_data_direction dir)184 static void vduse_domain_bounce(struct vduse_iova_domain *domain,
185 dma_addr_t iova, size_t size,
186 enum dma_data_direction dir)
187 {
188 struct vduse_bounce_map *map;
189 struct page *page;
190 unsigned int offset, head_offset;
191 void *addr;
192 size_t sz;
193
194 if (iova >= domain->bounce_size)
195 return;
196
197 while (size) {
198 map = &domain->bounce_maps[iova >> BOUNCE_MAP_SHIFT];
199 head_offset = offset_in_page(iova);
200 offset = offset_in_bounce_page(iova);
201 sz = min_t(size_t, BOUNCE_MAP_SIZE - offset, size);
202
203 if (WARN_ON(!map->bounce_page ||
204 map->orig_phys == INVALID_PHYS_ADDR))
205 return;
206
207 page = domain->user_bounce_pages ?
208 map->user_bounce_page : map->bounce_page;
209
210 addr = kmap_local_page(page);
211 do_bounce(map->orig_phys + offset, addr + head_offset, sz, dir);
212 kunmap_local(addr);
213 size -= sz;
214 iova += sz;
215 }
216 }
217
218 static struct page *
vduse_domain_get_coherent_page(struct vduse_iova_domain * domain,u64 iova)219 vduse_domain_get_coherent_page(struct vduse_iova_domain *domain, u64 iova)
220 {
221 u64 start = iova & PAGE_MASK;
222 u64 last = start + PAGE_SIZE - 1;
223 struct vhost_iotlb_map *map;
224 struct page *page = NULL;
225
226 spin_lock(&domain->iotlb_lock);
227 map = vhost_iotlb_itree_first(domain->iotlb, start, last);
228 if (!map)
229 goto out;
230
231 page = pfn_to_page((map->addr + iova - map->start) >> PAGE_SHIFT);
232 get_page(page);
233 out:
234 spin_unlock(&domain->iotlb_lock);
235
236 return page;
237 }
238
239 static struct page *
vduse_domain_get_bounce_page(struct vduse_iova_domain * domain,u64 iova)240 vduse_domain_get_bounce_page(struct vduse_iova_domain *domain, u64 iova)
241 {
242 struct vduse_bounce_map *map;
243 struct page *page = NULL;
244
245 read_lock(&domain->bounce_lock);
246 map = &domain->bounce_maps[iova >> BOUNCE_MAP_SHIFT];
247 if (domain->user_bounce_pages || !map->bounce_page)
248 goto out;
249
250 page = map->bounce_page;
251 get_page(page);
252 out:
253 read_unlock(&domain->bounce_lock);
254
255 return page;
256 }
257
258 static void
vduse_domain_free_kernel_bounce_pages(struct vduse_iova_domain * domain)259 vduse_domain_free_kernel_bounce_pages(struct vduse_iova_domain *domain)
260 {
261 struct vduse_bounce_map *map;
262 unsigned long pfn, bounce_pfns;
263
264 bounce_pfns = domain->bounce_size >> BOUNCE_MAP_SHIFT;
265
266 for (pfn = 0; pfn < bounce_pfns; pfn++) {
267 map = &domain->bounce_maps[pfn];
268 if (WARN_ON(map->orig_phys != INVALID_PHYS_ADDR))
269 continue;
270
271 if (!map->bounce_page)
272 continue;
273
274 if (!((pfn << BOUNCE_MAP_SHIFT) & ~PAGE_MASK))
275 __free_page(map->bounce_page);
276 map->bounce_page = NULL;
277 }
278 }
279
vduse_domain_add_user_bounce_pages(struct vduse_iova_domain * domain,struct page ** pages,int count)280 int vduse_domain_add_user_bounce_pages(struct vduse_iova_domain *domain,
281 struct page **pages, int count)
282 {
283 struct vduse_bounce_map *map, *head_map;
284 int i, j, ret;
285 int inner_pages = PAGE_SIZE / BOUNCE_MAP_SIZE;
286 int bounce_pfns = domain->bounce_size >> BOUNCE_MAP_SHIFT;
287 struct page *head_page = NULL;
288 bool need_copy;
289
290 /* Now we don't support partial mapping */
291 if (count != (domain->bounce_size >> PAGE_SHIFT))
292 return -EINVAL;
293
294 write_lock(&domain->bounce_lock);
295 ret = -EEXIST;
296 if (domain->user_bounce_pages)
297 goto out;
298
299 for (i = 0; i < count; i++) {
300 need_copy = false;
301 head_map = &domain->bounce_maps[(i * inner_pages)];
302 head_page = head_map->bounce_page;
303 for (j = 0; j < inner_pages; j++) {
304 if ((i * inner_pages + j) >= bounce_pfns)
305 break;
306 map = &domain->bounce_maps[(i * inner_pages + j)];
307 /* Copy kernel page to user page if it's in use */
308 if ((head_page) && (map->orig_phys != INVALID_PHYS_ADDR))
309 need_copy = true;
310 map->user_bounce_page = pages[i];
311 }
312 get_page(pages[i]);
313 if ((head_page) && (need_copy))
314 memcpy_to_page(pages[i], 0,
315 page_address(head_page),
316 PAGE_SIZE);
317 }
318 domain->user_bounce_pages = true;
319 ret = 0;
320 out:
321 write_unlock(&domain->bounce_lock);
322
323 return ret;
324 }
325
vduse_domain_remove_user_bounce_pages(struct vduse_iova_domain * domain)326 void vduse_domain_remove_user_bounce_pages(struct vduse_iova_domain *domain)
327 {
328 struct vduse_bounce_map *map, *head_map;
329 unsigned long i, j, count;
330 int inner_pages = PAGE_SIZE / BOUNCE_MAP_SIZE;
331 int bounce_pfns = domain->bounce_size >> BOUNCE_MAP_SHIFT;
332 struct page *head_page = NULL;
333 bool need_copy;
334
335 write_lock(&domain->bounce_lock);
336 if (!domain->user_bounce_pages)
337 goto out;
338
339 count = domain->bounce_size >> PAGE_SHIFT;
340 for (i = 0; i < count; i++) {
341 need_copy = false;
342 head_map = &domain->bounce_maps[(i * inner_pages)];
343 if (WARN_ON(!head_map->user_bounce_page))
344 continue;
345 head_page = head_map->user_bounce_page;
346
347 for (j = 0; j < inner_pages; j++) {
348 if ((i * inner_pages + j) >= bounce_pfns)
349 break;
350 map = &domain->bounce_maps[(i * inner_pages + j)];
351 if (WARN_ON(!map->user_bounce_page))
352 continue;
353 /* Copy user page to kernel page if it's in use */
354 if ((map->orig_phys != INVALID_PHYS_ADDR) && (head_map->bounce_page))
355 need_copy = true;
356 map->user_bounce_page = NULL;
357 }
358 if (need_copy)
359 memcpy_from_page(page_address(head_map->bounce_page),
360 head_page, 0, PAGE_SIZE);
361 put_page(head_page);
362 }
363 domain->user_bounce_pages = false;
364 out:
365 write_unlock(&domain->bounce_lock);
366 }
367
vduse_domain_reset_bounce_map(struct vduse_iova_domain * domain)368 void vduse_domain_reset_bounce_map(struct vduse_iova_domain *domain)
369 {
370 if (!domain->bounce_map)
371 return;
372
373 spin_lock(&domain->iotlb_lock);
374 if (!domain->bounce_map)
375 goto unlock;
376
377 vduse_iotlb_del_range(domain, 0, domain->bounce_size - 1);
378 domain->bounce_map = 0;
379 unlock:
380 spin_unlock(&domain->iotlb_lock);
381 }
382
vduse_domain_init_bounce_map(struct vduse_iova_domain * domain)383 static int vduse_domain_init_bounce_map(struct vduse_iova_domain *domain)
384 {
385 int ret = 0;
386
387 if (domain->bounce_map)
388 return 0;
389
390 spin_lock(&domain->iotlb_lock);
391 if (domain->bounce_map)
392 goto unlock;
393
394 ret = vduse_iotlb_add_range(domain, 0, domain->bounce_size - 1,
395 0, VHOST_MAP_RW, domain->file, 0);
396 if (ret)
397 goto unlock;
398
399 domain->bounce_map = 1;
400 unlock:
401 spin_unlock(&domain->iotlb_lock);
402 return ret;
403 }
404
405 static dma_addr_t
vduse_domain_alloc_iova(struct iova_domain * iovad,unsigned long size,unsigned long limit)406 vduse_domain_alloc_iova(struct iova_domain *iovad,
407 unsigned long size, unsigned long limit)
408 {
409 unsigned long shift = iova_shift(iovad);
410 unsigned long iova_len = iova_align(iovad, size) >> shift;
411 unsigned long iova_pfn;
412
413 iova_pfn = alloc_iova_fast(iovad, iova_len, limit >> shift, true);
414
415 return (dma_addr_t)iova_pfn << shift;
416 }
417
vduse_domain_free_iova(struct iova_domain * iovad,dma_addr_t iova,size_t size)418 static void vduse_domain_free_iova(struct iova_domain *iovad,
419 dma_addr_t iova, size_t size)
420 {
421 unsigned long shift = iova_shift(iovad);
422 unsigned long iova_len = iova_align(iovad, size) >> shift;
423
424 free_iova_fast(iovad, iova >> shift, iova_len);
425 }
426
vduse_domain_sync_single_for_device(struct vduse_iova_domain * domain,dma_addr_t dma_addr,size_t size,enum dma_data_direction dir)427 void vduse_domain_sync_single_for_device(struct vduse_iova_domain *domain,
428 dma_addr_t dma_addr, size_t size,
429 enum dma_data_direction dir)
430 {
431 read_lock(&domain->bounce_lock);
432 if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL)
433 vduse_domain_bounce(domain, dma_addr, size, DMA_TO_DEVICE);
434 read_unlock(&domain->bounce_lock);
435 }
436
vduse_domain_sync_single_for_cpu(struct vduse_iova_domain * domain,dma_addr_t dma_addr,size_t size,enum dma_data_direction dir)437 void vduse_domain_sync_single_for_cpu(struct vduse_iova_domain *domain,
438 dma_addr_t dma_addr, size_t size,
439 enum dma_data_direction dir)
440 {
441 read_lock(&domain->bounce_lock);
442 if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL)
443 vduse_domain_bounce(domain, dma_addr, size, DMA_FROM_DEVICE);
444 read_unlock(&domain->bounce_lock);
445 }
446
vduse_domain_map_page(struct vduse_iova_domain * domain,struct page * page,unsigned long offset,size_t size,enum dma_data_direction dir,unsigned long attrs)447 dma_addr_t vduse_domain_map_page(struct vduse_iova_domain *domain,
448 struct page *page, unsigned long offset,
449 size_t size, enum dma_data_direction dir,
450 unsigned long attrs)
451 {
452 struct iova_domain *iovad = &domain->stream_iovad;
453 unsigned long limit = domain->bounce_size - 1;
454 phys_addr_t pa = page_to_phys(page) + offset;
455 dma_addr_t iova = vduse_domain_alloc_iova(iovad, size, limit);
456
457 if (!iova)
458 return DMA_MAPPING_ERROR;
459
460 if (vduse_domain_init_bounce_map(domain))
461 goto err;
462
463 read_lock(&domain->bounce_lock);
464 if (vduse_domain_map_bounce_page(domain, (u64)iova, (u64)size, pa))
465 goto err_unlock;
466
467 if (!(attrs & DMA_ATTR_SKIP_CPU_SYNC) &&
468 (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL))
469 vduse_domain_bounce(domain, iova, size, DMA_TO_DEVICE);
470
471 read_unlock(&domain->bounce_lock);
472
473 return iova;
474 err_unlock:
475 read_unlock(&domain->bounce_lock);
476 err:
477 vduse_domain_free_iova(iovad, iova, size);
478 return DMA_MAPPING_ERROR;
479 }
480
vduse_domain_unmap_page(struct vduse_iova_domain * domain,dma_addr_t dma_addr,size_t size,enum dma_data_direction dir,unsigned long attrs)481 void vduse_domain_unmap_page(struct vduse_iova_domain *domain,
482 dma_addr_t dma_addr, size_t size,
483 enum dma_data_direction dir, unsigned long attrs)
484 {
485 struct iova_domain *iovad = &domain->stream_iovad;
486 read_lock(&domain->bounce_lock);
487 if (!(attrs & DMA_ATTR_SKIP_CPU_SYNC) &&
488 (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL))
489 vduse_domain_bounce(domain, dma_addr, size, DMA_FROM_DEVICE);
490
491 vduse_domain_unmap_bounce_page(domain, (u64)dma_addr, (u64)size);
492 read_unlock(&domain->bounce_lock);
493 vduse_domain_free_iova(iovad, dma_addr, size);
494 }
495
vduse_domain_alloc_coherent(struct vduse_iova_domain * domain,size_t size,void * orig)496 dma_addr_t vduse_domain_alloc_coherent(struct vduse_iova_domain *domain,
497 size_t size, void *orig)
498 {
499 struct iova_domain *iovad = &domain->consistent_iovad;
500 unsigned long limit = domain->iova_limit;
501 dma_addr_t iova = vduse_domain_alloc_iova(iovad, size, limit);
502
503 if (!iova)
504 return DMA_MAPPING_ERROR;
505
506 spin_lock(&domain->iotlb_lock);
507 if (vduse_iotlb_add_range(domain, (u64)iova, (u64)iova + size - 1,
508 virt_to_phys(orig), VHOST_MAP_RW,
509 domain->file, (u64)iova)) {
510 spin_unlock(&domain->iotlb_lock);
511 goto err;
512 }
513 spin_unlock(&domain->iotlb_lock);
514
515 return iova;
516
517 err:
518 vduse_domain_free_iova(iovad, iova, size);
519
520 return DMA_MAPPING_ERROR;
521 }
522
vduse_domain_free_coherent(struct vduse_iova_domain * domain,size_t size,dma_addr_t dma_addr,unsigned long attrs)523 void vduse_domain_free_coherent(struct vduse_iova_domain *domain, size_t size,
524 dma_addr_t dma_addr, unsigned long attrs)
525 {
526 struct iova_domain *iovad = &domain->consistent_iovad;
527 struct vhost_iotlb_map *map;
528 struct vdpa_map_file *map_file;
529
530 spin_lock(&domain->iotlb_lock);
531 map = vhost_iotlb_itree_first(domain->iotlb, (u64)dma_addr,
532 (u64)dma_addr + size - 1);
533 if (WARN_ON(!map)) {
534 spin_unlock(&domain->iotlb_lock);
535 return;
536 }
537 map_file = (struct vdpa_map_file *)map->opaque;
538 fput(map_file->file);
539 kfree(map_file);
540 vhost_iotlb_map_free(domain->iotlb, map);
541 spin_unlock(&domain->iotlb_lock);
542
543 vduse_domain_free_iova(iovad, dma_addr, size);
544 }
545
vduse_domain_mmap_fault(struct vm_fault * vmf)546 static vm_fault_t vduse_domain_mmap_fault(struct vm_fault *vmf)
547 {
548 struct vduse_iova_domain *domain = vmf->vma->vm_private_data;
549 unsigned long iova = vmf->pgoff << PAGE_SHIFT;
550 struct page *page;
551
552 if (!domain)
553 return VM_FAULT_SIGBUS;
554
555 if (iova < domain->bounce_size)
556 page = vduse_domain_get_bounce_page(domain, iova);
557 else
558 page = vduse_domain_get_coherent_page(domain, iova);
559
560 if (!page)
561 return VM_FAULT_SIGBUS;
562
563 vmf->page = page;
564
565 return 0;
566 }
567
568 static const struct vm_operations_struct vduse_domain_mmap_ops = {
569 .fault = vduse_domain_mmap_fault,
570 };
571
vduse_domain_mmap(struct file * file,struct vm_area_struct * vma)572 static int vduse_domain_mmap(struct file *file, struct vm_area_struct *vma)
573 {
574 struct vduse_iova_domain *domain = file->private_data;
575
576 vm_flags_set(vma, VM_DONTDUMP | VM_DONTEXPAND);
577 vma->vm_private_data = domain;
578 vma->vm_ops = &vduse_domain_mmap_ops;
579
580 return 0;
581 }
582
vduse_domain_release(struct inode * inode,struct file * file)583 static int vduse_domain_release(struct inode *inode, struct file *file)
584 {
585 struct vduse_iova_domain *domain = file->private_data;
586
587 spin_lock(&domain->iotlb_lock);
588 vduse_iotlb_del_range(domain, 0, ULLONG_MAX);
589 vduse_domain_remove_user_bounce_pages(domain);
590 vduse_domain_free_kernel_bounce_pages(domain);
591 spin_unlock(&domain->iotlb_lock);
592 put_iova_domain(&domain->stream_iovad);
593 put_iova_domain(&domain->consistent_iovad);
594 vhost_iotlb_free(domain->iotlb);
595 vfree(domain->bounce_maps);
596 kfree(domain);
597
598 return 0;
599 }
600
601 static const struct file_operations vduse_domain_fops = {
602 .owner = THIS_MODULE,
603 .mmap = vduse_domain_mmap,
604 .release = vduse_domain_release,
605 };
606
vduse_domain_destroy(struct vduse_iova_domain * domain)607 void vduse_domain_destroy(struct vduse_iova_domain *domain)
608 {
609 fput(domain->file);
610 }
611
612 struct vduse_iova_domain *
vduse_domain_create(unsigned long iova_limit,size_t bounce_size)613 vduse_domain_create(unsigned long iova_limit, size_t bounce_size)
614 {
615 struct vduse_iova_domain *domain;
616 struct file *file;
617 struct vduse_bounce_map *map;
618 unsigned long pfn, bounce_pfns;
619 int ret;
620
621 bounce_pfns = PAGE_ALIGN(bounce_size) >> BOUNCE_MAP_SHIFT;
622 if (iova_limit <= bounce_size)
623 return NULL;
624
625 domain = kzalloc_obj(*domain);
626 if (!domain)
627 return NULL;
628
629 domain->iotlb = vhost_iotlb_alloc(0, 0);
630 if (!domain->iotlb)
631 goto err_iotlb;
632
633 domain->iova_limit = iova_limit;
634 domain->bounce_size = PAGE_ALIGN(bounce_size);
635 domain->bounce_maps = vzalloc(bounce_pfns *
636 sizeof(struct vduse_bounce_map));
637 if (!domain->bounce_maps)
638 goto err_map;
639
640 for (pfn = 0; pfn < bounce_pfns; pfn++) {
641 map = &domain->bounce_maps[pfn];
642 map->orig_phys = INVALID_PHYS_ADDR;
643 }
644 file = anon_inode_getfile("[vduse-domain]", &vduse_domain_fops,
645 domain, O_RDWR);
646 if (IS_ERR(file))
647 goto err_file;
648
649 domain->file = file;
650 rwlock_init(&domain->bounce_lock);
651 spin_lock_init(&domain->iotlb_lock);
652 init_iova_domain(&domain->stream_iovad,
653 BOUNCE_MAP_SIZE, IOVA_START_PFN);
654 ret = iova_domain_init_rcaches(&domain->stream_iovad);
655 if (ret)
656 goto err_iovad_stream;
657 init_iova_domain(&domain->consistent_iovad,
658 PAGE_SIZE, bounce_pfns);
659 ret = iova_domain_init_rcaches(&domain->consistent_iovad);
660 if (ret)
661 goto err_iovad_consistent;
662
663 return domain;
664 err_iovad_consistent:
665 put_iova_domain(&domain->stream_iovad);
666 err_iovad_stream:
667 fput(file);
668 err_file:
669 vfree(domain->bounce_maps);
670 err_map:
671 vhost_iotlb_free(domain->iotlb);
672 err_iotlb:
673 kfree(domain);
674 return NULL;
675 }
676
vduse_domain_init(void)677 int vduse_domain_init(void)
678 {
679 return iova_cache_get();
680 }
681
vduse_domain_exit(void)682 void vduse_domain_exit(void)
683 {
684 iova_cache_put();
685 }
686