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