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 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(sizeof(*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 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 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 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 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; 107 u64 last = iova + size - 1; 108 109 while (iova <= last) { 110 map = &domain->bounce_maps[iova >> PAGE_SHIFT]; 111 if (!map->bounce_page) { 112 map->bounce_page = alloc_page(GFP_ATOMIC); 113 if (!map->bounce_page) 114 return -ENOMEM; 115 } 116 map->orig_phys = paddr; 117 paddr += PAGE_SIZE; 118 iova += PAGE_SIZE; 119 } 120 return 0; 121 } 122 123 static void vduse_domain_unmap_bounce_page(struct vduse_iova_domain *domain, 124 u64 iova, u64 size) 125 { 126 struct vduse_bounce_map *map; 127 u64 last = iova + size - 1; 128 129 while (iova <= last) { 130 map = &domain->bounce_maps[iova >> PAGE_SHIFT]; 131 map->orig_phys = INVALID_PHYS_ADDR; 132 iova += PAGE_SIZE; 133 } 134 } 135 136 static void do_bounce(phys_addr_t orig, void *addr, size_t size, 137 enum dma_data_direction dir) 138 { 139 unsigned long pfn = PFN_DOWN(orig); 140 unsigned int offset = offset_in_page(orig); 141 struct page *page; 142 unsigned int sz = 0; 143 144 while (size) { 145 sz = min_t(size_t, PAGE_SIZE - offset, size); 146 147 page = pfn_to_page(pfn); 148 if (dir == DMA_TO_DEVICE) 149 memcpy_from_page(addr, page, offset, sz); 150 else 151 memcpy_to_page(page, offset, addr, sz); 152 153 size -= sz; 154 pfn++; 155 addr += sz; 156 offset = 0; 157 } 158 } 159 160 static void vduse_domain_bounce(struct vduse_iova_domain *domain, 161 dma_addr_t iova, size_t size, 162 enum dma_data_direction dir) 163 { 164 struct vduse_bounce_map *map; 165 unsigned int offset; 166 void *addr; 167 size_t sz; 168 169 if (iova >= domain->bounce_size) 170 return; 171 172 while (size) { 173 map = &domain->bounce_maps[iova >> PAGE_SHIFT]; 174 offset = offset_in_page(iova); 175 sz = min_t(size_t, PAGE_SIZE - offset, size); 176 177 if (WARN_ON(!map->bounce_page || 178 map->orig_phys == INVALID_PHYS_ADDR)) 179 return; 180 181 addr = kmap_local_page(map->bounce_page); 182 do_bounce(map->orig_phys + offset, addr + offset, sz, dir); 183 kunmap_local(addr); 184 size -= sz; 185 iova += sz; 186 } 187 } 188 189 static struct page * 190 vduse_domain_get_coherent_page(struct vduse_iova_domain *domain, u64 iova) 191 { 192 u64 start = iova & PAGE_MASK; 193 u64 last = start + PAGE_SIZE - 1; 194 struct vhost_iotlb_map *map; 195 struct page *page = NULL; 196 197 spin_lock(&domain->iotlb_lock); 198 map = vhost_iotlb_itree_first(domain->iotlb, start, last); 199 if (!map) 200 goto out; 201 202 page = pfn_to_page((map->addr + iova - map->start) >> PAGE_SHIFT); 203 get_page(page); 204 out: 205 spin_unlock(&domain->iotlb_lock); 206 207 return page; 208 } 209 210 static struct page * 211 vduse_domain_get_bounce_page(struct vduse_iova_domain *domain, u64 iova) 212 { 213 struct vduse_bounce_map *map; 214 struct page *page = NULL; 215 216 read_lock(&domain->bounce_lock); 217 map = &domain->bounce_maps[iova >> PAGE_SHIFT]; 218 if (domain->user_bounce_pages || !map->bounce_page) 219 goto out; 220 221 page = map->bounce_page; 222 get_page(page); 223 out: 224 read_unlock(&domain->bounce_lock); 225 226 return page; 227 } 228 229 static void 230 vduse_domain_free_kernel_bounce_pages(struct vduse_iova_domain *domain) 231 { 232 struct vduse_bounce_map *map; 233 unsigned long pfn, bounce_pfns; 234 235 bounce_pfns = domain->bounce_size >> PAGE_SHIFT; 236 237 for (pfn = 0; pfn < bounce_pfns; pfn++) { 238 map = &domain->bounce_maps[pfn]; 239 if (WARN_ON(map->orig_phys != INVALID_PHYS_ADDR)) 240 continue; 241 242 if (!map->bounce_page) 243 continue; 244 245 __free_page(map->bounce_page); 246 map->bounce_page = NULL; 247 } 248 } 249 250 int vduse_domain_add_user_bounce_pages(struct vduse_iova_domain *domain, 251 struct page **pages, int count) 252 { 253 struct vduse_bounce_map *map; 254 int i, ret; 255 256 /* Now we don't support partial mapping */ 257 if (count != (domain->bounce_size >> PAGE_SHIFT)) 258 return -EINVAL; 259 260 write_lock(&domain->bounce_lock); 261 ret = -EEXIST; 262 if (domain->user_bounce_pages) 263 goto out; 264 265 for (i = 0; i < count; i++) { 266 map = &domain->bounce_maps[i]; 267 if (map->bounce_page) { 268 /* Copy kernel page to user page if it's in use */ 269 if (map->orig_phys != INVALID_PHYS_ADDR) 270 memcpy_to_page(pages[i], 0, 271 page_address(map->bounce_page), 272 PAGE_SIZE); 273 __free_page(map->bounce_page); 274 } 275 map->bounce_page = pages[i]; 276 get_page(pages[i]); 277 } 278 domain->user_bounce_pages = true; 279 ret = 0; 280 out: 281 write_unlock(&domain->bounce_lock); 282 283 return ret; 284 } 285 286 void vduse_domain_remove_user_bounce_pages(struct vduse_iova_domain *domain) 287 { 288 struct vduse_bounce_map *map; 289 unsigned long i, count; 290 291 write_lock(&domain->bounce_lock); 292 if (!domain->user_bounce_pages) 293 goto out; 294 295 count = domain->bounce_size >> PAGE_SHIFT; 296 for (i = 0; i < count; i++) { 297 struct page *page = NULL; 298 299 map = &domain->bounce_maps[i]; 300 if (WARN_ON(!map->bounce_page)) 301 continue; 302 303 /* Copy user page to kernel page if it's in use */ 304 if (map->orig_phys != INVALID_PHYS_ADDR) { 305 page = alloc_page(GFP_ATOMIC | __GFP_NOFAIL); 306 memcpy_from_page(page_address(page), 307 map->bounce_page, 0, PAGE_SIZE); 308 } 309 put_page(map->bounce_page); 310 map->bounce_page = page; 311 } 312 domain->user_bounce_pages = false; 313 out: 314 write_unlock(&domain->bounce_lock); 315 } 316 317 void vduse_domain_reset_bounce_map(struct vduse_iova_domain *domain) 318 { 319 if (!domain->bounce_map) 320 return; 321 322 spin_lock(&domain->iotlb_lock); 323 if (!domain->bounce_map) 324 goto unlock; 325 326 vduse_iotlb_del_range(domain, 0, domain->bounce_size - 1); 327 domain->bounce_map = 0; 328 unlock: 329 spin_unlock(&domain->iotlb_lock); 330 } 331 332 static int vduse_domain_init_bounce_map(struct vduse_iova_domain *domain) 333 { 334 int ret = 0; 335 336 if (domain->bounce_map) 337 return 0; 338 339 spin_lock(&domain->iotlb_lock); 340 if (domain->bounce_map) 341 goto unlock; 342 343 ret = vduse_iotlb_add_range(domain, 0, domain->bounce_size - 1, 344 0, VHOST_MAP_RW, domain->file, 0); 345 if (ret) 346 goto unlock; 347 348 domain->bounce_map = 1; 349 unlock: 350 spin_unlock(&domain->iotlb_lock); 351 return ret; 352 } 353 354 static dma_addr_t 355 vduse_domain_alloc_iova(struct iova_domain *iovad, 356 unsigned long size, unsigned long limit) 357 { 358 unsigned long shift = iova_shift(iovad); 359 unsigned long iova_len = iova_align(iovad, size) >> shift; 360 unsigned long iova_pfn; 361 362 iova_pfn = alloc_iova_fast(iovad, iova_len, limit >> shift, true); 363 364 return (dma_addr_t)iova_pfn << shift; 365 } 366 367 static void vduse_domain_free_iova(struct iova_domain *iovad, 368 dma_addr_t iova, size_t size) 369 { 370 unsigned long shift = iova_shift(iovad); 371 unsigned long iova_len = iova_align(iovad, size) >> shift; 372 373 free_iova_fast(iovad, iova >> shift, iova_len); 374 } 375 376 dma_addr_t vduse_domain_map_page(struct vduse_iova_domain *domain, 377 struct page *page, unsigned long offset, 378 size_t size, enum dma_data_direction dir, 379 unsigned long attrs) 380 { 381 struct iova_domain *iovad = &domain->stream_iovad; 382 unsigned long limit = domain->bounce_size - 1; 383 phys_addr_t pa = page_to_phys(page) + offset; 384 dma_addr_t iova = vduse_domain_alloc_iova(iovad, size, limit); 385 386 if (!iova) 387 return DMA_MAPPING_ERROR; 388 389 if (vduse_domain_init_bounce_map(domain)) 390 goto err; 391 392 read_lock(&domain->bounce_lock); 393 if (vduse_domain_map_bounce_page(domain, (u64)iova, (u64)size, pa)) 394 goto err_unlock; 395 396 if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL) 397 vduse_domain_bounce(domain, iova, size, DMA_TO_DEVICE); 398 399 read_unlock(&domain->bounce_lock); 400 401 return iova; 402 err_unlock: 403 read_unlock(&domain->bounce_lock); 404 err: 405 vduse_domain_free_iova(iovad, iova, size); 406 return DMA_MAPPING_ERROR; 407 } 408 409 void vduse_domain_unmap_page(struct vduse_iova_domain *domain, 410 dma_addr_t dma_addr, size_t size, 411 enum dma_data_direction dir, unsigned long attrs) 412 { 413 struct iova_domain *iovad = &domain->stream_iovad; 414 415 read_lock(&domain->bounce_lock); 416 if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL) 417 vduse_domain_bounce(domain, dma_addr, size, DMA_FROM_DEVICE); 418 419 vduse_domain_unmap_bounce_page(domain, (u64)dma_addr, (u64)size); 420 read_unlock(&domain->bounce_lock); 421 vduse_domain_free_iova(iovad, dma_addr, size); 422 } 423 424 void *vduse_domain_alloc_coherent(struct vduse_iova_domain *domain, 425 size_t size, dma_addr_t *dma_addr, 426 gfp_t flag, unsigned long attrs) 427 { 428 struct iova_domain *iovad = &domain->consistent_iovad; 429 unsigned long limit = domain->iova_limit; 430 dma_addr_t iova = vduse_domain_alloc_iova(iovad, size, limit); 431 void *orig = alloc_pages_exact(size, flag); 432 433 if (!iova || !orig) 434 goto err; 435 436 spin_lock(&domain->iotlb_lock); 437 if (vduse_iotlb_add_range(domain, (u64)iova, (u64)iova + size - 1, 438 virt_to_phys(orig), VHOST_MAP_RW, 439 domain->file, (u64)iova)) { 440 spin_unlock(&domain->iotlb_lock); 441 goto err; 442 } 443 spin_unlock(&domain->iotlb_lock); 444 445 *dma_addr = iova; 446 447 return orig; 448 err: 449 *dma_addr = DMA_MAPPING_ERROR; 450 if (orig) 451 free_pages_exact(orig, size); 452 if (iova) 453 vduse_domain_free_iova(iovad, iova, size); 454 455 return NULL; 456 } 457 458 void vduse_domain_free_coherent(struct vduse_iova_domain *domain, size_t size, 459 void *vaddr, dma_addr_t dma_addr, 460 unsigned long attrs) 461 { 462 struct iova_domain *iovad = &domain->consistent_iovad; 463 struct vhost_iotlb_map *map; 464 struct vdpa_map_file *map_file; 465 phys_addr_t pa; 466 467 spin_lock(&domain->iotlb_lock); 468 map = vhost_iotlb_itree_first(domain->iotlb, (u64)dma_addr, 469 (u64)dma_addr + size - 1); 470 if (WARN_ON(!map)) { 471 spin_unlock(&domain->iotlb_lock); 472 return; 473 } 474 map_file = (struct vdpa_map_file *)map->opaque; 475 fput(map_file->file); 476 kfree(map_file); 477 pa = map->addr; 478 vhost_iotlb_map_free(domain->iotlb, map); 479 spin_unlock(&domain->iotlb_lock); 480 481 vduse_domain_free_iova(iovad, dma_addr, size); 482 free_pages_exact(phys_to_virt(pa), size); 483 } 484 485 static vm_fault_t vduse_domain_mmap_fault(struct vm_fault *vmf) 486 { 487 struct vduse_iova_domain *domain = vmf->vma->vm_private_data; 488 unsigned long iova = vmf->pgoff << PAGE_SHIFT; 489 struct page *page; 490 491 if (!domain) 492 return VM_FAULT_SIGBUS; 493 494 if (iova < domain->bounce_size) 495 page = vduse_domain_get_bounce_page(domain, iova); 496 else 497 page = vduse_domain_get_coherent_page(domain, iova); 498 499 if (!page) 500 return VM_FAULT_SIGBUS; 501 502 vmf->page = page; 503 504 return 0; 505 } 506 507 static const struct vm_operations_struct vduse_domain_mmap_ops = { 508 .fault = vduse_domain_mmap_fault, 509 }; 510 511 static int vduse_domain_mmap(struct file *file, struct vm_area_struct *vma) 512 { 513 struct vduse_iova_domain *domain = file->private_data; 514 515 vm_flags_set(vma, VM_DONTDUMP | VM_DONTEXPAND); 516 vma->vm_private_data = domain; 517 vma->vm_ops = &vduse_domain_mmap_ops; 518 519 return 0; 520 } 521 522 static int vduse_domain_release(struct inode *inode, struct file *file) 523 { 524 struct vduse_iova_domain *domain = file->private_data; 525 526 spin_lock(&domain->iotlb_lock); 527 vduse_iotlb_del_range(domain, 0, ULLONG_MAX); 528 vduse_domain_remove_user_bounce_pages(domain); 529 vduse_domain_free_kernel_bounce_pages(domain); 530 spin_unlock(&domain->iotlb_lock); 531 put_iova_domain(&domain->stream_iovad); 532 put_iova_domain(&domain->consistent_iovad); 533 vhost_iotlb_free(domain->iotlb); 534 vfree(domain->bounce_maps); 535 kfree(domain); 536 537 return 0; 538 } 539 540 static const struct file_operations vduse_domain_fops = { 541 .owner = THIS_MODULE, 542 .mmap = vduse_domain_mmap, 543 .release = vduse_domain_release, 544 }; 545 546 void vduse_domain_destroy(struct vduse_iova_domain *domain) 547 { 548 fput(domain->file); 549 } 550 551 struct vduse_iova_domain * 552 vduse_domain_create(unsigned long iova_limit, size_t bounce_size) 553 { 554 struct vduse_iova_domain *domain; 555 struct file *file; 556 struct vduse_bounce_map *map; 557 unsigned long pfn, bounce_pfns; 558 int ret; 559 560 bounce_pfns = PAGE_ALIGN(bounce_size) >> PAGE_SHIFT; 561 if (iova_limit <= bounce_size) 562 return NULL; 563 564 domain = kzalloc(sizeof(*domain), GFP_KERNEL); 565 if (!domain) 566 return NULL; 567 568 domain->iotlb = vhost_iotlb_alloc(0, 0); 569 if (!domain->iotlb) 570 goto err_iotlb; 571 572 domain->iova_limit = iova_limit; 573 domain->bounce_size = PAGE_ALIGN(bounce_size); 574 domain->bounce_maps = vzalloc(bounce_pfns * 575 sizeof(struct vduse_bounce_map)); 576 if (!domain->bounce_maps) 577 goto err_map; 578 579 for (pfn = 0; pfn < bounce_pfns; pfn++) { 580 map = &domain->bounce_maps[pfn]; 581 map->orig_phys = INVALID_PHYS_ADDR; 582 } 583 file = anon_inode_getfile("[vduse-domain]", &vduse_domain_fops, 584 domain, O_RDWR); 585 if (IS_ERR(file)) 586 goto err_file; 587 588 domain->file = file; 589 rwlock_init(&domain->bounce_lock); 590 spin_lock_init(&domain->iotlb_lock); 591 init_iova_domain(&domain->stream_iovad, 592 PAGE_SIZE, IOVA_START_PFN); 593 ret = iova_domain_init_rcaches(&domain->stream_iovad); 594 if (ret) 595 goto err_iovad_stream; 596 init_iova_domain(&domain->consistent_iovad, 597 PAGE_SIZE, bounce_pfns); 598 ret = iova_domain_init_rcaches(&domain->consistent_iovad); 599 if (ret) 600 goto err_iovad_consistent; 601 602 return domain; 603 err_iovad_consistent: 604 put_iova_domain(&domain->stream_iovad); 605 err_iovad_stream: 606 fput(file); 607 err_file: 608 vfree(domain->bounce_maps); 609 err_map: 610 vhost_iotlb_free(domain->iotlb); 611 err_iotlb: 612 kfree(domain); 613 return NULL; 614 } 615 616 int vduse_domain_init(void) 617 { 618 return iova_cache_get(); 619 } 620 621 void vduse_domain_exit(void) 622 { 623 iova_cache_put(); 624 } 625