18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright 2018 Noralf Trønnes 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <linux/dma-buf.h> 78c2ecf20Sopenharmony_ci#include <linux/export.h> 88c2ecf20Sopenharmony_ci#include <linux/mutex.h> 98c2ecf20Sopenharmony_ci#include <linux/shmem_fs.h> 108c2ecf20Sopenharmony_ci#include <linux/slab.h> 118c2ecf20Sopenharmony_ci#include <linux/vmalloc.h> 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include <drm/drm.h> 148c2ecf20Sopenharmony_ci#include <drm/drm_device.h> 158c2ecf20Sopenharmony_ci#include <drm/drm_drv.h> 168c2ecf20Sopenharmony_ci#include <drm/drm_gem_shmem_helper.h> 178c2ecf20Sopenharmony_ci#include <drm/drm_prime.h> 188c2ecf20Sopenharmony_ci#include <drm/drm_print.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci/** 218c2ecf20Sopenharmony_ci * DOC: overview 228c2ecf20Sopenharmony_ci * 238c2ecf20Sopenharmony_ci * This library provides helpers for GEM objects backed by shmem buffers 248c2ecf20Sopenharmony_ci * allocated using anonymous pageable memory. 258c2ecf20Sopenharmony_ci */ 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_cistatic const struct drm_gem_object_funcs drm_gem_shmem_funcs = { 288c2ecf20Sopenharmony_ci .free = drm_gem_shmem_free_object, 298c2ecf20Sopenharmony_ci .print_info = drm_gem_shmem_print_info, 308c2ecf20Sopenharmony_ci .pin = drm_gem_shmem_pin, 318c2ecf20Sopenharmony_ci .unpin = drm_gem_shmem_unpin, 328c2ecf20Sopenharmony_ci .get_sg_table = drm_gem_shmem_get_sg_table, 338c2ecf20Sopenharmony_ci .vmap = drm_gem_shmem_vmap, 348c2ecf20Sopenharmony_ci .vunmap = drm_gem_shmem_vunmap, 358c2ecf20Sopenharmony_ci .mmap = drm_gem_shmem_mmap, 368c2ecf20Sopenharmony_ci}; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_cistatic struct drm_gem_shmem_object * 398c2ecf20Sopenharmony_ci__drm_gem_shmem_create(struct drm_device *dev, size_t size, bool private) 408c2ecf20Sopenharmony_ci{ 418c2ecf20Sopenharmony_ci struct drm_gem_shmem_object *shmem; 428c2ecf20Sopenharmony_ci struct drm_gem_object *obj; 438c2ecf20Sopenharmony_ci int ret = 0; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci size = PAGE_ALIGN(size); 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci if (dev->driver->gem_create_object) 488c2ecf20Sopenharmony_ci obj = dev->driver->gem_create_object(dev, size); 498c2ecf20Sopenharmony_ci else 508c2ecf20Sopenharmony_ci obj = kzalloc(sizeof(*shmem), GFP_KERNEL); 518c2ecf20Sopenharmony_ci if (!obj) 528c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci if (!obj->funcs) 558c2ecf20Sopenharmony_ci obj->funcs = &drm_gem_shmem_funcs; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci if (private) 588c2ecf20Sopenharmony_ci drm_gem_private_object_init(dev, obj, size); 598c2ecf20Sopenharmony_ci else 608c2ecf20Sopenharmony_ci ret = drm_gem_object_init(dev, obj, size); 618c2ecf20Sopenharmony_ci if (ret) 628c2ecf20Sopenharmony_ci goto err_free; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci ret = drm_gem_create_mmap_offset(obj); 658c2ecf20Sopenharmony_ci if (ret) 668c2ecf20Sopenharmony_ci goto err_release; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci shmem = to_drm_gem_shmem_obj(obj); 698c2ecf20Sopenharmony_ci mutex_init(&shmem->pages_lock); 708c2ecf20Sopenharmony_ci mutex_init(&shmem->vmap_lock); 718c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&shmem->madv_list); 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci if (!private) { 748c2ecf20Sopenharmony_ci /* 758c2ecf20Sopenharmony_ci * Our buffers are kept pinned, so allocating them 768c2ecf20Sopenharmony_ci * from the MOVABLE zone is a really bad idea, and 778c2ecf20Sopenharmony_ci * conflicts with CMA. See comments above new_inode() 788c2ecf20Sopenharmony_ci * why this is required _and_ expected if you're 798c2ecf20Sopenharmony_ci * going to pin these pages. 808c2ecf20Sopenharmony_ci */ 818c2ecf20Sopenharmony_ci mapping_set_gfp_mask(obj->filp->f_mapping, GFP_HIGHUSER | 828c2ecf20Sopenharmony_ci __GFP_RETRY_MAYFAIL | __GFP_NOWARN); 838c2ecf20Sopenharmony_ci } 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci return shmem; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_cierr_release: 888c2ecf20Sopenharmony_ci drm_gem_object_release(obj); 898c2ecf20Sopenharmony_cierr_free: 908c2ecf20Sopenharmony_ci kfree(obj); 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci return ERR_PTR(ret); 938c2ecf20Sopenharmony_ci} 948c2ecf20Sopenharmony_ci/** 958c2ecf20Sopenharmony_ci * drm_gem_shmem_create - Allocate an object with the given size 968c2ecf20Sopenharmony_ci * @dev: DRM device 978c2ecf20Sopenharmony_ci * @size: Size of the object to allocate 988c2ecf20Sopenharmony_ci * 998c2ecf20Sopenharmony_ci * This function creates a shmem GEM object. 1008c2ecf20Sopenharmony_ci * 1018c2ecf20Sopenharmony_ci * Returns: 1028c2ecf20Sopenharmony_ci * A struct drm_gem_shmem_object * on success or an ERR_PTR()-encoded negative 1038c2ecf20Sopenharmony_ci * error code on failure. 1048c2ecf20Sopenharmony_ci */ 1058c2ecf20Sopenharmony_cistruct drm_gem_shmem_object *drm_gem_shmem_create(struct drm_device *dev, size_t size) 1068c2ecf20Sopenharmony_ci{ 1078c2ecf20Sopenharmony_ci return __drm_gem_shmem_create(dev, size, false); 1088c2ecf20Sopenharmony_ci} 1098c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(drm_gem_shmem_create); 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci/** 1128c2ecf20Sopenharmony_ci * drm_gem_shmem_free_object - Free resources associated with a shmem GEM object 1138c2ecf20Sopenharmony_ci * @obj: GEM object to free 1148c2ecf20Sopenharmony_ci * 1158c2ecf20Sopenharmony_ci * This function cleans up the GEM object state and frees the memory used to 1168c2ecf20Sopenharmony_ci * store the object itself. It should be used to implement 1178c2ecf20Sopenharmony_ci * &drm_gem_object_funcs.free. 1188c2ecf20Sopenharmony_ci */ 1198c2ecf20Sopenharmony_civoid drm_gem_shmem_free_object(struct drm_gem_object *obj) 1208c2ecf20Sopenharmony_ci{ 1218c2ecf20Sopenharmony_ci struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj); 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci WARN_ON(shmem->vmap_use_count); 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci if (obj->import_attach) { 1268c2ecf20Sopenharmony_ci drm_prime_gem_destroy(obj, shmem->sgt); 1278c2ecf20Sopenharmony_ci } else { 1288c2ecf20Sopenharmony_ci if (shmem->sgt) { 1298c2ecf20Sopenharmony_ci dma_unmap_sgtable(obj->dev->dev, shmem->sgt, 1308c2ecf20Sopenharmony_ci DMA_BIDIRECTIONAL, 0); 1318c2ecf20Sopenharmony_ci sg_free_table(shmem->sgt); 1328c2ecf20Sopenharmony_ci kfree(shmem->sgt); 1338c2ecf20Sopenharmony_ci } 1348c2ecf20Sopenharmony_ci if (shmem->pages) 1358c2ecf20Sopenharmony_ci drm_gem_shmem_put_pages(shmem); 1368c2ecf20Sopenharmony_ci } 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci WARN_ON(shmem->pages_use_count); 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci drm_gem_object_release(obj); 1418c2ecf20Sopenharmony_ci mutex_destroy(&shmem->pages_lock); 1428c2ecf20Sopenharmony_ci mutex_destroy(&shmem->vmap_lock); 1438c2ecf20Sopenharmony_ci kfree(shmem); 1448c2ecf20Sopenharmony_ci} 1458c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(drm_gem_shmem_free_object); 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_cistatic int drm_gem_shmem_get_pages_locked(struct drm_gem_shmem_object *shmem) 1488c2ecf20Sopenharmony_ci{ 1498c2ecf20Sopenharmony_ci struct drm_gem_object *obj = &shmem->base; 1508c2ecf20Sopenharmony_ci struct page **pages; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci if (shmem->pages_use_count++ > 0) 1538c2ecf20Sopenharmony_ci return 0; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci pages = drm_gem_get_pages(obj); 1568c2ecf20Sopenharmony_ci if (IS_ERR(pages)) { 1578c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("Failed to get pages (%ld)\n", PTR_ERR(pages)); 1588c2ecf20Sopenharmony_ci shmem->pages_use_count = 0; 1598c2ecf20Sopenharmony_ci return PTR_ERR(pages); 1608c2ecf20Sopenharmony_ci } 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci shmem->pages = pages; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci return 0; 1658c2ecf20Sopenharmony_ci} 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci/* 1688c2ecf20Sopenharmony_ci * drm_gem_shmem_get_pages - Allocate backing pages for a shmem GEM object 1698c2ecf20Sopenharmony_ci * @shmem: shmem GEM object 1708c2ecf20Sopenharmony_ci * 1718c2ecf20Sopenharmony_ci * This function makes sure that backing pages exists for the shmem GEM object 1728c2ecf20Sopenharmony_ci * and increases the use count. 1738c2ecf20Sopenharmony_ci * 1748c2ecf20Sopenharmony_ci * Returns: 1758c2ecf20Sopenharmony_ci * 0 on success or a negative error code on failure. 1768c2ecf20Sopenharmony_ci */ 1778c2ecf20Sopenharmony_ciint drm_gem_shmem_get_pages(struct drm_gem_shmem_object *shmem) 1788c2ecf20Sopenharmony_ci{ 1798c2ecf20Sopenharmony_ci int ret; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci WARN_ON(shmem->base.import_attach); 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci ret = mutex_lock_interruptible(&shmem->pages_lock); 1848c2ecf20Sopenharmony_ci if (ret) 1858c2ecf20Sopenharmony_ci return ret; 1868c2ecf20Sopenharmony_ci ret = drm_gem_shmem_get_pages_locked(shmem); 1878c2ecf20Sopenharmony_ci mutex_unlock(&shmem->pages_lock); 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci return ret; 1908c2ecf20Sopenharmony_ci} 1918c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_gem_shmem_get_pages); 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_cistatic void drm_gem_shmem_put_pages_locked(struct drm_gem_shmem_object *shmem) 1948c2ecf20Sopenharmony_ci{ 1958c2ecf20Sopenharmony_ci struct drm_gem_object *obj = &shmem->base; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(!shmem->pages_use_count)) 1988c2ecf20Sopenharmony_ci return; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci if (--shmem->pages_use_count > 0) 2018c2ecf20Sopenharmony_ci return; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci drm_gem_put_pages(obj, shmem->pages, 2048c2ecf20Sopenharmony_ci shmem->pages_mark_dirty_on_put, 2058c2ecf20Sopenharmony_ci shmem->pages_mark_accessed_on_put); 2068c2ecf20Sopenharmony_ci shmem->pages = NULL; 2078c2ecf20Sopenharmony_ci} 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci/* 2108c2ecf20Sopenharmony_ci * drm_gem_shmem_put_pages - Decrease use count on the backing pages for a shmem GEM object 2118c2ecf20Sopenharmony_ci * @shmem: shmem GEM object 2128c2ecf20Sopenharmony_ci * 2138c2ecf20Sopenharmony_ci * This function decreases the use count and puts the backing pages when use drops to zero. 2148c2ecf20Sopenharmony_ci */ 2158c2ecf20Sopenharmony_civoid drm_gem_shmem_put_pages(struct drm_gem_shmem_object *shmem) 2168c2ecf20Sopenharmony_ci{ 2178c2ecf20Sopenharmony_ci mutex_lock(&shmem->pages_lock); 2188c2ecf20Sopenharmony_ci drm_gem_shmem_put_pages_locked(shmem); 2198c2ecf20Sopenharmony_ci mutex_unlock(&shmem->pages_lock); 2208c2ecf20Sopenharmony_ci} 2218c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_gem_shmem_put_pages); 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci/** 2248c2ecf20Sopenharmony_ci * drm_gem_shmem_pin - Pin backing pages for a shmem GEM object 2258c2ecf20Sopenharmony_ci * @obj: GEM object 2268c2ecf20Sopenharmony_ci * 2278c2ecf20Sopenharmony_ci * This function makes sure the backing pages are pinned in memory while the 2288c2ecf20Sopenharmony_ci * buffer is exported. It should only be used to implement 2298c2ecf20Sopenharmony_ci * &drm_gem_object_funcs.pin. 2308c2ecf20Sopenharmony_ci * 2318c2ecf20Sopenharmony_ci * Returns: 2328c2ecf20Sopenharmony_ci * 0 on success or a negative error code on failure. 2338c2ecf20Sopenharmony_ci */ 2348c2ecf20Sopenharmony_ciint drm_gem_shmem_pin(struct drm_gem_object *obj) 2358c2ecf20Sopenharmony_ci{ 2368c2ecf20Sopenharmony_ci struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj); 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci WARN_ON(shmem->base.import_attach); 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci return drm_gem_shmem_get_pages(shmem); 2418c2ecf20Sopenharmony_ci} 2428c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_gem_shmem_pin); 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci/** 2458c2ecf20Sopenharmony_ci * drm_gem_shmem_unpin - Unpin backing pages for a shmem GEM object 2468c2ecf20Sopenharmony_ci * @obj: GEM object 2478c2ecf20Sopenharmony_ci * 2488c2ecf20Sopenharmony_ci * This function removes the requirement that the backing pages are pinned in 2498c2ecf20Sopenharmony_ci * memory. It should only be used to implement &drm_gem_object_funcs.unpin. 2508c2ecf20Sopenharmony_ci */ 2518c2ecf20Sopenharmony_civoid drm_gem_shmem_unpin(struct drm_gem_object *obj) 2528c2ecf20Sopenharmony_ci{ 2538c2ecf20Sopenharmony_ci struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj); 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci WARN_ON(shmem->base.import_attach); 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci drm_gem_shmem_put_pages(shmem); 2588c2ecf20Sopenharmony_ci} 2598c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_gem_shmem_unpin); 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_cistatic void *drm_gem_shmem_vmap_locked(struct drm_gem_shmem_object *shmem) 2628c2ecf20Sopenharmony_ci{ 2638c2ecf20Sopenharmony_ci struct drm_gem_object *obj = &shmem->base; 2648c2ecf20Sopenharmony_ci int ret; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci if (shmem->vmap_use_count++ > 0) 2678c2ecf20Sopenharmony_ci return shmem->vaddr; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci if (obj->import_attach) { 2708c2ecf20Sopenharmony_ci shmem->vaddr = dma_buf_vmap(obj->import_attach->dmabuf); 2718c2ecf20Sopenharmony_ci } else { 2728c2ecf20Sopenharmony_ci pgprot_t prot = PAGE_KERNEL; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci ret = drm_gem_shmem_get_pages(shmem); 2758c2ecf20Sopenharmony_ci if (ret) 2768c2ecf20Sopenharmony_ci goto err_zero_use; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci if (!shmem->map_cached) 2798c2ecf20Sopenharmony_ci prot = pgprot_writecombine(prot); 2808c2ecf20Sopenharmony_ci shmem->vaddr = vmap(shmem->pages, obj->size >> PAGE_SHIFT, 2818c2ecf20Sopenharmony_ci VM_MAP, prot); 2828c2ecf20Sopenharmony_ci } 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci if (!shmem->vaddr) { 2858c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("Failed to vmap pages\n"); 2868c2ecf20Sopenharmony_ci ret = -ENOMEM; 2878c2ecf20Sopenharmony_ci goto err_put_pages; 2888c2ecf20Sopenharmony_ci } 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci return shmem->vaddr; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_cierr_put_pages: 2938c2ecf20Sopenharmony_ci if (!obj->import_attach) 2948c2ecf20Sopenharmony_ci drm_gem_shmem_put_pages(shmem); 2958c2ecf20Sopenharmony_cierr_zero_use: 2968c2ecf20Sopenharmony_ci shmem->vmap_use_count = 0; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci return ERR_PTR(ret); 2998c2ecf20Sopenharmony_ci} 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci/* 3028c2ecf20Sopenharmony_ci * drm_gem_shmem_vmap - Create a virtual mapping for a shmem GEM object 3038c2ecf20Sopenharmony_ci * @shmem: shmem GEM object 3048c2ecf20Sopenharmony_ci * 3058c2ecf20Sopenharmony_ci * This function makes sure that a contiguous kernel virtual address mapping 3068c2ecf20Sopenharmony_ci * exists for the buffer backing the shmem GEM object. 3078c2ecf20Sopenharmony_ci * 3088c2ecf20Sopenharmony_ci * This function can be used to implement &drm_gem_object_funcs.vmap. But it can 3098c2ecf20Sopenharmony_ci * also be called by drivers directly, in which case it will hide the 3108c2ecf20Sopenharmony_ci * differences between dma-buf imported and natively allocated objects. 3118c2ecf20Sopenharmony_ci * 3128c2ecf20Sopenharmony_ci * Acquired mappings should be cleaned up by calling drm_gem_shmem_vunmap(). 3138c2ecf20Sopenharmony_ci * 3148c2ecf20Sopenharmony_ci * Returns: 3158c2ecf20Sopenharmony_ci * 0 on success or a negative error code on failure. 3168c2ecf20Sopenharmony_ci */ 3178c2ecf20Sopenharmony_civoid *drm_gem_shmem_vmap(struct drm_gem_object *obj) 3188c2ecf20Sopenharmony_ci{ 3198c2ecf20Sopenharmony_ci struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj); 3208c2ecf20Sopenharmony_ci void *vaddr; 3218c2ecf20Sopenharmony_ci int ret; 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci ret = mutex_lock_interruptible(&shmem->vmap_lock); 3248c2ecf20Sopenharmony_ci if (ret) 3258c2ecf20Sopenharmony_ci return ERR_PTR(ret); 3268c2ecf20Sopenharmony_ci vaddr = drm_gem_shmem_vmap_locked(shmem); 3278c2ecf20Sopenharmony_ci mutex_unlock(&shmem->vmap_lock); 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci return vaddr; 3308c2ecf20Sopenharmony_ci} 3318c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_gem_shmem_vmap); 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_cistatic void drm_gem_shmem_vunmap_locked(struct drm_gem_shmem_object *shmem) 3348c2ecf20Sopenharmony_ci{ 3358c2ecf20Sopenharmony_ci struct drm_gem_object *obj = &shmem->base; 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(!shmem->vmap_use_count)) 3388c2ecf20Sopenharmony_ci return; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci if (--shmem->vmap_use_count > 0) 3418c2ecf20Sopenharmony_ci return; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci if (obj->import_attach) { 3448c2ecf20Sopenharmony_ci dma_buf_vunmap(obj->import_attach->dmabuf, shmem->vaddr); 3458c2ecf20Sopenharmony_ci } else { 3468c2ecf20Sopenharmony_ci vunmap(shmem->vaddr); 3478c2ecf20Sopenharmony_ci drm_gem_shmem_put_pages(shmem); 3488c2ecf20Sopenharmony_ci } 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci shmem->vaddr = NULL; 3518c2ecf20Sopenharmony_ci} 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci/* 3548c2ecf20Sopenharmony_ci * drm_gem_shmem_vunmap - Unmap a virtual mapping fo a shmem GEM object 3558c2ecf20Sopenharmony_ci * @shmem: shmem GEM object 3568c2ecf20Sopenharmony_ci * 3578c2ecf20Sopenharmony_ci * This function cleans up a kernel virtual address mapping acquired by 3588c2ecf20Sopenharmony_ci * drm_gem_shmem_vmap(). The mapping is only removed when the use count drops to 3598c2ecf20Sopenharmony_ci * zero. 3608c2ecf20Sopenharmony_ci * 3618c2ecf20Sopenharmony_ci * This function can be used to implement &drm_gem_object_funcs.vmap. But it can 3628c2ecf20Sopenharmony_ci * also be called by drivers directly, in which case it will hide the 3638c2ecf20Sopenharmony_ci * differences between dma-buf imported and natively allocated objects. 3648c2ecf20Sopenharmony_ci */ 3658c2ecf20Sopenharmony_civoid drm_gem_shmem_vunmap(struct drm_gem_object *obj, void *vaddr) 3668c2ecf20Sopenharmony_ci{ 3678c2ecf20Sopenharmony_ci struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj); 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci mutex_lock(&shmem->vmap_lock); 3708c2ecf20Sopenharmony_ci drm_gem_shmem_vunmap_locked(shmem); 3718c2ecf20Sopenharmony_ci mutex_unlock(&shmem->vmap_lock); 3728c2ecf20Sopenharmony_ci} 3738c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_gem_shmem_vunmap); 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_cistruct drm_gem_shmem_object * 3768c2ecf20Sopenharmony_cidrm_gem_shmem_create_with_handle(struct drm_file *file_priv, 3778c2ecf20Sopenharmony_ci struct drm_device *dev, size_t size, 3788c2ecf20Sopenharmony_ci uint32_t *handle) 3798c2ecf20Sopenharmony_ci{ 3808c2ecf20Sopenharmony_ci struct drm_gem_shmem_object *shmem; 3818c2ecf20Sopenharmony_ci int ret; 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci shmem = drm_gem_shmem_create(dev, size); 3848c2ecf20Sopenharmony_ci if (IS_ERR(shmem)) 3858c2ecf20Sopenharmony_ci return shmem; 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci /* 3888c2ecf20Sopenharmony_ci * Allocate an id of idr table where the obj is registered 3898c2ecf20Sopenharmony_ci * and handle has the id what user can see. 3908c2ecf20Sopenharmony_ci */ 3918c2ecf20Sopenharmony_ci ret = drm_gem_handle_create(file_priv, &shmem->base, handle); 3928c2ecf20Sopenharmony_ci /* drop reference from allocate - handle holds it now. */ 3938c2ecf20Sopenharmony_ci drm_gem_object_put(&shmem->base); 3948c2ecf20Sopenharmony_ci if (ret) 3958c2ecf20Sopenharmony_ci return ERR_PTR(ret); 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci return shmem; 3988c2ecf20Sopenharmony_ci} 3998c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_gem_shmem_create_with_handle); 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci/* Update madvise status, returns true if not purged, else 4028c2ecf20Sopenharmony_ci * false or -errno. 4038c2ecf20Sopenharmony_ci */ 4048c2ecf20Sopenharmony_ciint drm_gem_shmem_madvise(struct drm_gem_object *obj, int madv) 4058c2ecf20Sopenharmony_ci{ 4068c2ecf20Sopenharmony_ci struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj); 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci mutex_lock(&shmem->pages_lock); 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci if (shmem->madv >= 0) 4118c2ecf20Sopenharmony_ci shmem->madv = madv; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci madv = shmem->madv; 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci mutex_unlock(&shmem->pages_lock); 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci return (madv >= 0); 4188c2ecf20Sopenharmony_ci} 4198c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_gem_shmem_madvise); 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_civoid drm_gem_shmem_purge_locked(struct drm_gem_object *obj) 4228c2ecf20Sopenharmony_ci{ 4238c2ecf20Sopenharmony_ci struct drm_device *dev = obj->dev; 4248c2ecf20Sopenharmony_ci struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj); 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci WARN_ON(!drm_gem_shmem_is_purgeable(shmem)); 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci dma_unmap_sgtable(obj->dev->dev, shmem->sgt, DMA_BIDIRECTIONAL, 0); 4298c2ecf20Sopenharmony_ci sg_free_table(shmem->sgt); 4308c2ecf20Sopenharmony_ci kfree(shmem->sgt); 4318c2ecf20Sopenharmony_ci shmem->sgt = NULL; 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci drm_gem_shmem_put_pages_locked(shmem); 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci shmem->madv = -1; 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci drm_vma_node_unmap(&obj->vma_node, dev->anon_inode->i_mapping); 4388c2ecf20Sopenharmony_ci drm_gem_free_mmap_offset(obj); 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci /* Our goal here is to return as much of the memory as 4418c2ecf20Sopenharmony_ci * is possible back to the system as we are called from OOM. 4428c2ecf20Sopenharmony_ci * To do this we must instruct the shmfs to drop all of its 4438c2ecf20Sopenharmony_ci * backing pages, *now*. 4448c2ecf20Sopenharmony_ci */ 4458c2ecf20Sopenharmony_ci shmem_truncate_range(file_inode(obj->filp), 0, (loff_t)-1); 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci invalidate_mapping_pages(file_inode(obj->filp)->i_mapping, 4488c2ecf20Sopenharmony_ci 0, (loff_t)-1); 4498c2ecf20Sopenharmony_ci} 4508c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_gem_shmem_purge_locked); 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_cibool drm_gem_shmem_purge(struct drm_gem_object *obj) 4538c2ecf20Sopenharmony_ci{ 4548c2ecf20Sopenharmony_ci struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj); 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci if (!mutex_trylock(&shmem->pages_lock)) 4578c2ecf20Sopenharmony_ci return false; 4588c2ecf20Sopenharmony_ci drm_gem_shmem_purge_locked(obj); 4598c2ecf20Sopenharmony_ci mutex_unlock(&shmem->pages_lock); 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci return true; 4628c2ecf20Sopenharmony_ci} 4638c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_gem_shmem_purge); 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci/** 4668c2ecf20Sopenharmony_ci * drm_gem_shmem_create_object_cached - Create a shmem buffer object with 4678c2ecf20Sopenharmony_ci * cached mappings 4688c2ecf20Sopenharmony_ci * @dev: DRM device 4698c2ecf20Sopenharmony_ci * @size: Size of the object to allocate 4708c2ecf20Sopenharmony_ci * 4718c2ecf20Sopenharmony_ci * By default, shmem buffer objects use writecombine mappings. This 4728c2ecf20Sopenharmony_ci * function implements struct drm_driver.gem_create_object for shmem 4738c2ecf20Sopenharmony_ci * buffer objects with cached mappings. 4748c2ecf20Sopenharmony_ci * 4758c2ecf20Sopenharmony_ci * Returns: 4768c2ecf20Sopenharmony_ci * A struct drm_gem_shmem_object * on success or NULL negative on failure. 4778c2ecf20Sopenharmony_ci */ 4788c2ecf20Sopenharmony_cistruct drm_gem_object * 4798c2ecf20Sopenharmony_cidrm_gem_shmem_create_object_cached(struct drm_device *dev, size_t size) 4808c2ecf20Sopenharmony_ci{ 4818c2ecf20Sopenharmony_ci struct drm_gem_shmem_object *shmem; 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci shmem = kzalloc(sizeof(*shmem), GFP_KERNEL); 4848c2ecf20Sopenharmony_ci if (!shmem) 4858c2ecf20Sopenharmony_ci return NULL; 4868c2ecf20Sopenharmony_ci shmem->map_cached = true; 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci return &shmem->base; 4898c2ecf20Sopenharmony_ci} 4908c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_gem_shmem_create_object_cached); 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci/** 4938c2ecf20Sopenharmony_ci * drm_gem_shmem_dumb_create - Create a dumb shmem buffer object 4948c2ecf20Sopenharmony_ci * @file: DRM file structure to create the dumb buffer for 4958c2ecf20Sopenharmony_ci * @dev: DRM device 4968c2ecf20Sopenharmony_ci * @args: IOCTL data 4978c2ecf20Sopenharmony_ci * 4988c2ecf20Sopenharmony_ci * This function computes the pitch of the dumb buffer and rounds it up to an 4998c2ecf20Sopenharmony_ci * integer number of bytes per pixel. Drivers for hardware that doesn't have 5008c2ecf20Sopenharmony_ci * any additional restrictions on the pitch can directly use this function as 5018c2ecf20Sopenharmony_ci * their &drm_driver.dumb_create callback. 5028c2ecf20Sopenharmony_ci * 5038c2ecf20Sopenharmony_ci * For hardware with additional restrictions, drivers can adjust the fields 5048c2ecf20Sopenharmony_ci * set up by userspace before calling into this function. 5058c2ecf20Sopenharmony_ci * 5068c2ecf20Sopenharmony_ci * Returns: 5078c2ecf20Sopenharmony_ci * 0 on success or a negative error code on failure. 5088c2ecf20Sopenharmony_ci */ 5098c2ecf20Sopenharmony_ciint drm_gem_shmem_dumb_create(struct drm_file *file, struct drm_device *dev, 5108c2ecf20Sopenharmony_ci struct drm_mode_create_dumb *args) 5118c2ecf20Sopenharmony_ci{ 5128c2ecf20Sopenharmony_ci u32 min_pitch = DIV_ROUND_UP(args->width * args->bpp, 8); 5138c2ecf20Sopenharmony_ci struct drm_gem_shmem_object *shmem; 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci if (!args->pitch || !args->size) { 5168c2ecf20Sopenharmony_ci args->pitch = min_pitch; 5178c2ecf20Sopenharmony_ci args->size = args->pitch * args->height; 5188c2ecf20Sopenharmony_ci } else { 5198c2ecf20Sopenharmony_ci /* ensure sane minimum values */ 5208c2ecf20Sopenharmony_ci if (args->pitch < min_pitch) 5218c2ecf20Sopenharmony_ci args->pitch = min_pitch; 5228c2ecf20Sopenharmony_ci if (args->size < args->pitch * args->height) 5238c2ecf20Sopenharmony_ci args->size = args->pitch * args->height; 5248c2ecf20Sopenharmony_ci } 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci shmem = drm_gem_shmem_create_with_handle(file, dev, args->size, &args->handle); 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci return PTR_ERR_OR_ZERO(shmem); 5298c2ecf20Sopenharmony_ci} 5308c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(drm_gem_shmem_dumb_create); 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_cistatic vm_fault_t drm_gem_shmem_fault(struct vm_fault *vmf) 5338c2ecf20Sopenharmony_ci{ 5348c2ecf20Sopenharmony_ci struct vm_area_struct *vma = vmf->vma; 5358c2ecf20Sopenharmony_ci struct drm_gem_object *obj = vma->vm_private_data; 5368c2ecf20Sopenharmony_ci struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj); 5378c2ecf20Sopenharmony_ci loff_t num_pages = obj->size >> PAGE_SHIFT; 5388c2ecf20Sopenharmony_ci vm_fault_t ret; 5398c2ecf20Sopenharmony_ci struct page *page; 5408c2ecf20Sopenharmony_ci pgoff_t page_offset; 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci /* We don't use vmf->pgoff since that has the fake offset */ 5438c2ecf20Sopenharmony_ci page_offset = (vmf->address - vma->vm_start) >> PAGE_SHIFT; 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci mutex_lock(&shmem->pages_lock); 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci if (page_offset >= num_pages || 5488c2ecf20Sopenharmony_ci WARN_ON_ONCE(!shmem->pages) || 5498c2ecf20Sopenharmony_ci shmem->madv < 0) { 5508c2ecf20Sopenharmony_ci ret = VM_FAULT_SIGBUS; 5518c2ecf20Sopenharmony_ci } else { 5528c2ecf20Sopenharmony_ci page = shmem->pages[page_offset]; 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci ret = vmf_insert_page(vma, vmf->address, page); 5558c2ecf20Sopenharmony_ci } 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci mutex_unlock(&shmem->pages_lock); 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci return ret; 5608c2ecf20Sopenharmony_ci} 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_cistatic void drm_gem_shmem_vm_open(struct vm_area_struct *vma) 5638c2ecf20Sopenharmony_ci{ 5648c2ecf20Sopenharmony_ci struct drm_gem_object *obj = vma->vm_private_data; 5658c2ecf20Sopenharmony_ci struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj); 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci WARN_ON(shmem->base.import_attach); 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci mutex_lock(&shmem->pages_lock); 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci /* 5728c2ecf20Sopenharmony_ci * We should have already pinned the pages when the buffer was first 5738c2ecf20Sopenharmony_ci * mmap'd, vm_open() just grabs an additional reference for the new 5748c2ecf20Sopenharmony_ci * mm the vma is getting copied into (ie. on fork()). 5758c2ecf20Sopenharmony_ci */ 5768c2ecf20Sopenharmony_ci if (!WARN_ON_ONCE(!shmem->pages_use_count)) 5778c2ecf20Sopenharmony_ci shmem->pages_use_count++; 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci mutex_unlock(&shmem->pages_lock); 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci drm_gem_vm_open(vma); 5828c2ecf20Sopenharmony_ci} 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_cistatic void drm_gem_shmem_vm_close(struct vm_area_struct *vma) 5858c2ecf20Sopenharmony_ci{ 5868c2ecf20Sopenharmony_ci struct drm_gem_object *obj = vma->vm_private_data; 5878c2ecf20Sopenharmony_ci struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj); 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci drm_gem_shmem_put_pages(shmem); 5908c2ecf20Sopenharmony_ci drm_gem_vm_close(vma); 5918c2ecf20Sopenharmony_ci} 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_cistatic const struct vm_operations_struct drm_gem_shmem_vm_ops = { 5948c2ecf20Sopenharmony_ci .fault = drm_gem_shmem_fault, 5958c2ecf20Sopenharmony_ci .open = drm_gem_shmem_vm_open, 5968c2ecf20Sopenharmony_ci .close = drm_gem_shmem_vm_close, 5978c2ecf20Sopenharmony_ci}; 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci/** 6008c2ecf20Sopenharmony_ci * drm_gem_shmem_mmap - Memory-map a shmem GEM object 6018c2ecf20Sopenharmony_ci * @obj: gem object 6028c2ecf20Sopenharmony_ci * @vma: VMA for the area to be mapped 6038c2ecf20Sopenharmony_ci * 6048c2ecf20Sopenharmony_ci * This function implements an augmented version of the GEM DRM file mmap 6058c2ecf20Sopenharmony_ci * operation for shmem objects. Drivers which employ the shmem helpers should 6068c2ecf20Sopenharmony_ci * use this function as their &drm_gem_object_funcs.mmap handler. 6078c2ecf20Sopenharmony_ci * 6088c2ecf20Sopenharmony_ci * Returns: 6098c2ecf20Sopenharmony_ci * 0 on success or a negative error code on failure. 6108c2ecf20Sopenharmony_ci */ 6118c2ecf20Sopenharmony_ciint drm_gem_shmem_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma) 6128c2ecf20Sopenharmony_ci{ 6138c2ecf20Sopenharmony_ci struct drm_gem_shmem_object *shmem; 6148c2ecf20Sopenharmony_ci int ret; 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci if (obj->import_attach) { 6178c2ecf20Sopenharmony_ci /* Reset both vm_ops and vm_private_data, so we don't end up with 6188c2ecf20Sopenharmony_ci * vm_ops pointing to our implementation if the dma-buf backend 6198c2ecf20Sopenharmony_ci * doesn't set those fields. 6208c2ecf20Sopenharmony_ci */ 6218c2ecf20Sopenharmony_ci vma->vm_private_data = NULL; 6228c2ecf20Sopenharmony_ci vma->vm_ops = NULL; 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci ret = dma_buf_mmap(obj->dma_buf, vma, 0); 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci /* Drop the reference drm_gem_mmap_obj() acquired.*/ 6278c2ecf20Sopenharmony_ci if (!ret) 6288c2ecf20Sopenharmony_ci drm_gem_object_put(obj); 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci return ret; 6318c2ecf20Sopenharmony_ci } 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci shmem = to_drm_gem_shmem_obj(obj); 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci ret = drm_gem_shmem_get_pages(shmem); 6368c2ecf20Sopenharmony_ci if (ret) 6378c2ecf20Sopenharmony_ci return ret; 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci vma->vm_flags |= VM_MIXEDMAP | VM_DONTEXPAND; 6408c2ecf20Sopenharmony_ci vma->vm_page_prot = vm_get_page_prot(vma->vm_flags); 6418c2ecf20Sopenharmony_ci if (!shmem->map_cached) 6428c2ecf20Sopenharmony_ci vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); 6438c2ecf20Sopenharmony_ci vma->vm_ops = &drm_gem_shmem_vm_ops; 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci return 0; 6468c2ecf20Sopenharmony_ci} 6478c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(drm_gem_shmem_mmap); 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci/** 6508c2ecf20Sopenharmony_ci * drm_gem_shmem_print_info() - Print &drm_gem_shmem_object info for debugfs 6518c2ecf20Sopenharmony_ci * @p: DRM printer 6528c2ecf20Sopenharmony_ci * @indent: Tab indentation level 6538c2ecf20Sopenharmony_ci * @obj: GEM object 6548c2ecf20Sopenharmony_ci * 6558c2ecf20Sopenharmony_ci * This implements the &drm_gem_object_funcs.info callback. 6568c2ecf20Sopenharmony_ci */ 6578c2ecf20Sopenharmony_civoid drm_gem_shmem_print_info(struct drm_printer *p, unsigned int indent, 6588c2ecf20Sopenharmony_ci const struct drm_gem_object *obj) 6598c2ecf20Sopenharmony_ci{ 6608c2ecf20Sopenharmony_ci const struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj); 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci drm_printf_indent(p, indent, "pages_use_count=%u\n", shmem->pages_use_count); 6638c2ecf20Sopenharmony_ci drm_printf_indent(p, indent, "vmap_use_count=%u\n", shmem->vmap_use_count); 6648c2ecf20Sopenharmony_ci drm_printf_indent(p, indent, "vaddr=%p\n", shmem->vaddr); 6658c2ecf20Sopenharmony_ci} 6668c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_gem_shmem_print_info); 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci/** 6698c2ecf20Sopenharmony_ci * drm_gem_shmem_get_sg_table - Provide a scatter/gather table of pinned 6708c2ecf20Sopenharmony_ci * pages for a shmem GEM object 6718c2ecf20Sopenharmony_ci * @obj: GEM object 6728c2ecf20Sopenharmony_ci * 6738c2ecf20Sopenharmony_ci * This function exports a scatter/gather table suitable for PRIME usage by 6748c2ecf20Sopenharmony_ci * calling the standard DMA mapping API. Drivers should not call this function 6758c2ecf20Sopenharmony_ci * directly, instead it should only be used as an implementation for 6768c2ecf20Sopenharmony_ci * &drm_gem_object_funcs.get_sg_table. 6778c2ecf20Sopenharmony_ci * 6788c2ecf20Sopenharmony_ci * Drivers who need to acquire an scatter/gather table for objects need to call 6798c2ecf20Sopenharmony_ci * drm_gem_shmem_get_pages_sgt() instead. 6808c2ecf20Sopenharmony_ci * 6818c2ecf20Sopenharmony_ci * Returns: 6828c2ecf20Sopenharmony_ci * A pointer to the scatter/gather table of pinned pages or NULL on failure. 6838c2ecf20Sopenharmony_ci */ 6848c2ecf20Sopenharmony_cistruct sg_table *drm_gem_shmem_get_sg_table(struct drm_gem_object *obj) 6858c2ecf20Sopenharmony_ci{ 6868c2ecf20Sopenharmony_ci struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj); 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci WARN_ON(shmem->base.import_attach); 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci return drm_prime_pages_to_sg(obj->dev, shmem->pages, obj->size >> PAGE_SHIFT); 6918c2ecf20Sopenharmony_ci} 6928c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(drm_gem_shmem_get_sg_table); 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_ci/** 6958c2ecf20Sopenharmony_ci * drm_gem_shmem_get_pages_sgt - Pin pages, dma map them, and return a 6968c2ecf20Sopenharmony_ci * scatter/gather table for a shmem GEM object. 6978c2ecf20Sopenharmony_ci * @obj: GEM object 6988c2ecf20Sopenharmony_ci * 6998c2ecf20Sopenharmony_ci * This function returns a scatter/gather table suitable for driver usage. If 7008c2ecf20Sopenharmony_ci * the sg table doesn't exist, the pages are pinned, dma-mapped, and a sg 7018c2ecf20Sopenharmony_ci * table created. 7028c2ecf20Sopenharmony_ci * 7038c2ecf20Sopenharmony_ci * This is the main function for drivers to get at backing storage, and it hides 7048c2ecf20Sopenharmony_ci * and difference between dma-buf imported and natively allocated objects. 7058c2ecf20Sopenharmony_ci * drm_gem_shmem_get_sg_table() should not be directly called by drivers. 7068c2ecf20Sopenharmony_ci * 7078c2ecf20Sopenharmony_ci * Returns: 7088c2ecf20Sopenharmony_ci * A pointer to the scatter/gather table of pinned pages or errno on failure. 7098c2ecf20Sopenharmony_ci */ 7108c2ecf20Sopenharmony_cistruct sg_table *drm_gem_shmem_get_pages_sgt(struct drm_gem_object *obj) 7118c2ecf20Sopenharmony_ci{ 7128c2ecf20Sopenharmony_ci int ret; 7138c2ecf20Sopenharmony_ci struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj); 7148c2ecf20Sopenharmony_ci struct sg_table *sgt; 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci if (shmem->sgt) 7178c2ecf20Sopenharmony_ci return shmem->sgt; 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci WARN_ON(obj->import_attach); 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci ret = drm_gem_shmem_get_pages(shmem); 7228c2ecf20Sopenharmony_ci if (ret) 7238c2ecf20Sopenharmony_ci return ERR_PTR(ret); 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci sgt = drm_gem_shmem_get_sg_table(&shmem->base); 7268c2ecf20Sopenharmony_ci if (IS_ERR(sgt)) { 7278c2ecf20Sopenharmony_ci ret = PTR_ERR(sgt); 7288c2ecf20Sopenharmony_ci goto err_put_pages; 7298c2ecf20Sopenharmony_ci } 7308c2ecf20Sopenharmony_ci /* Map the pages for use by the h/w. */ 7318c2ecf20Sopenharmony_ci ret = dma_map_sgtable(obj->dev->dev, sgt, DMA_BIDIRECTIONAL, 0); 7328c2ecf20Sopenharmony_ci if (ret) 7338c2ecf20Sopenharmony_ci goto err_free_sgt; 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci shmem->sgt = sgt; 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci return sgt; 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_cierr_free_sgt: 7408c2ecf20Sopenharmony_ci sg_free_table(sgt); 7418c2ecf20Sopenharmony_ci kfree(sgt); 7428c2ecf20Sopenharmony_cierr_put_pages: 7438c2ecf20Sopenharmony_ci drm_gem_shmem_put_pages(shmem); 7448c2ecf20Sopenharmony_ci return ERR_PTR(ret); 7458c2ecf20Sopenharmony_ci} 7468c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(drm_gem_shmem_get_pages_sgt); 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci/** 7498c2ecf20Sopenharmony_ci * drm_gem_shmem_prime_import_sg_table - Produce a shmem GEM object from 7508c2ecf20Sopenharmony_ci * another driver's scatter/gather table of pinned pages 7518c2ecf20Sopenharmony_ci * @dev: Device to import into 7528c2ecf20Sopenharmony_ci * @attach: DMA-BUF attachment 7538c2ecf20Sopenharmony_ci * @sgt: Scatter/gather table of pinned pages 7548c2ecf20Sopenharmony_ci * 7558c2ecf20Sopenharmony_ci * This function imports a scatter/gather table exported via DMA-BUF by 7568c2ecf20Sopenharmony_ci * another driver. Drivers that use the shmem helpers should set this as their 7578c2ecf20Sopenharmony_ci * &drm_driver.gem_prime_import_sg_table callback. 7588c2ecf20Sopenharmony_ci * 7598c2ecf20Sopenharmony_ci * Returns: 7608c2ecf20Sopenharmony_ci * A pointer to a newly created GEM object or an ERR_PTR-encoded negative 7618c2ecf20Sopenharmony_ci * error code on failure. 7628c2ecf20Sopenharmony_ci */ 7638c2ecf20Sopenharmony_cistruct drm_gem_object * 7648c2ecf20Sopenharmony_cidrm_gem_shmem_prime_import_sg_table(struct drm_device *dev, 7658c2ecf20Sopenharmony_ci struct dma_buf_attachment *attach, 7668c2ecf20Sopenharmony_ci struct sg_table *sgt) 7678c2ecf20Sopenharmony_ci{ 7688c2ecf20Sopenharmony_ci size_t size = PAGE_ALIGN(attach->dmabuf->size); 7698c2ecf20Sopenharmony_ci struct drm_gem_shmem_object *shmem; 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci shmem = __drm_gem_shmem_create(dev, size, true); 7728c2ecf20Sopenharmony_ci if (IS_ERR(shmem)) 7738c2ecf20Sopenharmony_ci return ERR_CAST(shmem); 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci shmem->sgt = sgt; 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci DRM_DEBUG_PRIME("size = %zu\n", size); 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci return &shmem->base; 7808c2ecf20Sopenharmony_ci} 7818c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(drm_gem_shmem_prime_import_sg_table); 782