FILE
drm_gem_shmem_helper.c
File preview with syntax highlighting.
linux-6.19.14/drivers/gpu/drm/drm_gem_shmem_helper.c
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Copyright 2018 Noralf Trønnes 4 */ 5 6#include <linux/dma-buf.h> 7#include <linux/export.h> 8#include <linux/module.h> 9#include <linux/mutex.h> 10#include <linux/shmem_fs.h> 11#include <linux/slab.h> 12#include <linux/vmalloc.h> 13 14#ifdef CONFIG_X86 15#include <asm/set_memory.h> 16#endif 17 18#include <kunit/visibility.h> 19 20#include <drm/drm.h> 21#include <drm/drm_device.h> 22#include <drm/drm_drv.h> 23#include <drm/drm_dumb_buffers.h> 24#include <drm/drm_gem_shmem_helper.h> 25#include <drm/drm_prime.h> 26#include <drm/drm_print.h> 27 28MODULE_IMPORT_NS("DMA_BUF"); 29 30/** 31 * DOC: overview 32 * 33 * This library provides helpers for GEM objects backed by shmem buffers 34 * allocated using anonymous pageable memory. 35 * 36 * Functions that operate on the GEM object receive struct &drm_gem_shmem_object. 37 * For GEM callback helpers in struct &drm_gem_object functions, see likewise 38 * named functions with an _object_ infix (e.g., drm_gem_shmem_object_vmap() wraps 39 * drm_gem_shmem_vmap()). These helpers perform the necessary type conversion. 40 */ 41 42static const struct drm_gem_object_funcs drm_gem_shmem_funcs = { 43 .free = drm_gem_shmem_object_free, 44 .print_info = drm_gem_shmem_object_print_info, 45 .pin = drm_gem_shmem_object_pin, 46 .unpin = drm_gem_shmem_object_unpin, 47 .get_sg_table = drm_gem_shmem_object_get_sg_table, 48 .vmap = drm_gem_shmem_object_vmap, 49 .vunmap = drm_gem_shmem_object_vunmap, 50 .mmap = drm_gem_shmem_object_mmap, 51 .vm_ops = &drm_gem_shmem_vm_ops, 52}; 53 54static int __drm_gem_shmem_init(struct drm_device *dev, struct drm_gem_shmem_object *shmem, 55 size_t size, bool private, struct vfsmount *gemfs) 56{ 57 struct drm_gem_object *obj = &shmem->base; 58 int ret = 0; 59 60 if (!obj->funcs) 61 obj->funcs = &drm_gem_shmem_funcs; 62 63 if (private) { 64 drm_gem_private_object_init(dev, obj, size); 65 shmem->map_wc = false; /* dma-buf mappings use always writecombine */ 66 } else { 67 ret = drm_gem_object_init_with_mnt(dev, obj, size, gemfs); 68 } 69 if (ret) { 70 drm_gem_private_object_fini(obj); 71 return ret; 72 } 73 74 ret = drm_gem_create_mmap_offset(obj); 75 if (ret) 76 goto err_release; 77 78 INIT_LIST_HEAD(&shmem->madv_list); 79 80 if (!private) { 81 /* 82 * Our buffers are kept pinned, so allocating them 83 * from the MOVABLE zone is a really bad idea, and 84 * conflicts with CMA. See comments above new_inode() 85 * why this is required _and_ expected if you're 86 * going to pin these pages. 87 */ 88 mapping_set_gfp_mask(obj->filp->f_mapping, GFP_HIGHUSER | 89 __GFP_RETRY_MAYFAIL | __GFP_NOWARN); 90 } 91 92 return 0; 93err_release: 94 drm_gem_object_release(obj); 95 return ret; 96} 97 98/** 99 * drm_gem_shmem_init - Initialize an allocated object. 100 * @dev: DRM device 101 * @shmem: The allocated shmem GEM object. 102 * @size: Buffer size in bytes 103 * 104 * Returns: 105 * 0 on success, or a negative error code on failure. 106 */ 107int drm_gem_shmem_init(struct drm_device *dev, struct drm_gem_shmem_object *shmem, size_t size) 108{ 109 return __drm_gem_shmem_init(dev, shmem, size, false, NULL); 110} 111EXPORT_SYMBOL_GPL(drm_gem_shmem_init); 112 113static struct drm_gem_shmem_object * 114__drm_gem_shmem_create(struct drm_device *dev, size_t size, bool private, 115 struct vfsmount *gemfs) 116{ 117 struct drm_gem_shmem_object *shmem; 118 struct drm_gem_object *obj; 119 int ret = 0; 120 121 size = PAGE_ALIGN(size); 122 123 if (dev->driver->gem_create_object) { 124 obj = dev->driver->gem_create_object(dev, size); 125 if (IS_ERR(obj)) 126 return ERR_CAST(obj); 127 shmem = to_drm_gem_shmem_obj(obj); 128 } else { 129 shmem = kzalloc(sizeof(*shmem), GFP_KERNEL); 130 if (!shmem) 131 return ERR_PTR(-ENOMEM); 132 obj = &shmem->base; 133 } 134 135 ret = __drm_gem_shmem_init(dev, shmem, size, private, gemfs); 136 if (ret) { 137 kfree(obj); 138 return ERR_PTR(ret); 139 } 140 141 return shmem; 142} 143/** 144 * drm_gem_shmem_create - Allocate an object with the given size 145 * @dev: DRM device 146 * @size: Size of the object to allocate 147 * 148 * This function creates a shmem GEM object. 149 * 150 * Returns: 151 * A struct drm_gem_shmem_object * on success or an ERR_PTR()-encoded negative 152 * error code on failure. 153 */ 154struct drm_gem_shmem_object *drm_gem_shmem_create(struct drm_device *dev, size_t size) 155{ 156 return __drm_gem_shmem_create(dev, size, false, NULL); 157} 158EXPORT_SYMBOL_GPL(drm_gem_shmem_create); 159 160/** 161 * drm_gem_shmem_create_with_mnt - Allocate an object with the given size in a 162 * given mountpoint 163 * @dev: DRM device 164 * @size: Size of the object to allocate 165 * @gemfs: tmpfs mount where the GEM object will be created 166 * 167 * This function creates a shmem GEM object in a given tmpfs mountpoint. 168 * 169 * Returns: 170 * A struct drm_gem_shmem_object * on success or an ERR_PTR()-encoded negative 171 * error code on failure. 172 */ 173struct drm_gem_shmem_object *drm_gem_shmem_create_with_mnt(struct drm_device *dev, 174 size_t size, 175 struct vfsmount *gemfs) 176{ 177 return __drm_gem_shmem_create(dev, size, false, gemfs); 178} 179EXPORT_SYMBOL_GPL(drm_gem_shmem_create_with_mnt); 180 181/** 182 * drm_gem_shmem_release - Release resources associated with a shmem GEM object. 183 * @shmem: shmem GEM object 184 * 185 * This function cleans up the GEM object state, but does not free the memory used to store the 186 * object itself. This function is meant to be a dedicated helper for the Rust GEM bindings. 187 */ 188void drm_gem_shmem_release(struct drm_gem_shmem_object *shmem) 189{ 190 struct drm_gem_object *obj = &shmem->base; 191 192 if (drm_gem_is_imported(obj)) { 193 drm_prime_gem_destroy(obj, shmem->sgt); 194 } else { 195 dma_resv_lock(shmem->base.resv, NULL); 196 197 drm_WARN_ON(obj->dev, refcount_read(&shmem->vmap_use_count)); 198 199 if (shmem->sgt) { 200 dma_unmap_sgtable(obj->dev->dev, shmem->sgt, 201 DMA_BIDIRECTIONAL, 0); 202 sg_free_table(shmem->sgt); 203 kfree(shmem->sgt); 204 } 205 if (shmem->pages) 206 drm_gem_shmem_put_pages_locked(shmem); 207 208 drm_WARN_ON(obj->dev, refcount_read(&shmem->pages_use_count)); 209 drm_WARN_ON(obj->dev, refcount_read(&shmem->pages_pin_count)); 210 211 dma_resv_unlock(shmem->base.resv); 212 } 213 214 drm_gem_object_release(obj); 215} 216EXPORT_SYMBOL_GPL(drm_gem_shmem_release); 217 218/** 219 * drm_gem_shmem_free - Free resources associated with a shmem GEM object 220 * @shmem: shmem GEM object to free 221 * 222 * This function cleans up the GEM object state and frees the memory used to 223 * store the object itself. 224 */ 225void drm_gem_shmem_free(struct drm_gem_shmem_object *shmem) 226{ 227 drm_gem_shmem_release(shmem); 228 kfree(shmem); 229} 230EXPORT_SYMBOL_GPL(drm_gem_shmem_free); 231 232static int drm_gem_shmem_get_pages_locked(struct drm_gem_shmem_object *shmem) 233{ 234 struct drm_gem_object *obj = &shmem->base; 235 struct page **pages; 236 237 dma_resv_assert_held(shmem->base.resv); 238 239 if (refcount_inc_not_zero(&shmem->pages_use_count)) 240 return 0; 241 242 pages = drm_gem_get_pages(obj); 243 if (IS_ERR(pages)) { 244 drm_dbg_kms(obj->dev, "Failed to get pages (%ld)\n", 245 PTR_ERR(pages)); 246 return PTR_ERR(pages); 247 } 248 249 /* 250 * TODO: Allocating WC pages which are correctly flushed is only 251 * supported on x86. Ideal solution would be a GFP_WC flag, which also 252 * ttm_pool.c could use. 253 */ 254#ifdef CONFIG_X86 255 if (shmem->map_wc) 256 set_pages_array_wc(pages, obj->size >> PAGE_SHIFT); 257#endif 258 259 shmem->pages = pages; 260 261 refcount_set(&shmem->pages_use_count, 1); 262 263 return 0; 264} 265 266/* 267 * drm_gem_shmem_put_pages_locked - Decrease use count on the backing pages for a shmem GEM object 268 * @shmem: shmem GEM object 269 * 270 * This function decreases the use count and puts the backing pages when use drops to zero. 271 */ 272void drm_gem_shmem_put_pages_locked(struct drm_gem_shmem_object *shmem) 273{ 274 struct drm_gem_object *obj = &shmem->base; 275 276 dma_resv_assert_held(shmem->base.resv); 277 278 if (refcount_dec_and_test(&shmem->pages_use_count)) { 279#ifdef CONFIG_X86 280 if (shmem->map_wc) 281 set_pages_array_wb(shmem->pages, obj->size >> PAGE_SHIFT); 282#endif 283 284 drm_gem_put_pages(obj, shmem->pages, 285 shmem->pages_mark_dirty_on_put, 286 shmem->pages_mark_accessed_on_put); 287 shmem->pages = NULL; 288 } 289} 290EXPORT_SYMBOL_GPL(drm_gem_shmem_put_pages_locked); 291 292int drm_gem_shmem_pin_locked(struct drm_gem_shmem_object *shmem) 293{ 294 int ret; 295 296 dma_resv_assert_held(shmem->base.resv); 297 298 drm_WARN_ON(shmem->base.dev, drm_gem_is_imported(&shmem->base)); 299 300 if (refcount_inc_not_zero(&shmem->pages_pin_count)) 301 return 0; 302 303 ret = drm_gem_shmem_get_pages_locked(shmem); 304 if (!ret) 305 refcount_set(&shmem->pages_pin_count, 1); 306 307 return ret; 308} 309EXPORT_SYMBOL(drm_gem_shmem_pin_locked); 310 311void drm_gem_shmem_unpin_locked(struct drm_gem_shmem_object *shmem) 312{ 313 dma_resv_assert_held(shmem->base.resv); 314 315 if (refcount_dec_and_test(&shmem->pages_pin_count)) 316 drm_gem_shmem_put_pages_locked(shmem); 317} 318EXPORT_SYMBOL(drm_gem_shmem_unpin_locked); 319 320/** 321 * drm_gem_shmem_pin - Pin backing pages for a shmem GEM object 322 * @shmem: shmem GEM object 323 * 324 * This function makes sure the backing pages are pinned in memory while the 325 * buffer is exported. 326 * 327 * Returns: 328 * 0 on success or a negative error code on failure. 329 */ 330int drm_gem_shmem_pin(struct drm_gem_shmem_object *shmem) 331{ 332 struct drm_gem_object *obj = &shmem->base; 333 int ret; 334 335 drm_WARN_ON(obj->dev, drm_gem_is_imported(obj)); 336 337 if (refcount_inc_not_zero(&shmem->pages_pin_count)) 338 return 0; 339 340 ret = dma_resv_lock_interruptible(shmem->base.resv, NULL); 341 if (ret) 342 return ret; 343 ret = drm_gem_shmem_pin_locked(shmem); 344 dma_resv_unlock(shmem->base.resv); 345 346 return ret; 347} 348EXPORT_SYMBOL_GPL(drm_gem_shmem_pin); 349 350/** 351 * drm_gem_shmem_unpin - Unpin backing pages for a shmem GEM object 352 * @shmem: shmem GEM object 353 * 354 * This function removes the requirement that the backing pages are pinned in 355 * memory. 356 */ 357void drm_gem_shmem_unpin(struct drm_gem_shmem_object *shmem) 358{ 359 struct drm_gem_object *obj = &shmem->base; 360 361 drm_WARN_ON(obj->dev, drm_gem_is_imported(obj)); 362 363 if (refcount_dec_not_one(&shmem->pages_pin_count)) 364 return; 365 366 dma_resv_lock(shmem->base.resv, NULL); 367 drm_gem_shmem_unpin_locked(shmem); 368 dma_resv_unlock(shmem->base.resv); 369} 370EXPORT_SYMBOL_GPL(drm_gem_shmem_unpin); 371 372/* 373 * drm_gem_shmem_vmap_locked - Create a virtual mapping for a shmem GEM object 374 * @shmem: shmem GEM object 375 * @map: Returns the kernel virtual address of the SHMEM GEM object's backing 376 * store. 377 * 378 * This function makes sure that a contiguous kernel virtual address mapping 379 * exists for the buffer backing the shmem GEM object. It hides the differences 380 * between dma-buf imported and natively allocated objects. 381 * 382 * Acquired mappings should be cleaned up by calling drm_gem_shmem_vunmap_locked(). 383 * 384 * Returns: 385 * 0 on success or a negative error code on failure. 386 */ 387int drm_gem_shmem_vmap_locked(struct drm_gem_shmem_object *shmem, 388 struct iosys_map *map) 389{ 390 struct drm_gem_object *obj = &shmem->base; 391 int ret = 0; 392 393 dma_resv_assert_held(obj->resv); 394 395 if (drm_gem_is_imported(obj)) { 396 ret = dma_buf_vmap(obj->import_attach->dmabuf, map); 397 } else { 398 pgprot_t prot = PAGE_KERNEL; 399 400 dma_resv_assert_held(shmem->base.resv); 401 402 if (refcount_inc_not_zero(&shmem->vmap_use_count)) { 403 iosys_map_set_vaddr(map, shmem->vaddr); 404 return 0; 405 } 406 407 ret = drm_gem_shmem_pin_locked(shmem); 408 if (ret) 409 return ret; 410 411 if (shmem->map_wc) 412 prot = pgprot_writecombine(prot); 413 shmem->vaddr = vmap(shmem->pages, obj->size >> PAGE_SHIFT, 414 VM_MAP, prot); 415 if (!shmem->vaddr) { 416 ret = -ENOMEM; 417 } else { 418 iosys_map_set_vaddr(map, shmem->vaddr); 419 refcount_set(&shmem->vmap_use_count, 1); 420 } 421 } 422 423 if (ret) { 424 drm_dbg_kms(obj->dev, "Failed to vmap pages, error %d\n", ret); 425 goto err_put_pages; 426 } 427 428 return 0; 429 430err_put_pages: 431 if (!drm_gem_is_imported(obj)) 432 drm_gem_shmem_unpin_locked(shmem); 433 434 return ret; 435} 436EXPORT_SYMBOL_GPL(drm_gem_shmem_vmap_locked); 437 438/* 439 * drm_gem_shmem_vunmap_locked - Unmap a virtual mapping for a shmem GEM object 440 * @shmem: shmem GEM object 441 * @map: Kernel virtual address where the SHMEM GEM object was mapped 442 * 443 * This function cleans up a kernel virtual address mapping acquired by 444 * drm_gem_shmem_vmap_locked(). The mapping is only removed when the use count 445 * drops to zero. 446 * 447 * This function hides the differences between dma-buf imported and natively 448 * allocated objects. 449 */ 450void drm_gem_shmem_vunmap_locked(struct drm_gem_shmem_object *shmem, 451 struct iosys_map *map) 452{ 453 struct drm_gem_object *obj = &shmem->base; 454 455 dma_resv_assert_held(obj->resv); 456 457 if (drm_gem_is_imported(obj)) { 458 dma_buf_vunmap(obj->import_attach->dmabuf, map); 459 } else { 460 dma_resv_assert_held(shmem->base.resv); 461 462 if (refcount_dec_and_test(&shmem->vmap_use_count)) { 463 vunmap(shmem->vaddr); 464 shmem->vaddr = NULL; 465 466 drm_gem_shmem_unpin_locked(shmem); 467 } 468 } 469} 470EXPORT_SYMBOL_GPL(drm_gem_shmem_vunmap_locked); 471 472static int 473drm_gem_shmem_create_with_handle(struct drm_file *file_priv, 474 struct drm_device *dev, size_t size, 475 uint32_t *handle) 476{ 477 struct drm_gem_shmem_object *shmem; 478 int ret; 479 480 shmem = drm_gem_shmem_create(dev, size); 481 if (IS_ERR(shmem)) 482 return PTR_ERR(shmem); 483 484 /* 485 * Allocate an id of idr table where the obj is registered 486 * and handle has the id what user can see. 487 */ 488 ret = drm_gem_handle_create(file_priv, &shmem->base, handle); 489 /* drop reference from allocate - handle holds it now. */ 490 drm_gem_object_put(&shmem->base); 491 492 return ret; 493} 494 495/* Update madvise status, returns true if not purged, else 496 * false or -errno. 497 */ 498int drm_gem_shmem_madvise_locked(struct drm_gem_shmem_object *shmem, int madv) 499{ 500 dma_resv_assert_held(shmem->base.resv); 501 502 if (shmem->madv >= 0) 503 shmem->madv = madv; 504 505 madv = shmem->madv; 506 507 return (madv >= 0); 508} 509EXPORT_SYMBOL_GPL(drm_gem_shmem_madvise_locked); 510 511void drm_gem_shmem_purge_locked(struct drm_gem_shmem_object *shmem) 512{ 513 struct drm_gem_object *obj = &shmem->base; 514 struct drm_device *dev = obj->dev; 515 516 dma_resv_assert_held(shmem->base.resv); 517 518 drm_WARN_ON(obj->dev, !drm_gem_shmem_is_purgeable(shmem)); 519 520 dma_unmap_sgtable(dev->dev, shmem->sgt, DMA_BIDIRECTIONAL, 0); 521 sg_free_table(shmem->sgt); 522 kfree(shmem->sgt); 523 shmem->sgt = NULL; 524 525 drm_gem_shmem_put_pages_locked(shmem); 526 527 shmem->madv = -1; 528 529 drm_vma_node_unmap(&obj->vma_node, dev->anon_inode->i_mapping); 530 drm_gem_free_mmap_offset(obj); 531 532 /* Our goal here is to return as much of the memory as 533 * is possible back to the system as we are called from OOM. 534 * To do this we must instruct the shmfs to drop all of its 535 * backing pages, *now*. 536 */ 537 shmem_truncate_range(file_inode(obj->filp), 0, (loff_t)-1); 538 539 invalidate_mapping_pages(file_inode(obj->filp)->i_mapping, 0, (loff_t)-1); 540} 541EXPORT_SYMBOL_GPL(drm_gem_shmem_purge_locked); 542 543/** 544 * drm_gem_shmem_dumb_create - Create a dumb shmem buffer object 545 * @file: DRM file structure to create the dumb buffer for 546 * @dev: DRM device 547 * @args: IOCTL data 548 * 549 * This function computes the pitch of the dumb buffer and rounds it up to an 550 * integer number of bytes per pixel. Drivers for hardware that doesn't have 551 * any additional restrictions on the pitch can directly use this function as 552 * their &drm_driver.dumb_create callback. 553 * 554 * For hardware with additional restrictions, drivers can adjust the fields 555 * set up by userspace before calling into this function. 556 * 557 * Returns: 558 * 0 on success or a negative error code on failure. 559 */ 560int drm_gem_shmem_dumb_create(struct drm_file *file, struct drm_device *dev, 561 struct drm_mode_create_dumb *args) 562{ 563 int ret; 564 565 ret = drm_mode_size_dumb(dev, args, 0, 0); 566 if (ret) 567 return ret; 568 569 return drm_gem_shmem_create_with_handle(file, dev, args->size, &args->handle); 570} 571EXPORT_SYMBOL_GPL(drm_gem_shmem_dumb_create); 572 573static vm_fault_t drm_gem_shmem_fault(struct vm_fault *vmf) 574{ 575 struct vm_area_struct *vma = vmf->vma; 576 struct drm_gem_object *obj = vma->vm_private_data; 577 struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj); 578 loff_t num_pages = obj->size >> PAGE_SHIFT; 579 vm_fault_t ret; 580 struct page *page; 581 pgoff_t page_offset; 582 583 /* We don't use vmf->pgoff since that has the fake offset */ 584 page_offset = (vmf->address - vma->vm_start) >> PAGE_SHIFT; 585 586 dma_resv_lock(shmem->base.resv, NULL); 587 588 if (page_offset >= num_pages || 589 drm_WARN_ON_ONCE(obj->dev, !shmem->pages) || 590 shmem->madv < 0) { 591 ret = VM_FAULT_SIGBUS; 592 } else { 593 page = shmem->pages[page_offset]; 594 595 ret = vmf_insert_pfn(vma, vmf->address, page_to_pfn(page)); 596 } 597 598 dma_resv_unlock(shmem->base.resv); 599 600 return ret; 601} 602 603static void drm_gem_shmem_vm_open(struct vm_area_struct *vma) 604{ 605 struct drm_gem_object *obj = vma->vm_private_data; 606 struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj); 607 608 drm_WARN_ON(obj->dev, drm_gem_is_imported(obj)); 609 610 dma_resv_lock(shmem->base.resv, NULL); 611 612 /* 613 * We should have already pinned the pages when the buffer was first 614 * mmap'd, vm_open() just grabs an additional reference for the new 615 * mm the vma is getting copied into (ie. on fork()). 616 */ 617 drm_WARN_ON_ONCE(obj->dev, 618 !refcount_inc_not_zero(&shmem->pages_use_count)); 619 620 dma_resv_unlock(shmem->base.resv); 621 622 drm_gem_vm_open(vma); 623} 624 625static void drm_gem_shmem_vm_close(struct vm_area_struct *vma) 626{ 627 struct drm_gem_object *obj = vma->vm_private_data; 628 struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj); 629 630 dma_resv_lock(shmem->base.resv, NULL); 631 drm_gem_shmem_put_pages_locked(shmem); 632 dma_resv_unlock(shmem->base.resv); 633 634 drm_gem_vm_close(vma); 635} 636 637const struct vm_operations_struct drm_gem_shmem_vm_ops = { 638 .fault = drm_gem_shmem_fault, 639 .open = drm_gem_shmem_vm_open, 640 .close = drm_gem_shmem_vm_close, 641}; 642EXPORT_SYMBOL_GPL(drm_gem_shmem_vm_ops); 643 644/** 645 * drm_gem_shmem_mmap - Memory-map a shmem GEM object 646 * @shmem: shmem GEM object 647 * @vma: VMA for the area to be mapped 648 * 649 * This function implements an augmented version of the GEM DRM file mmap 650 * operation for shmem objects. 651 * 652 * Returns: 653 * 0 on success or a negative error code on failure. 654 */ 655int drm_gem_shmem_mmap(struct drm_gem_shmem_object *shmem, struct vm_area_struct *vma) 656{ 657 struct drm_gem_object *obj = &shmem->base; 658 int ret; 659 660 if (drm_gem_is_imported(obj)) { 661 /* Reset both vm_ops and vm_private_data, so we don't end up with 662 * vm_ops pointing to our implementation if the dma-buf backend 663 * doesn't set those fields. 664 */ 665 vma->vm_private_data = NULL; 666 vma->vm_ops = NULL; 667 668 ret = dma_buf_mmap(obj->dma_buf, vma, 0); 669 670 /* Drop the reference drm_gem_mmap_obj() acquired.*/ 671 if (!ret) 672 drm_gem_object_put(obj); 673 674 return ret; 675 } 676 677 if (is_cow_mapping(vma->vm_flags)) 678 return -EINVAL; 679 680 dma_resv_lock(shmem->base.resv, NULL); 681 ret = drm_gem_shmem_get_pages_locked(shmem); 682 dma_resv_unlock(shmem->base.resv); 683 684 if (ret) 685 return ret; 686 687 vm_flags_set(vma, VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP); 688 vma->vm_page_prot = vm_get_page_prot(vma->vm_flags); 689 if (shmem->map_wc) 690 vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); 691 692 return 0; 693} 694EXPORT_SYMBOL_GPL(drm_gem_shmem_mmap); 695 696/** 697 * drm_gem_shmem_print_info() - Print &drm_gem_shmem_object info for debugfs 698 * @shmem: shmem GEM object 699 * @p: DRM printer 700 * @indent: Tab indentation level 701 */ 702void drm_gem_shmem_print_info(const struct drm_gem_shmem_object *shmem, 703 struct drm_printer *p, unsigned int indent) 704{ 705 if (drm_gem_is_imported(&shmem->base)) 706 return; 707 708 drm_printf_indent(p, indent, "pages_pin_count=%u\n", refcount_read(&shmem->pages_pin_count)); 709 drm_printf_indent(p, indent, "pages_use_count=%u\n", refcount_read(&shmem->pages_use_count)); 710 drm_printf_indent(p, indent, "vmap_use_count=%u\n", refcount_read(&shmem->vmap_use_count)); 711 drm_printf_indent(p, indent, "vaddr=%p\n", shmem->vaddr); 712} 713EXPORT_SYMBOL_GPL(drm_gem_shmem_print_info); 714 715/** 716 * drm_gem_shmem_get_sg_table - Provide a scatter/gather table of pinned 717 * pages for a shmem GEM object 718 * @shmem: shmem GEM object 719 * 720 * This function exports a scatter/gather table suitable for PRIME usage by 721 * calling the standard DMA mapping API. 722 * 723 * Drivers who need to acquire an scatter/gather table for objects need to call 724 * drm_gem_shmem_get_pages_sgt() instead. 725 * 726 * Returns: 727 * A pointer to the scatter/gather table of pinned pages or error pointer on failure. 728 */ 729struct sg_table *drm_gem_shmem_get_sg_table(struct drm_gem_shmem_object *shmem) 730{ 731 struct drm_gem_object *obj = &shmem->base; 732 733 drm_WARN_ON(obj->dev, drm_gem_is_imported(obj)); 734 735 return drm_prime_pages_to_sg(obj->dev, shmem->pages, obj->size >> PAGE_SHIFT); 736} 737EXPORT_SYMBOL_GPL(drm_gem_shmem_get_sg_table); 738 739static struct sg_table *drm_gem_shmem_get_pages_sgt_locked(struct drm_gem_shmem_object *shmem) 740{ 741 struct drm_gem_object *obj = &shmem->base; 742 int ret; 743 struct sg_table *sgt; 744 745 if (shmem->sgt) 746 return shmem->sgt; 747 748 drm_WARN_ON(obj->dev, drm_gem_is_imported(obj)); 749 750 ret = drm_gem_shmem_get_pages_locked(shmem); 751 if (ret) 752 return ERR_PTR(ret); 753 754 sgt = drm_gem_shmem_get_sg_table(shmem); 755 if (IS_ERR(sgt)) { 756 ret = PTR_ERR(sgt); 757 goto err_put_pages; 758 } 759 /* Map the pages for use by the h/w. */ 760 ret = dma_map_sgtable(obj->dev->dev, sgt, DMA_BIDIRECTIONAL, 0); 761 if (ret) 762 goto err_free_sgt; 763 764 shmem->sgt = sgt; 765 766 return sgt; 767 768err_free_sgt: 769 sg_free_table(sgt); 770 kfree(sgt); 771err_put_pages: 772 drm_gem_shmem_put_pages_locked(shmem); 773 return ERR_PTR(ret); 774} 775 776/** 777 * drm_gem_shmem_get_pages_sgt - Pin pages, dma map them, and return a 778 * scatter/gather table for a shmem GEM object. 779 * @shmem: shmem GEM object 780 * 781 * This function returns a scatter/gather table suitable for driver usage. If 782 * the sg table doesn't exist, the pages are pinned, dma-mapped, and a sg 783 * table created. 784 * 785 * This is the main function for drivers to get at backing storage, and it hides 786 * and difference between dma-buf imported and natively allocated objects. 787 * drm_gem_shmem_get_sg_table() should not be directly called by drivers. 788 * 789 * Returns: 790 * A pointer to the scatter/gather table of pinned pages or errno on failure. 791 */ 792struct sg_table *drm_gem_shmem_get_pages_sgt(struct drm_gem_shmem_object *shmem) 793{ 794 int ret; 795 struct sg_table *sgt; 796 797 ret = dma_resv_lock_interruptible(shmem->base.resv, NULL); 798 if (ret) 799 return ERR_PTR(ret); 800 sgt = drm_gem_shmem_get_pages_sgt_locked(shmem); 801 dma_resv_unlock(shmem->base.resv); 802 803 return sgt; 804} 805EXPORT_SYMBOL_GPL(drm_gem_shmem_get_pages_sgt); 806 807/** 808 * drm_gem_shmem_prime_import_sg_table - Produce a shmem GEM object from 809 * another driver's scatter/gather table of pinned pages 810 * @dev: Device to import into 811 * @attach: DMA-BUF attachment 812 * @sgt: Scatter/gather table of pinned pages 813 * 814 * This function imports a scatter/gather table exported via DMA-BUF by 815 * another driver. Drivers that use the shmem helpers should set this as their 816 * &drm_driver.gem_prime_import_sg_table callback. 817 * 818 * Returns: 819 * A pointer to a newly created GEM object or an ERR_PTR-encoded negative 820 * error code on failure. 821 */ 822struct drm_gem_object * 823drm_gem_shmem_prime_import_sg_table(struct drm_device *dev, 824 struct dma_buf_attachment *attach, 825 struct sg_table *sgt) 826{ 827 size_t size = PAGE_ALIGN(attach->dmabuf->size); 828 struct drm_gem_shmem_object *shmem; 829 830 shmem = __drm_gem_shmem_create(dev, size, true, NULL); 831 if (IS_ERR(shmem)) 832 return ERR_CAST(shmem); 833 834 shmem->sgt = sgt; 835 836 drm_dbg_prime(dev, "size = %zu\n", size); 837 838 return &shmem->base; 839} 840EXPORT_SYMBOL_GPL(drm_gem_shmem_prime_import_sg_table); 841 842/** 843 * drm_gem_shmem_prime_import_no_map - Import dmabuf without mapping its sg_table 844 * @dev: Device to import into 845 * @dma_buf: dma-buf object to import 846 * 847 * Drivers that use the shmem helpers but also wants to import dmabuf without 848 * mapping its sg_table can use this as their &drm_driver.gem_prime_import 849 * implementation. 850 */ 851struct drm_gem_object *drm_gem_shmem_prime_import_no_map(struct drm_device *dev, 852 struct dma_buf *dma_buf) 853{ 854 struct dma_buf_attachment *attach; 855 struct drm_gem_shmem_object *shmem; 856 struct drm_gem_object *obj; 857 size_t size; 858 int ret; 859 860 if (drm_gem_is_prime_exported_dma_buf(dev, dma_buf)) { 861 /* 862 * Importing dmabuf exported from our own gem increases 863 * refcount on gem itself instead of f_count of dmabuf. 864 */ 865 obj = dma_buf->priv; 866 drm_gem_object_get(obj); 867 return obj; 868 } 869 870 attach = dma_buf_attach(dma_buf, dev->dev); 871 if (IS_ERR(attach)) 872 return ERR_CAST(attach); 873 874 get_dma_buf(dma_buf); 875 876 size = PAGE_ALIGN(attach->dmabuf->size); 877 878 shmem = __drm_gem_shmem_create(dev, size, true, NULL); 879 if (IS_ERR(shmem)) { 880 ret = PTR_ERR(shmem); 881 goto fail_detach; 882 } 883 884 drm_dbg_prime(dev, "size = %zu\n", size); 885 886 shmem->base.import_attach = attach; 887 shmem->base.resv = dma_buf->resv; 888 889 return &shmem->base; 890 891fail_detach: 892 dma_buf_detach(dma_buf, attach); 893 dma_buf_put(dma_buf); 894 895 return ERR_PTR(ret); 896} 897EXPORT_SYMBOL_GPL(drm_gem_shmem_prime_import_no_map); 898 899/* 900 * Kunit helpers 901 */ 902 903#if IS_ENABLED(CONFIG_KUNIT) 904int drm_gem_shmem_vmap(struct drm_gem_shmem_object *shmem, struct iosys_map *map) 905{ 906 struct drm_gem_object *obj = &shmem->base; 907 int ret; 908 909 ret = dma_resv_lock_interruptible(obj->resv, NULL); 910 if (ret) 911 return ret; 912 ret = drm_gem_shmem_vmap_locked(shmem, map); 913 dma_resv_unlock(obj->resv); 914 915 return ret; 916} 917EXPORT_SYMBOL_IF_KUNIT(drm_gem_shmem_vmap); 918 919void drm_gem_shmem_vunmap(struct drm_gem_shmem_object *shmem, struct iosys_map *map) 920{ 921 struct drm_gem_object *obj = &shmem->base; 922 923 dma_resv_lock_interruptible(obj->resv, NULL); 924 drm_gem_shmem_vunmap_locked(shmem, map); 925 dma_resv_unlock(obj->resv); 926} 927EXPORT_SYMBOL_IF_KUNIT(drm_gem_shmem_vunmap); 928 929int drm_gem_shmem_madvise(struct drm_gem_shmem_object *shmem, int madv) 930{ 931 struct drm_gem_object *obj = &shmem->base; 932 int ret; 933 934 ret = dma_resv_lock_interruptible(obj->resv, NULL); 935 if (ret) 936 return ret; 937 ret = drm_gem_shmem_madvise_locked(shmem, madv); 938 dma_resv_unlock(obj->resv); 939 940 return ret; 941} 942EXPORT_SYMBOL_IF_KUNIT(drm_gem_shmem_madvise); 943 944int drm_gem_shmem_purge(struct drm_gem_shmem_object *shmem) 945{ 946 struct drm_gem_object *obj = &shmem->base; 947 int ret; 948 949 ret = dma_resv_lock_interruptible(obj->resv, NULL); 950 if (ret) 951 return ret; 952 drm_gem_shmem_purge_locked(shmem); 953 dma_resv_unlock(obj->resv); 954 955 return 0; 956} 957EXPORT_SYMBOL_IF_KUNIT(drm_gem_shmem_purge); 958#endif 959 960MODULE_DESCRIPTION("DRM SHMEM memory-management helpers"); 961MODULE_IMPORT_NS("DMA_BUF"); 962MODULE_LICENSE("GPL");
~/
Read-only file preview.