162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright © 2008 Intel Corporation 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 562306a36Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 662306a36Sopenharmony_ci * to deal in the Software without restriction, including without limitation 762306a36Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 862306a36Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 962306a36Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * The above copyright notice and this permission notice (including the next 1262306a36Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the 1362306a36Sopenharmony_ci * Software. 1462306a36Sopenharmony_ci * 1562306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1662306a36Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1762306a36Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 1862306a36Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 1962306a36Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 2062306a36Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 2162306a36Sopenharmony_ci * IN THE SOFTWARE. 2262306a36Sopenharmony_ci * 2362306a36Sopenharmony_ci * Authors: 2462306a36Sopenharmony_ci * Eric Anholt <eric@anholt.net> 2562306a36Sopenharmony_ci * 2662306a36Sopenharmony_ci */ 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci#include <linux/dma-buf.h> 2962306a36Sopenharmony_ci#include <linux/file.h> 3062306a36Sopenharmony_ci#include <linux/fs.h> 3162306a36Sopenharmony_ci#include <linux/iosys-map.h> 3262306a36Sopenharmony_ci#include <linux/mem_encrypt.h> 3362306a36Sopenharmony_ci#include <linux/mm.h> 3462306a36Sopenharmony_ci#include <linux/mman.h> 3562306a36Sopenharmony_ci#include <linux/module.h> 3662306a36Sopenharmony_ci#include <linux/pagemap.h> 3762306a36Sopenharmony_ci#include <linux/pagevec.h> 3862306a36Sopenharmony_ci#include <linux/shmem_fs.h> 3962306a36Sopenharmony_ci#include <linux/slab.h> 4062306a36Sopenharmony_ci#include <linux/string_helpers.h> 4162306a36Sopenharmony_ci#include <linux/types.h> 4262306a36Sopenharmony_ci#include <linux/uaccess.h> 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci#include <drm/drm.h> 4562306a36Sopenharmony_ci#include <drm/drm_device.h> 4662306a36Sopenharmony_ci#include <drm/drm_drv.h> 4762306a36Sopenharmony_ci#include <drm/drm_file.h> 4862306a36Sopenharmony_ci#include <drm/drm_gem.h> 4962306a36Sopenharmony_ci#include <drm/drm_managed.h> 5062306a36Sopenharmony_ci#include <drm/drm_print.h> 5162306a36Sopenharmony_ci#include <drm/drm_vma_manager.h> 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci#include "drm_internal.h" 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci/** @file drm_gem.c 5662306a36Sopenharmony_ci * 5762306a36Sopenharmony_ci * This file provides some of the base ioctls and library routines for 5862306a36Sopenharmony_ci * the graphics memory manager implemented by each device driver. 5962306a36Sopenharmony_ci * 6062306a36Sopenharmony_ci * Because various devices have different requirements in terms of 6162306a36Sopenharmony_ci * synchronization and migration strategies, implementing that is left up to 6262306a36Sopenharmony_ci * the driver, and all that the general API provides should be generic -- 6362306a36Sopenharmony_ci * allocating objects, reading/writing data with the cpu, freeing objects. 6462306a36Sopenharmony_ci * Even there, platform-dependent optimizations for reading/writing data with 6562306a36Sopenharmony_ci * the CPU mean we'll likely hook those out to driver-specific calls. However, 6662306a36Sopenharmony_ci * the DRI2 implementation wants to have at least allocate/mmap be generic. 6762306a36Sopenharmony_ci * 6862306a36Sopenharmony_ci * The goal was to have swap-backed object allocation managed through 6962306a36Sopenharmony_ci * struct file. However, file descriptors as handles to a struct file have 7062306a36Sopenharmony_ci * two major failings: 7162306a36Sopenharmony_ci * - Process limits prevent more than 1024 or so being used at a time by 7262306a36Sopenharmony_ci * default. 7362306a36Sopenharmony_ci * - Inability to allocate high fds will aggravate the X Server's select() 7462306a36Sopenharmony_ci * handling, and likely that of many GL client applications as well. 7562306a36Sopenharmony_ci * 7662306a36Sopenharmony_ci * This led to a plan of using our own integer IDs (called handles, following 7762306a36Sopenharmony_ci * DRM terminology) to mimic fds, and implement the fd syscalls we need as 7862306a36Sopenharmony_ci * ioctls. The objects themselves will still include the struct file so 7962306a36Sopenharmony_ci * that we can transition to fds if the required kernel infrastructure shows 8062306a36Sopenharmony_ci * up at a later date, and as our interface with shmfs for memory allocation. 8162306a36Sopenharmony_ci */ 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_cistatic void 8462306a36Sopenharmony_cidrm_gem_init_release(struct drm_device *dev, void *ptr) 8562306a36Sopenharmony_ci{ 8662306a36Sopenharmony_ci drm_vma_offset_manager_destroy(dev->vma_offset_manager); 8762306a36Sopenharmony_ci} 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci/** 9062306a36Sopenharmony_ci * drm_gem_init - Initialize the GEM device fields 9162306a36Sopenharmony_ci * @dev: drm_devic structure to initialize 9262306a36Sopenharmony_ci */ 9362306a36Sopenharmony_ciint 9462306a36Sopenharmony_cidrm_gem_init(struct drm_device *dev) 9562306a36Sopenharmony_ci{ 9662306a36Sopenharmony_ci struct drm_vma_offset_manager *vma_offset_manager; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci mutex_init(&dev->object_name_lock); 9962306a36Sopenharmony_ci idr_init_base(&dev->object_name_idr, 1); 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci vma_offset_manager = drmm_kzalloc(dev, sizeof(*vma_offset_manager), 10262306a36Sopenharmony_ci GFP_KERNEL); 10362306a36Sopenharmony_ci if (!vma_offset_manager) { 10462306a36Sopenharmony_ci DRM_ERROR("out of memory\n"); 10562306a36Sopenharmony_ci return -ENOMEM; 10662306a36Sopenharmony_ci } 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci dev->vma_offset_manager = vma_offset_manager; 10962306a36Sopenharmony_ci drm_vma_offset_manager_init(vma_offset_manager, 11062306a36Sopenharmony_ci DRM_FILE_PAGE_OFFSET_START, 11162306a36Sopenharmony_ci DRM_FILE_PAGE_OFFSET_SIZE); 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci return drmm_add_action(dev, drm_gem_init_release, NULL); 11462306a36Sopenharmony_ci} 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci/** 11762306a36Sopenharmony_ci * drm_gem_object_init - initialize an allocated shmem-backed GEM object 11862306a36Sopenharmony_ci * @dev: drm_device the object should be initialized for 11962306a36Sopenharmony_ci * @obj: drm_gem_object to initialize 12062306a36Sopenharmony_ci * @size: object size 12162306a36Sopenharmony_ci * 12262306a36Sopenharmony_ci * Initialize an already allocated GEM object of the specified size with 12362306a36Sopenharmony_ci * shmfs backing store. 12462306a36Sopenharmony_ci */ 12562306a36Sopenharmony_ciint drm_gem_object_init(struct drm_device *dev, 12662306a36Sopenharmony_ci struct drm_gem_object *obj, size_t size) 12762306a36Sopenharmony_ci{ 12862306a36Sopenharmony_ci struct file *filp; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci drm_gem_private_object_init(dev, obj, size); 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci filp = shmem_file_setup("drm mm object", size, VM_NORESERVE); 13362306a36Sopenharmony_ci if (IS_ERR(filp)) 13462306a36Sopenharmony_ci return PTR_ERR(filp); 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci obj->filp = filp; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci return 0; 13962306a36Sopenharmony_ci} 14062306a36Sopenharmony_ciEXPORT_SYMBOL(drm_gem_object_init); 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci/** 14362306a36Sopenharmony_ci * drm_gem_private_object_init - initialize an allocated private GEM object 14462306a36Sopenharmony_ci * @dev: drm_device the object should be initialized for 14562306a36Sopenharmony_ci * @obj: drm_gem_object to initialize 14662306a36Sopenharmony_ci * @size: object size 14762306a36Sopenharmony_ci * 14862306a36Sopenharmony_ci * Initialize an already allocated GEM object of the specified size with 14962306a36Sopenharmony_ci * no GEM provided backing store. Instead the caller is responsible for 15062306a36Sopenharmony_ci * backing the object and handling it. 15162306a36Sopenharmony_ci */ 15262306a36Sopenharmony_civoid drm_gem_private_object_init(struct drm_device *dev, 15362306a36Sopenharmony_ci struct drm_gem_object *obj, size_t size) 15462306a36Sopenharmony_ci{ 15562306a36Sopenharmony_ci BUG_ON((size & (PAGE_SIZE - 1)) != 0); 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci obj->dev = dev; 15862306a36Sopenharmony_ci obj->filp = NULL; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci kref_init(&obj->refcount); 16162306a36Sopenharmony_ci obj->handle_count = 0; 16262306a36Sopenharmony_ci obj->size = size; 16362306a36Sopenharmony_ci dma_resv_init(&obj->_resv); 16462306a36Sopenharmony_ci if (!obj->resv) 16562306a36Sopenharmony_ci obj->resv = &obj->_resv; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci if (drm_core_check_feature(dev, DRIVER_GEM_GPUVA)) 16862306a36Sopenharmony_ci drm_gem_gpuva_init(obj); 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci drm_vma_node_reset(&obj->vma_node); 17162306a36Sopenharmony_ci INIT_LIST_HEAD(&obj->lru_node); 17262306a36Sopenharmony_ci} 17362306a36Sopenharmony_ciEXPORT_SYMBOL(drm_gem_private_object_init); 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci/** 17662306a36Sopenharmony_ci * drm_gem_private_object_fini - Finalize a failed drm_gem_object 17762306a36Sopenharmony_ci * @obj: drm_gem_object 17862306a36Sopenharmony_ci * 17962306a36Sopenharmony_ci * Uninitialize an already allocated GEM object when it initialized failed 18062306a36Sopenharmony_ci */ 18162306a36Sopenharmony_civoid drm_gem_private_object_fini(struct drm_gem_object *obj) 18262306a36Sopenharmony_ci{ 18362306a36Sopenharmony_ci WARN_ON(obj->dma_buf); 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci dma_resv_fini(&obj->_resv); 18662306a36Sopenharmony_ci} 18762306a36Sopenharmony_ciEXPORT_SYMBOL(drm_gem_private_object_fini); 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci/** 19062306a36Sopenharmony_ci * drm_gem_object_handle_free - release resources bound to userspace handles 19162306a36Sopenharmony_ci * @obj: GEM object to clean up. 19262306a36Sopenharmony_ci * 19362306a36Sopenharmony_ci * Called after the last handle to the object has been closed 19462306a36Sopenharmony_ci * 19562306a36Sopenharmony_ci * Removes any name for the object. Note that this must be 19662306a36Sopenharmony_ci * called before drm_gem_object_free or we'll be touching 19762306a36Sopenharmony_ci * freed memory 19862306a36Sopenharmony_ci */ 19962306a36Sopenharmony_cistatic void drm_gem_object_handle_free(struct drm_gem_object *obj) 20062306a36Sopenharmony_ci{ 20162306a36Sopenharmony_ci struct drm_device *dev = obj->dev; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci /* Remove any name for this object */ 20462306a36Sopenharmony_ci if (obj->name) { 20562306a36Sopenharmony_ci idr_remove(&dev->object_name_idr, obj->name); 20662306a36Sopenharmony_ci obj->name = 0; 20762306a36Sopenharmony_ci } 20862306a36Sopenharmony_ci} 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_cistatic void drm_gem_object_exported_dma_buf_free(struct drm_gem_object *obj) 21162306a36Sopenharmony_ci{ 21262306a36Sopenharmony_ci /* Unbreak the reference cycle if we have an exported dma_buf. */ 21362306a36Sopenharmony_ci if (obj->dma_buf) { 21462306a36Sopenharmony_ci dma_buf_put(obj->dma_buf); 21562306a36Sopenharmony_ci obj->dma_buf = NULL; 21662306a36Sopenharmony_ci } 21762306a36Sopenharmony_ci} 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_cistatic void 22062306a36Sopenharmony_cidrm_gem_object_handle_put_unlocked(struct drm_gem_object *obj) 22162306a36Sopenharmony_ci{ 22262306a36Sopenharmony_ci struct drm_device *dev = obj->dev; 22362306a36Sopenharmony_ci bool final = false; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci if (WARN_ON(READ_ONCE(obj->handle_count) == 0)) 22662306a36Sopenharmony_ci return; 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci /* 22962306a36Sopenharmony_ci * Must bump handle count first as this may be the last 23062306a36Sopenharmony_ci * ref, in which case the object would disappear before we 23162306a36Sopenharmony_ci * checked for a name 23262306a36Sopenharmony_ci */ 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci mutex_lock(&dev->object_name_lock); 23562306a36Sopenharmony_ci if (--obj->handle_count == 0) { 23662306a36Sopenharmony_ci drm_gem_object_handle_free(obj); 23762306a36Sopenharmony_ci drm_gem_object_exported_dma_buf_free(obj); 23862306a36Sopenharmony_ci final = true; 23962306a36Sopenharmony_ci } 24062306a36Sopenharmony_ci mutex_unlock(&dev->object_name_lock); 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci if (final) 24362306a36Sopenharmony_ci drm_gem_object_put(obj); 24462306a36Sopenharmony_ci} 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci/* 24762306a36Sopenharmony_ci * Called at device or object close to release the file's 24862306a36Sopenharmony_ci * handle references on objects. 24962306a36Sopenharmony_ci */ 25062306a36Sopenharmony_cistatic int 25162306a36Sopenharmony_cidrm_gem_object_release_handle(int id, void *ptr, void *data) 25262306a36Sopenharmony_ci{ 25362306a36Sopenharmony_ci struct drm_file *file_priv = data; 25462306a36Sopenharmony_ci struct drm_gem_object *obj = ptr; 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci if (obj->funcs->close) 25762306a36Sopenharmony_ci obj->funcs->close(obj, file_priv); 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci drm_prime_remove_buf_handle(&file_priv->prime, id); 26062306a36Sopenharmony_ci drm_vma_node_revoke(&obj->vma_node, file_priv); 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci drm_gem_object_handle_put_unlocked(obj); 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci return 0; 26562306a36Sopenharmony_ci} 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci/** 26862306a36Sopenharmony_ci * drm_gem_handle_delete - deletes the given file-private handle 26962306a36Sopenharmony_ci * @filp: drm file-private structure to use for the handle look up 27062306a36Sopenharmony_ci * @handle: userspace handle to delete 27162306a36Sopenharmony_ci * 27262306a36Sopenharmony_ci * Removes the GEM handle from the @filp lookup table which has been added with 27362306a36Sopenharmony_ci * drm_gem_handle_create(). If this is the last handle also cleans up linked 27462306a36Sopenharmony_ci * resources like GEM names. 27562306a36Sopenharmony_ci */ 27662306a36Sopenharmony_ciint 27762306a36Sopenharmony_cidrm_gem_handle_delete(struct drm_file *filp, u32 handle) 27862306a36Sopenharmony_ci{ 27962306a36Sopenharmony_ci struct drm_gem_object *obj; 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci spin_lock(&filp->table_lock); 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci /* Check if we currently have a reference on the object */ 28462306a36Sopenharmony_ci obj = idr_replace(&filp->object_idr, NULL, handle); 28562306a36Sopenharmony_ci spin_unlock(&filp->table_lock); 28662306a36Sopenharmony_ci if (IS_ERR_OR_NULL(obj)) 28762306a36Sopenharmony_ci return -EINVAL; 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci /* Release driver's reference and decrement refcount. */ 29062306a36Sopenharmony_ci drm_gem_object_release_handle(handle, obj, filp); 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci /* And finally make the handle available for future allocations. */ 29362306a36Sopenharmony_ci spin_lock(&filp->table_lock); 29462306a36Sopenharmony_ci idr_remove(&filp->object_idr, handle); 29562306a36Sopenharmony_ci spin_unlock(&filp->table_lock); 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci return 0; 29862306a36Sopenharmony_ci} 29962306a36Sopenharmony_ciEXPORT_SYMBOL(drm_gem_handle_delete); 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci/** 30262306a36Sopenharmony_ci * drm_gem_dumb_map_offset - return the fake mmap offset for a gem object 30362306a36Sopenharmony_ci * @file: drm file-private structure containing the gem object 30462306a36Sopenharmony_ci * @dev: corresponding drm_device 30562306a36Sopenharmony_ci * @handle: gem object handle 30662306a36Sopenharmony_ci * @offset: return location for the fake mmap offset 30762306a36Sopenharmony_ci * 30862306a36Sopenharmony_ci * This implements the &drm_driver.dumb_map_offset kms driver callback for 30962306a36Sopenharmony_ci * drivers which use gem to manage their backing storage. 31062306a36Sopenharmony_ci * 31162306a36Sopenharmony_ci * Returns: 31262306a36Sopenharmony_ci * 0 on success or a negative error code on failure. 31362306a36Sopenharmony_ci */ 31462306a36Sopenharmony_ciint drm_gem_dumb_map_offset(struct drm_file *file, struct drm_device *dev, 31562306a36Sopenharmony_ci u32 handle, u64 *offset) 31662306a36Sopenharmony_ci{ 31762306a36Sopenharmony_ci struct drm_gem_object *obj; 31862306a36Sopenharmony_ci int ret; 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci obj = drm_gem_object_lookup(file, handle); 32162306a36Sopenharmony_ci if (!obj) 32262306a36Sopenharmony_ci return -ENOENT; 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci /* Don't allow imported objects to be mapped */ 32562306a36Sopenharmony_ci if (obj->import_attach) { 32662306a36Sopenharmony_ci ret = -EINVAL; 32762306a36Sopenharmony_ci goto out; 32862306a36Sopenharmony_ci } 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci ret = drm_gem_create_mmap_offset(obj); 33162306a36Sopenharmony_ci if (ret) 33262306a36Sopenharmony_ci goto out; 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci *offset = drm_vma_node_offset_addr(&obj->vma_node); 33562306a36Sopenharmony_ciout: 33662306a36Sopenharmony_ci drm_gem_object_put(obj); 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci return ret; 33962306a36Sopenharmony_ci} 34062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(drm_gem_dumb_map_offset); 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci/** 34362306a36Sopenharmony_ci * drm_gem_handle_create_tail - internal functions to create a handle 34462306a36Sopenharmony_ci * @file_priv: drm file-private structure to register the handle for 34562306a36Sopenharmony_ci * @obj: object to register 34662306a36Sopenharmony_ci * @handlep: pointer to return the created handle to the caller 34762306a36Sopenharmony_ci * 34862306a36Sopenharmony_ci * This expects the &drm_device.object_name_lock to be held already and will 34962306a36Sopenharmony_ci * drop it before returning. Used to avoid races in establishing new handles 35062306a36Sopenharmony_ci * when importing an object from either an flink name or a dma-buf. 35162306a36Sopenharmony_ci * 35262306a36Sopenharmony_ci * Handles must be release again through drm_gem_handle_delete(). This is done 35362306a36Sopenharmony_ci * when userspace closes @file_priv for all attached handles, or through the 35462306a36Sopenharmony_ci * GEM_CLOSE ioctl for individual handles. 35562306a36Sopenharmony_ci */ 35662306a36Sopenharmony_ciint 35762306a36Sopenharmony_cidrm_gem_handle_create_tail(struct drm_file *file_priv, 35862306a36Sopenharmony_ci struct drm_gem_object *obj, 35962306a36Sopenharmony_ci u32 *handlep) 36062306a36Sopenharmony_ci{ 36162306a36Sopenharmony_ci struct drm_device *dev = obj->dev; 36262306a36Sopenharmony_ci u32 handle; 36362306a36Sopenharmony_ci int ret; 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci WARN_ON(!mutex_is_locked(&dev->object_name_lock)); 36662306a36Sopenharmony_ci if (obj->handle_count++ == 0) 36762306a36Sopenharmony_ci drm_gem_object_get(obj); 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci /* 37062306a36Sopenharmony_ci * Get the user-visible handle using idr. Preload and perform 37162306a36Sopenharmony_ci * allocation under our spinlock. 37262306a36Sopenharmony_ci */ 37362306a36Sopenharmony_ci idr_preload(GFP_KERNEL); 37462306a36Sopenharmony_ci spin_lock(&file_priv->table_lock); 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci ret = idr_alloc(&file_priv->object_idr, obj, 1, 0, GFP_NOWAIT); 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci spin_unlock(&file_priv->table_lock); 37962306a36Sopenharmony_ci idr_preload_end(); 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci mutex_unlock(&dev->object_name_lock); 38262306a36Sopenharmony_ci if (ret < 0) 38362306a36Sopenharmony_ci goto err_unref; 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci handle = ret; 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci ret = drm_vma_node_allow(&obj->vma_node, file_priv); 38862306a36Sopenharmony_ci if (ret) 38962306a36Sopenharmony_ci goto err_remove; 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci if (obj->funcs->open) { 39262306a36Sopenharmony_ci ret = obj->funcs->open(obj, file_priv); 39362306a36Sopenharmony_ci if (ret) 39462306a36Sopenharmony_ci goto err_revoke; 39562306a36Sopenharmony_ci } 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci *handlep = handle; 39862306a36Sopenharmony_ci return 0; 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_cierr_revoke: 40162306a36Sopenharmony_ci drm_vma_node_revoke(&obj->vma_node, file_priv); 40262306a36Sopenharmony_cierr_remove: 40362306a36Sopenharmony_ci spin_lock(&file_priv->table_lock); 40462306a36Sopenharmony_ci idr_remove(&file_priv->object_idr, handle); 40562306a36Sopenharmony_ci spin_unlock(&file_priv->table_lock); 40662306a36Sopenharmony_cierr_unref: 40762306a36Sopenharmony_ci drm_gem_object_handle_put_unlocked(obj); 40862306a36Sopenharmony_ci return ret; 40962306a36Sopenharmony_ci} 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci/** 41262306a36Sopenharmony_ci * drm_gem_handle_create - create a gem handle for an object 41362306a36Sopenharmony_ci * @file_priv: drm file-private structure to register the handle for 41462306a36Sopenharmony_ci * @obj: object to register 41562306a36Sopenharmony_ci * @handlep: pointer to return the created handle to the caller 41662306a36Sopenharmony_ci * 41762306a36Sopenharmony_ci * Create a handle for this object. This adds a handle reference to the object, 41862306a36Sopenharmony_ci * which includes a regular reference count. Callers will likely want to 41962306a36Sopenharmony_ci * dereference the object afterwards. 42062306a36Sopenharmony_ci * 42162306a36Sopenharmony_ci * Since this publishes @obj to userspace it must be fully set up by this point, 42262306a36Sopenharmony_ci * drivers must call this last in their buffer object creation callbacks. 42362306a36Sopenharmony_ci */ 42462306a36Sopenharmony_ciint drm_gem_handle_create(struct drm_file *file_priv, 42562306a36Sopenharmony_ci struct drm_gem_object *obj, 42662306a36Sopenharmony_ci u32 *handlep) 42762306a36Sopenharmony_ci{ 42862306a36Sopenharmony_ci mutex_lock(&obj->dev->object_name_lock); 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci return drm_gem_handle_create_tail(file_priv, obj, handlep); 43162306a36Sopenharmony_ci} 43262306a36Sopenharmony_ciEXPORT_SYMBOL(drm_gem_handle_create); 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci/** 43662306a36Sopenharmony_ci * drm_gem_free_mmap_offset - release a fake mmap offset for an object 43762306a36Sopenharmony_ci * @obj: obj in question 43862306a36Sopenharmony_ci * 43962306a36Sopenharmony_ci * This routine frees fake offsets allocated by drm_gem_create_mmap_offset(). 44062306a36Sopenharmony_ci * 44162306a36Sopenharmony_ci * Note that drm_gem_object_release() already calls this function, so drivers 44262306a36Sopenharmony_ci * don't have to take care of releasing the mmap offset themselves when freeing 44362306a36Sopenharmony_ci * the GEM object. 44462306a36Sopenharmony_ci */ 44562306a36Sopenharmony_civoid 44662306a36Sopenharmony_cidrm_gem_free_mmap_offset(struct drm_gem_object *obj) 44762306a36Sopenharmony_ci{ 44862306a36Sopenharmony_ci struct drm_device *dev = obj->dev; 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci drm_vma_offset_remove(dev->vma_offset_manager, &obj->vma_node); 45162306a36Sopenharmony_ci} 45262306a36Sopenharmony_ciEXPORT_SYMBOL(drm_gem_free_mmap_offset); 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci/** 45562306a36Sopenharmony_ci * drm_gem_create_mmap_offset_size - create a fake mmap offset for an object 45662306a36Sopenharmony_ci * @obj: obj in question 45762306a36Sopenharmony_ci * @size: the virtual size 45862306a36Sopenharmony_ci * 45962306a36Sopenharmony_ci * GEM memory mapping works by handing back to userspace a fake mmap offset 46062306a36Sopenharmony_ci * it can use in a subsequent mmap(2) call. The DRM core code then looks 46162306a36Sopenharmony_ci * up the object based on the offset and sets up the various memory mapping 46262306a36Sopenharmony_ci * structures. 46362306a36Sopenharmony_ci * 46462306a36Sopenharmony_ci * This routine allocates and attaches a fake offset for @obj, in cases where 46562306a36Sopenharmony_ci * the virtual size differs from the physical size (ie. &drm_gem_object.size). 46662306a36Sopenharmony_ci * Otherwise just use drm_gem_create_mmap_offset(). 46762306a36Sopenharmony_ci * 46862306a36Sopenharmony_ci * This function is idempotent and handles an already allocated mmap offset 46962306a36Sopenharmony_ci * transparently. Drivers do not need to check for this case. 47062306a36Sopenharmony_ci */ 47162306a36Sopenharmony_ciint 47262306a36Sopenharmony_cidrm_gem_create_mmap_offset_size(struct drm_gem_object *obj, size_t size) 47362306a36Sopenharmony_ci{ 47462306a36Sopenharmony_ci struct drm_device *dev = obj->dev; 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci return drm_vma_offset_add(dev->vma_offset_manager, &obj->vma_node, 47762306a36Sopenharmony_ci size / PAGE_SIZE); 47862306a36Sopenharmony_ci} 47962306a36Sopenharmony_ciEXPORT_SYMBOL(drm_gem_create_mmap_offset_size); 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci/** 48262306a36Sopenharmony_ci * drm_gem_create_mmap_offset - create a fake mmap offset for an object 48362306a36Sopenharmony_ci * @obj: obj in question 48462306a36Sopenharmony_ci * 48562306a36Sopenharmony_ci * GEM memory mapping works by handing back to userspace a fake mmap offset 48662306a36Sopenharmony_ci * it can use in a subsequent mmap(2) call. The DRM core code then looks 48762306a36Sopenharmony_ci * up the object based on the offset and sets up the various memory mapping 48862306a36Sopenharmony_ci * structures. 48962306a36Sopenharmony_ci * 49062306a36Sopenharmony_ci * This routine allocates and attaches a fake offset for @obj. 49162306a36Sopenharmony_ci * 49262306a36Sopenharmony_ci * Drivers can call drm_gem_free_mmap_offset() before freeing @obj to release 49362306a36Sopenharmony_ci * the fake offset again. 49462306a36Sopenharmony_ci */ 49562306a36Sopenharmony_ciint drm_gem_create_mmap_offset(struct drm_gem_object *obj) 49662306a36Sopenharmony_ci{ 49762306a36Sopenharmony_ci return drm_gem_create_mmap_offset_size(obj, obj->size); 49862306a36Sopenharmony_ci} 49962306a36Sopenharmony_ciEXPORT_SYMBOL(drm_gem_create_mmap_offset); 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci/* 50262306a36Sopenharmony_ci * Move folios to appropriate lru and release the folios, decrementing the 50362306a36Sopenharmony_ci * ref count of those folios. 50462306a36Sopenharmony_ci */ 50562306a36Sopenharmony_cistatic void drm_gem_check_release_batch(struct folio_batch *fbatch) 50662306a36Sopenharmony_ci{ 50762306a36Sopenharmony_ci check_move_unevictable_folios(fbatch); 50862306a36Sopenharmony_ci __folio_batch_release(fbatch); 50962306a36Sopenharmony_ci cond_resched(); 51062306a36Sopenharmony_ci} 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci/** 51362306a36Sopenharmony_ci * drm_gem_get_pages - helper to allocate backing pages for a GEM object 51462306a36Sopenharmony_ci * from shmem 51562306a36Sopenharmony_ci * @obj: obj in question 51662306a36Sopenharmony_ci * 51762306a36Sopenharmony_ci * This reads the page-array of the shmem-backing storage of the given gem 51862306a36Sopenharmony_ci * object. An array of pages is returned. If a page is not allocated or 51962306a36Sopenharmony_ci * swapped-out, this will allocate/swap-in the required pages. Note that the 52062306a36Sopenharmony_ci * whole object is covered by the page-array and pinned in memory. 52162306a36Sopenharmony_ci * 52262306a36Sopenharmony_ci * Use drm_gem_put_pages() to release the array and unpin all pages. 52362306a36Sopenharmony_ci * 52462306a36Sopenharmony_ci * This uses the GFP-mask set on the shmem-mapping (see mapping_set_gfp_mask()). 52562306a36Sopenharmony_ci * If you require other GFP-masks, you have to do those allocations yourself. 52662306a36Sopenharmony_ci * 52762306a36Sopenharmony_ci * Note that you are not allowed to change gfp-zones during runtime. That is, 52862306a36Sopenharmony_ci * shmem_read_mapping_page_gfp() must be called with the same gfp_zone(gfp) as 52962306a36Sopenharmony_ci * set during initialization. If you have special zone constraints, set them 53062306a36Sopenharmony_ci * after drm_gem_object_init() via mapping_set_gfp_mask(). shmem-core takes care 53162306a36Sopenharmony_ci * to keep pages in the required zone during swap-in. 53262306a36Sopenharmony_ci * 53362306a36Sopenharmony_ci * This function is only valid on objects initialized with 53462306a36Sopenharmony_ci * drm_gem_object_init(), but not for those initialized with 53562306a36Sopenharmony_ci * drm_gem_private_object_init() only. 53662306a36Sopenharmony_ci */ 53762306a36Sopenharmony_cistruct page **drm_gem_get_pages(struct drm_gem_object *obj) 53862306a36Sopenharmony_ci{ 53962306a36Sopenharmony_ci struct address_space *mapping; 54062306a36Sopenharmony_ci struct page **pages; 54162306a36Sopenharmony_ci struct folio *folio; 54262306a36Sopenharmony_ci struct folio_batch fbatch; 54362306a36Sopenharmony_ci long i, j, npages; 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci if (WARN_ON(!obj->filp)) 54662306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci /* This is the shared memory object that backs the GEM resource */ 54962306a36Sopenharmony_ci mapping = obj->filp->f_mapping; 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci /* We already BUG_ON() for non-page-aligned sizes in 55262306a36Sopenharmony_ci * drm_gem_object_init(), so we should never hit this unless 55362306a36Sopenharmony_ci * driver author is doing something really wrong: 55462306a36Sopenharmony_ci */ 55562306a36Sopenharmony_ci WARN_ON((obj->size & (PAGE_SIZE - 1)) != 0); 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci npages = obj->size >> PAGE_SHIFT; 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci pages = kvmalloc_array(npages, sizeof(struct page *), GFP_KERNEL); 56062306a36Sopenharmony_ci if (pages == NULL) 56162306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci mapping_set_unevictable(mapping); 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci i = 0; 56662306a36Sopenharmony_ci while (i < npages) { 56762306a36Sopenharmony_ci long nr; 56862306a36Sopenharmony_ci folio = shmem_read_folio_gfp(mapping, i, 56962306a36Sopenharmony_ci mapping_gfp_mask(mapping)); 57062306a36Sopenharmony_ci if (IS_ERR(folio)) 57162306a36Sopenharmony_ci goto fail; 57262306a36Sopenharmony_ci nr = min(npages - i, folio_nr_pages(folio)); 57362306a36Sopenharmony_ci for (j = 0; j < nr; j++, i++) 57462306a36Sopenharmony_ci pages[i] = folio_file_page(folio, i); 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci /* Make sure shmem keeps __GFP_DMA32 allocated pages in the 57762306a36Sopenharmony_ci * correct region during swapin. Note that this requires 57862306a36Sopenharmony_ci * __GFP_DMA32 to be set in mapping_gfp_mask(inode->i_mapping) 57962306a36Sopenharmony_ci * so shmem can relocate pages during swapin if required. 58062306a36Sopenharmony_ci */ 58162306a36Sopenharmony_ci BUG_ON(mapping_gfp_constraint(mapping, __GFP_DMA32) && 58262306a36Sopenharmony_ci (folio_pfn(folio) >= 0x00100000UL)); 58362306a36Sopenharmony_ci } 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci return pages; 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_cifail: 58862306a36Sopenharmony_ci mapping_clear_unevictable(mapping); 58962306a36Sopenharmony_ci folio_batch_init(&fbatch); 59062306a36Sopenharmony_ci j = 0; 59162306a36Sopenharmony_ci while (j < i) { 59262306a36Sopenharmony_ci struct folio *f = page_folio(pages[j]); 59362306a36Sopenharmony_ci if (!folio_batch_add(&fbatch, f)) 59462306a36Sopenharmony_ci drm_gem_check_release_batch(&fbatch); 59562306a36Sopenharmony_ci j += folio_nr_pages(f); 59662306a36Sopenharmony_ci } 59762306a36Sopenharmony_ci if (fbatch.nr) 59862306a36Sopenharmony_ci drm_gem_check_release_batch(&fbatch); 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci kvfree(pages); 60162306a36Sopenharmony_ci return ERR_CAST(folio); 60262306a36Sopenharmony_ci} 60362306a36Sopenharmony_ciEXPORT_SYMBOL(drm_gem_get_pages); 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci/** 60662306a36Sopenharmony_ci * drm_gem_put_pages - helper to free backing pages for a GEM object 60762306a36Sopenharmony_ci * @obj: obj in question 60862306a36Sopenharmony_ci * @pages: pages to free 60962306a36Sopenharmony_ci * @dirty: if true, pages will be marked as dirty 61062306a36Sopenharmony_ci * @accessed: if true, the pages will be marked as accessed 61162306a36Sopenharmony_ci */ 61262306a36Sopenharmony_civoid drm_gem_put_pages(struct drm_gem_object *obj, struct page **pages, 61362306a36Sopenharmony_ci bool dirty, bool accessed) 61462306a36Sopenharmony_ci{ 61562306a36Sopenharmony_ci int i, npages; 61662306a36Sopenharmony_ci struct address_space *mapping; 61762306a36Sopenharmony_ci struct folio_batch fbatch; 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci mapping = file_inode(obj->filp)->i_mapping; 62062306a36Sopenharmony_ci mapping_clear_unevictable(mapping); 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci /* We already BUG_ON() for non-page-aligned sizes in 62362306a36Sopenharmony_ci * drm_gem_object_init(), so we should never hit this unless 62462306a36Sopenharmony_ci * driver author is doing something really wrong: 62562306a36Sopenharmony_ci */ 62662306a36Sopenharmony_ci WARN_ON((obj->size & (PAGE_SIZE - 1)) != 0); 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci npages = obj->size >> PAGE_SHIFT; 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci folio_batch_init(&fbatch); 63162306a36Sopenharmony_ci for (i = 0; i < npages; i++) { 63262306a36Sopenharmony_ci struct folio *folio; 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci if (!pages[i]) 63562306a36Sopenharmony_ci continue; 63662306a36Sopenharmony_ci folio = page_folio(pages[i]); 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci if (dirty) 63962306a36Sopenharmony_ci folio_mark_dirty(folio); 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci if (accessed) 64262306a36Sopenharmony_ci folio_mark_accessed(folio); 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci /* Undo the reference we took when populating the table */ 64562306a36Sopenharmony_ci if (!folio_batch_add(&fbatch, folio)) 64662306a36Sopenharmony_ci drm_gem_check_release_batch(&fbatch); 64762306a36Sopenharmony_ci i += folio_nr_pages(folio) - 1; 64862306a36Sopenharmony_ci } 64962306a36Sopenharmony_ci if (folio_batch_count(&fbatch)) 65062306a36Sopenharmony_ci drm_gem_check_release_batch(&fbatch); 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci kvfree(pages); 65362306a36Sopenharmony_ci} 65462306a36Sopenharmony_ciEXPORT_SYMBOL(drm_gem_put_pages); 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_cistatic int objects_lookup(struct drm_file *filp, u32 *handle, int count, 65762306a36Sopenharmony_ci struct drm_gem_object **objs) 65862306a36Sopenharmony_ci{ 65962306a36Sopenharmony_ci int i, ret = 0; 66062306a36Sopenharmony_ci struct drm_gem_object *obj; 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci spin_lock(&filp->table_lock); 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci for (i = 0; i < count; i++) { 66562306a36Sopenharmony_ci /* Check if we currently have a reference on the object */ 66662306a36Sopenharmony_ci obj = idr_find(&filp->object_idr, handle[i]); 66762306a36Sopenharmony_ci if (!obj) { 66862306a36Sopenharmony_ci ret = -ENOENT; 66962306a36Sopenharmony_ci break; 67062306a36Sopenharmony_ci } 67162306a36Sopenharmony_ci drm_gem_object_get(obj); 67262306a36Sopenharmony_ci objs[i] = obj; 67362306a36Sopenharmony_ci } 67462306a36Sopenharmony_ci spin_unlock(&filp->table_lock); 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci return ret; 67762306a36Sopenharmony_ci} 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci/** 68062306a36Sopenharmony_ci * drm_gem_objects_lookup - look up GEM objects from an array of handles 68162306a36Sopenharmony_ci * @filp: DRM file private date 68262306a36Sopenharmony_ci * @bo_handles: user pointer to array of userspace handle 68362306a36Sopenharmony_ci * @count: size of handle array 68462306a36Sopenharmony_ci * @objs_out: returned pointer to array of drm_gem_object pointers 68562306a36Sopenharmony_ci * 68662306a36Sopenharmony_ci * Takes an array of userspace handles and returns a newly allocated array of 68762306a36Sopenharmony_ci * GEM objects. 68862306a36Sopenharmony_ci * 68962306a36Sopenharmony_ci * For a single handle lookup, use drm_gem_object_lookup(). 69062306a36Sopenharmony_ci * 69162306a36Sopenharmony_ci * Returns: 69262306a36Sopenharmony_ci * 69362306a36Sopenharmony_ci * @objs filled in with GEM object pointers. Returned GEM objects need to be 69462306a36Sopenharmony_ci * released with drm_gem_object_put(). -ENOENT is returned on a lookup 69562306a36Sopenharmony_ci * failure. 0 is returned on success. 69662306a36Sopenharmony_ci * 69762306a36Sopenharmony_ci */ 69862306a36Sopenharmony_ciint drm_gem_objects_lookup(struct drm_file *filp, void __user *bo_handles, 69962306a36Sopenharmony_ci int count, struct drm_gem_object ***objs_out) 70062306a36Sopenharmony_ci{ 70162306a36Sopenharmony_ci int ret; 70262306a36Sopenharmony_ci u32 *handles; 70362306a36Sopenharmony_ci struct drm_gem_object **objs; 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci if (!count) 70662306a36Sopenharmony_ci return 0; 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci objs = kvmalloc_array(count, sizeof(struct drm_gem_object *), 70962306a36Sopenharmony_ci GFP_KERNEL | __GFP_ZERO); 71062306a36Sopenharmony_ci if (!objs) 71162306a36Sopenharmony_ci return -ENOMEM; 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci *objs_out = objs; 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci handles = kvmalloc_array(count, sizeof(u32), GFP_KERNEL); 71662306a36Sopenharmony_ci if (!handles) { 71762306a36Sopenharmony_ci ret = -ENOMEM; 71862306a36Sopenharmony_ci goto out; 71962306a36Sopenharmony_ci } 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci if (copy_from_user(handles, bo_handles, count * sizeof(u32))) { 72262306a36Sopenharmony_ci ret = -EFAULT; 72362306a36Sopenharmony_ci DRM_DEBUG("Failed to copy in GEM handles\n"); 72462306a36Sopenharmony_ci goto out; 72562306a36Sopenharmony_ci } 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci ret = objects_lookup(filp, handles, count, objs); 72862306a36Sopenharmony_ciout: 72962306a36Sopenharmony_ci kvfree(handles); 73062306a36Sopenharmony_ci return ret; 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci} 73362306a36Sopenharmony_ciEXPORT_SYMBOL(drm_gem_objects_lookup); 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci/** 73662306a36Sopenharmony_ci * drm_gem_object_lookup - look up a GEM object from its handle 73762306a36Sopenharmony_ci * @filp: DRM file private date 73862306a36Sopenharmony_ci * @handle: userspace handle 73962306a36Sopenharmony_ci * 74062306a36Sopenharmony_ci * Returns: 74162306a36Sopenharmony_ci * 74262306a36Sopenharmony_ci * A reference to the object named by the handle if such exists on @filp, NULL 74362306a36Sopenharmony_ci * otherwise. 74462306a36Sopenharmony_ci * 74562306a36Sopenharmony_ci * If looking up an array of handles, use drm_gem_objects_lookup(). 74662306a36Sopenharmony_ci */ 74762306a36Sopenharmony_cistruct drm_gem_object * 74862306a36Sopenharmony_cidrm_gem_object_lookup(struct drm_file *filp, u32 handle) 74962306a36Sopenharmony_ci{ 75062306a36Sopenharmony_ci struct drm_gem_object *obj = NULL; 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci objects_lookup(filp, &handle, 1, &obj); 75362306a36Sopenharmony_ci return obj; 75462306a36Sopenharmony_ci} 75562306a36Sopenharmony_ciEXPORT_SYMBOL(drm_gem_object_lookup); 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci/** 75862306a36Sopenharmony_ci * drm_gem_dma_resv_wait - Wait on GEM object's reservation's objects 75962306a36Sopenharmony_ci * shared and/or exclusive fences. 76062306a36Sopenharmony_ci * @filep: DRM file private date 76162306a36Sopenharmony_ci * @handle: userspace handle 76262306a36Sopenharmony_ci * @wait_all: if true, wait on all fences, else wait on just exclusive fence 76362306a36Sopenharmony_ci * @timeout: timeout value in jiffies or zero to return immediately 76462306a36Sopenharmony_ci * 76562306a36Sopenharmony_ci * Returns: 76662306a36Sopenharmony_ci * 76762306a36Sopenharmony_ci * Returns -ERESTARTSYS if interrupted, 0 if the wait timed out, or 76862306a36Sopenharmony_ci * greater than 0 on success. 76962306a36Sopenharmony_ci */ 77062306a36Sopenharmony_cilong drm_gem_dma_resv_wait(struct drm_file *filep, u32 handle, 77162306a36Sopenharmony_ci bool wait_all, unsigned long timeout) 77262306a36Sopenharmony_ci{ 77362306a36Sopenharmony_ci long ret; 77462306a36Sopenharmony_ci struct drm_gem_object *obj; 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci obj = drm_gem_object_lookup(filep, handle); 77762306a36Sopenharmony_ci if (!obj) { 77862306a36Sopenharmony_ci DRM_DEBUG("Failed to look up GEM BO %d\n", handle); 77962306a36Sopenharmony_ci return -EINVAL; 78062306a36Sopenharmony_ci } 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci ret = dma_resv_wait_timeout(obj->resv, dma_resv_usage_rw(wait_all), 78362306a36Sopenharmony_ci true, timeout); 78462306a36Sopenharmony_ci if (ret == 0) 78562306a36Sopenharmony_ci ret = -ETIME; 78662306a36Sopenharmony_ci else if (ret > 0) 78762306a36Sopenharmony_ci ret = 0; 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci drm_gem_object_put(obj); 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_ci return ret; 79262306a36Sopenharmony_ci} 79362306a36Sopenharmony_ciEXPORT_SYMBOL(drm_gem_dma_resv_wait); 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci/** 79662306a36Sopenharmony_ci * drm_gem_close_ioctl - implementation of the GEM_CLOSE ioctl 79762306a36Sopenharmony_ci * @dev: drm_device 79862306a36Sopenharmony_ci * @data: ioctl data 79962306a36Sopenharmony_ci * @file_priv: drm file-private structure 80062306a36Sopenharmony_ci * 80162306a36Sopenharmony_ci * Releases the handle to an mm object. 80262306a36Sopenharmony_ci */ 80362306a36Sopenharmony_ciint 80462306a36Sopenharmony_cidrm_gem_close_ioctl(struct drm_device *dev, void *data, 80562306a36Sopenharmony_ci struct drm_file *file_priv) 80662306a36Sopenharmony_ci{ 80762306a36Sopenharmony_ci struct drm_gem_close *args = data; 80862306a36Sopenharmony_ci int ret; 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_ci if (!drm_core_check_feature(dev, DRIVER_GEM)) 81162306a36Sopenharmony_ci return -EOPNOTSUPP; 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_ci ret = drm_gem_handle_delete(file_priv, args->handle); 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci return ret; 81662306a36Sopenharmony_ci} 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci/** 81962306a36Sopenharmony_ci * drm_gem_flink_ioctl - implementation of the GEM_FLINK ioctl 82062306a36Sopenharmony_ci * @dev: drm_device 82162306a36Sopenharmony_ci * @data: ioctl data 82262306a36Sopenharmony_ci * @file_priv: drm file-private structure 82362306a36Sopenharmony_ci * 82462306a36Sopenharmony_ci * Create a global name for an object, returning the name. 82562306a36Sopenharmony_ci * 82662306a36Sopenharmony_ci * Note that the name does not hold a reference; when the object 82762306a36Sopenharmony_ci * is freed, the name goes away. 82862306a36Sopenharmony_ci */ 82962306a36Sopenharmony_ciint 83062306a36Sopenharmony_cidrm_gem_flink_ioctl(struct drm_device *dev, void *data, 83162306a36Sopenharmony_ci struct drm_file *file_priv) 83262306a36Sopenharmony_ci{ 83362306a36Sopenharmony_ci struct drm_gem_flink *args = data; 83462306a36Sopenharmony_ci struct drm_gem_object *obj; 83562306a36Sopenharmony_ci int ret; 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_ci if (!drm_core_check_feature(dev, DRIVER_GEM)) 83862306a36Sopenharmony_ci return -EOPNOTSUPP; 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci obj = drm_gem_object_lookup(file_priv, args->handle); 84162306a36Sopenharmony_ci if (obj == NULL) 84262306a36Sopenharmony_ci return -ENOENT; 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ci mutex_lock(&dev->object_name_lock); 84562306a36Sopenharmony_ci /* prevent races with concurrent gem_close. */ 84662306a36Sopenharmony_ci if (obj->handle_count == 0) { 84762306a36Sopenharmony_ci ret = -ENOENT; 84862306a36Sopenharmony_ci goto err; 84962306a36Sopenharmony_ci } 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_ci if (!obj->name) { 85262306a36Sopenharmony_ci ret = idr_alloc(&dev->object_name_idr, obj, 1, 0, GFP_KERNEL); 85362306a36Sopenharmony_ci if (ret < 0) 85462306a36Sopenharmony_ci goto err; 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_ci obj->name = ret; 85762306a36Sopenharmony_ci } 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ci args->name = (uint64_t) obj->name; 86062306a36Sopenharmony_ci ret = 0; 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_cierr: 86362306a36Sopenharmony_ci mutex_unlock(&dev->object_name_lock); 86462306a36Sopenharmony_ci drm_gem_object_put(obj); 86562306a36Sopenharmony_ci return ret; 86662306a36Sopenharmony_ci} 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci/** 86962306a36Sopenharmony_ci * drm_gem_open_ioctl - implementation of the GEM_OPEN ioctl 87062306a36Sopenharmony_ci * @dev: drm_device 87162306a36Sopenharmony_ci * @data: ioctl data 87262306a36Sopenharmony_ci * @file_priv: drm file-private structure 87362306a36Sopenharmony_ci * 87462306a36Sopenharmony_ci * Open an object using the global name, returning a handle and the size. 87562306a36Sopenharmony_ci * 87662306a36Sopenharmony_ci * This handle (of course) holds a reference to the object, so the object 87762306a36Sopenharmony_ci * will not go away until the handle is deleted. 87862306a36Sopenharmony_ci */ 87962306a36Sopenharmony_ciint 88062306a36Sopenharmony_cidrm_gem_open_ioctl(struct drm_device *dev, void *data, 88162306a36Sopenharmony_ci struct drm_file *file_priv) 88262306a36Sopenharmony_ci{ 88362306a36Sopenharmony_ci struct drm_gem_open *args = data; 88462306a36Sopenharmony_ci struct drm_gem_object *obj; 88562306a36Sopenharmony_ci int ret; 88662306a36Sopenharmony_ci u32 handle; 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_ci if (!drm_core_check_feature(dev, DRIVER_GEM)) 88962306a36Sopenharmony_ci return -EOPNOTSUPP; 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_ci mutex_lock(&dev->object_name_lock); 89262306a36Sopenharmony_ci obj = idr_find(&dev->object_name_idr, (int) args->name); 89362306a36Sopenharmony_ci if (obj) { 89462306a36Sopenharmony_ci drm_gem_object_get(obj); 89562306a36Sopenharmony_ci } else { 89662306a36Sopenharmony_ci mutex_unlock(&dev->object_name_lock); 89762306a36Sopenharmony_ci return -ENOENT; 89862306a36Sopenharmony_ci } 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci /* drm_gem_handle_create_tail unlocks dev->object_name_lock. */ 90162306a36Sopenharmony_ci ret = drm_gem_handle_create_tail(file_priv, obj, &handle); 90262306a36Sopenharmony_ci if (ret) 90362306a36Sopenharmony_ci goto err; 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci args->handle = handle; 90662306a36Sopenharmony_ci args->size = obj->size; 90762306a36Sopenharmony_ci 90862306a36Sopenharmony_cierr: 90962306a36Sopenharmony_ci drm_gem_object_put(obj); 91062306a36Sopenharmony_ci return ret; 91162306a36Sopenharmony_ci} 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_ci/** 91462306a36Sopenharmony_ci * drm_gem_open - initializes GEM file-private structures at devnode open time 91562306a36Sopenharmony_ci * @dev: drm_device which is being opened by userspace 91662306a36Sopenharmony_ci * @file_private: drm file-private structure to set up 91762306a36Sopenharmony_ci * 91862306a36Sopenharmony_ci * Called at device open time, sets up the structure for handling refcounting 91962306a36Sopenharmony_ci * of mm objects. 92062306a36Sopenharmony_ci */ 92162306a36Sopenharmony_civoid 92262306a36Sopenharmony_cidrm_gem_open(struct drm_device *dev, struct drm_file *file_private) 92362306a36Sopenharmony_ci{ 92462306a36Sopenharmony_ci idr_init_base(&file_private->object_idr, 1); 92562306a36Sopenharmony_ci spin_lock_init(&file_private->table_lock); 92662306a36Sopenharmony_ci} 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_ci/** 92962306a36Sopenharmony_ci * drm_gem_release - release file-private GEM resources 93062306a36Sopenharmony_ci * @dev: drm_device which is being closed by userspace 93162306a36Sopenharmony_ci * @file_private: drm file-private structure to clean up 93262306a36Sopenharmony_ci * 93362306a36Sopenharmony_ci * Called at close time when the filp is going away. 93462306a36Sopenharmony_ci * 93562306a36Sopenharmony_ci * Releases any remaining references on objects by this filp. 93662306a36Sopenharmony_ci */ 93762306a36Sopenharmony_civoid 93862306a36Sopenharmony_cidrm_gem_release(struct drm_device *dev, struct drm_file *file_private) 93962306a36Sopenharmony_ci{ 94062306a36Sopenharmony_ci idr_for_each(&file_private->object_idr, 94162306a36Sopenharmony_ci &drm_gem_object_release_handle, file_private); 94262306a36Sopenharmony_ci idr_destroy(&file_private->object_idr); 94362306a36Sopenharmony_ci} 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci/** 94662306a36Sopenharmony_ci * drm_gem_object_release - release GEM buffer object resources 94762306a36Sopenharmony_ci * @obj: GEM buffer object 94862306a36Sopenharmony_ci * 94962306a36Sopenharmony_ci * This releases any structures and resources used by @obj and is the inverse of 95062306a36Sopenharmony_ci * drm_gem_object_init(). 95162306a36Sopenharmony_ci */ 95262306a36Sopenharmony_civoid 95362306a36Sopenharmony_cidrm_gem_object_release(struct drm_gem_object *obj) 95462306a36Sopenharmony_ci{ 95562306a36Sopenharmony_ci if (obj->filp) 95662306a36Sopenharmony_ci fput(obj->filp); 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_ci drm_gem_private_object_fini(obj); 95962306a36Sopenharmony_ci 96062306a36Sopenharmony_ci drm_gem_free_mmap_offset(obj); 96162306a36Sopenharmony_ci drm_gem_lru_remove(obj); 96262306a36Sopenharmony_ci} 96362306a36Sopenharmony_ciEXPORT_SYMBOL(drm_gem_object_release); 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_ci/** 96662306a36Sopenharmony_ci * drm_gem_object_free - free a GEM object 96762306a36Sopenharmony_ci * @kref: kref of the object to free 96862306a36Sopenharmony_ci * 96962306a36Sopenharmony_ci * Called after the last reference to the object has been lost. 97062306a36Sopenharmony_ci * 97162306a36Sopenharmony_ci * Frees the object 97262306a36Sopenharmony_ci */ 97362306a36Sopenharmony_civoid 97462306a36Sopenharmony_cidrm_gem_object_free(struct kref *kref) 97562306a36Sopenharmony_ci{ 97662306a36Sopenharmony_ci struct drm_gem_object *obj = 97762306a36Sopenharmony_ci container_of(kref, struct drm_gem_object, refcount); 97862306a36Sopenharmony_ci 97962306a36Sopenharmony_ci if (WARN_ON(!obj->funcs->free)) 98062306a36Sopenharmony_ci return; 98162306a36Sopenharmony_ci 98262306a36Sopenharmony_ci obj->funcs->free(obj); 98362306a36Sopenharmony_ci} 98462306a36Sopenharmony_ciEXPORT_SYMBOL(drm_gem_object_free); 98562306a36Sopenharmony_ci 98662306a36Sopenharmony_ci/** 98762306a36Sopenharmony_ci * drm_gem_vm_open - vma->ops->open implementation for GEM 98862306a36Sopenharmony_ci * @vma: VM area structure 98962306a36Sopenharmony_ci * 99062306a36Sopenharmony_ci * This function implements the #vm_operations_struct open() callback for GEM 99162306a36Sopenharmony_ci * drivers. This must be used together with drm_gem_vm_close(). 99262306a36Sopenharmony_ci */ 99362306a36Sopenharmony_civoid drm_gem_vm_open(struct vm_area_struct *vma) 99462306a36Sopenharmony_ci{ 99562306a36Sopenharmony_ci struct drm_gem_object *obj = vma->vm_private_data; 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_ci drm_gem_object_get(obj); 99862306a36Sopenharmony_ci} 99962306a36Sopenharmony_ciEXPORT_SYMBOL(drm_gem_vm_open); 100062306a36Sopenharmony_ci 100162306a36Sopenharmony_ci/** 100262306a36Sopenharmony_ci * drm_gem_vm_close - vma->ops->close implementation for GEM 100362306a36Sopenharmony_ci * @vma: VM area structure 100462306a36Sopenharmony_ci * 100562306a36Sopenharmony_ci * This function implements the #vm_operations_struct close() callback for GEM 100662306a36Sopenharmony_ci * drivers. This must be used together with drm_gem_vm_open(). 100762306a36Sopenharmony_ci */ 100862306a36Sopenharmony_civoid drm_gem_vm_close(struct vm_area_struct *vma) 100962306a36Sopenharmony_ci{ 101062306a36Sopenharmony_ci struct drm_gem_object *obj = vma->vm_private_data; 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_ci drm_gem_object_put(obj); 101362306a36Sopenharmony_ci} 101462306a36Sopenharmony_ciEXPORT_SYMBOL(drm_gem_vm_close); 101562306a36Sopenharmony_ci 101662306a36Sopenharmony_ci/** 101762306a36Sopenharmony_ci * drm_gem_mmap_obj - memory map a GEM object 101862306a36Sopenharmony_ci * @obj: the GEM object to map 101962306a36Sopenharmony_ci * @obj_size: the object size to be mapped, in bytes 102062306a36Sopenharmony_ci * @vma: VMA for the area to be mapped 102162306a36Sopenharmony_ci * 102262306a36Sopenharmony_ci * Set up the VMA to prepare mapping of the GEM object using the GEM object's 102362306a36Sopenharmony_ci * vm_ops. Depending on their requirements, GEM objects can either 102462306a36Sopenharmony_ci * provide a fault handler in their vm_ops (in which case any accesses to 102562306a36Sopenharmony_ci * the object will be trapped, to perform migration, GTT binding, surface 102662306a36Sopenharmony_ci * register allocation, or performance monitoring), or mmap the buffer memory 102762306a36Sopenharmony_ci * synchronously after calling drm_gem_mmap_obj. 102862306a36Sopenharmony_ci * 102962306a36Sopenharmony_ci * This function is mainly intended to implement the DMABUF mmap operation, when 103062306a36Sopenharmony_ci * the GEM object is not looked up based on its fake offset. To implement the 103162306a36Sopenharmony_ci * DRM mmap operation, drivers should use the drm_gem_mmap() function. 103262306a36Sopenharmony_ci * 103362306a36Sopenharmony_ci * drm_gem_mmap_obj() assumes the user is granted access to the buffer while 103462306a36Sopenharmony_ci * drm_gem_mmap() prevents unprivileged users from mapping random objects. So 103562306a36Sopenharmony_ci * callers must verify access restrictions before calling this helper. 103662306a36Sopenharmony_ci * 103762306a36Sopenharmony_ci * Return 0 or success or -EINVAL if the object size is smaller than the VMA 103862306a36Sopenharmony_ci * size, or if no vm_ops are provided. 103962306a36Sopenharmony_ci */ 104062306a36Sopenharmony_ciint drm_gem_mmap_obj(struct drm_gem_object *obj, unsigned long obj_size, 104162306a36Sopenharmony_ci struct vm_area_struct *vma) 104262306a36Sopenharmony_ci{ 104362306a36Sopenharmony_ci int ret; 104462306a36Sopenharmony_ci 104562306a36Sopenharmony_ci /* Check for valid size. */ 104662306a36Sopenharmony_ci if (obj_size < vma->vm_end - vma->vm_start) 104762306a36Sopenharmony_ci return -EINVAL; 104862306a36Sopenharmony_ci 104962306a36Sopenharmony_ci /* Take a ref for this mapping of the object, so that the fault 105062306a36Sopenharmony_ci * handler can dereference the mmap offset's pointer to the object. 105162306a36Sopenharmony_ci * This reference is cleaned up by the corresponding vm_close 105262306a36Sopenharmony_ci * (which should happen whether the vma was created by this call, or 105362306a36Sopenharmony_ci * by a vm_open due to mremap or partial unmap or whatever). 105462306a36Sopenharmony_ci */ 105562306a36Sopenharmony_ci drm_gem_object_get(obj); 105662306a36Sopenharmony_ci 105762306a36Sopenharmony_ci vma->vm_private_data = obj; 105862306a36Sopenharmony_ci vma->vm_ops = obj->funcs->vm_ops; 105962306a36Sopenharmony_ci 106062306a36Sopenharmony_ci if (obj->funcs->mmap) { 106162306a36Sopenharmony_ci ret = obj->funcs->mmap(obj, vma); 106262306a36Sopenharmony_ci if (ret) 106362306a36Sopenharmony_ci goto err_drm_gem_object_put; 106462306a36Sopenharmony_ci WARN_ON(!(vma->vm_flags & VM_DONTEXPAND)); 106562306a36Sopenharmony_ci } else { 106662306a36Sopenharmony_ci if (!vma->vm_ops) { 106762306a36Sopenharmony_ci ret = -EINVAL; 106862306a36Sopenharmony_ci goto err_drm_gem_object_put; 106962306a36Sopenharmony_ci } 107062306a36Sopenharmony_ci 107162306a36Sopenharmony_ci vm_flags_set(vma, VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP); 107262306a36Sopenharmony_ci vma->vm_page_prot = pgprot_writecombine(vm_get_page_prot(vma->vm_flags)); 107362306a36Sopenharmony_ci vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot); 107462306a36Sopenharmony_ci } 107562306a36Sopenharmony_ci 107662306a36Sopenharmony_ci return 0; 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_cierr_drm_gem_object_put: 107962306a36Sopenharmony_ci drm_gem_object_put(obj); 108062306a36Sopenharmony_ci return ret; 108162306a36Sopenharmony_ci} 108262306a36Sopenharmony_ciEXPORT_SYMBOL(drm_gem_mmap_obj); 108362306a36Sopenharmony_ci 108462306a36Sopenharmony_ci/** 108562306a36Sopenharmony_ci * drm_gem_mmap - memory map routine for GEM objects 108662306a36Sopenharmony_ci * @filp: DRM file pointer 108762306a36Sopenharmony_ci * @vma: VMA for the area to be mapped 108862306a36Sopenharmony_ci * 108962306a36Sopenharmony_ci * If a driver supports GEM object mapping, mmap calls on the DRM file 109062306a36Sopenharmony_ci * descriptor will end up here. 109162306a36Sopenharmony_ci * 109262306a36Sopenharmony_ci * Look up the GEM object based on the offset passed in (vma->vm_pgoff will 109362306a36Sopenharmony_ci * contain the fake offset we created when the GTT map ioctl was called on 109462306a36Sopenharmony_ci * the object) and map it with a call to drm_gem_mmap_obj(). 109562306a36Sopenharmony_ci * 109662306a36Sopenharmony_ci * If the caller is not granted access to the buffer object, the mmap will fail 109762306a36Sopenharmony_ci * with EACCES. Please see the vma manager for more information. 109862306a36Sopenharmony_ci */ 109962306a36Sopenharmony_ciint drm_gem_mmap(struct file *filp, struct vm_area_struct *vma) 110062306a36Sopenharmony_ci{ 110162306a36Sopenharmony_ci struct drm_file *priv = filp->private_data; 110262306a36Sopenharmony_ci struct drm_device *dev = priv->minor->dev; 110362306a36Sopenharmony_ci struct drm_gem_object *obj = NULL; 110462306a36Sopenharmony_ci struct drm_vma_offset_node *node; 110562306a36Sopenharmony_ci int ret; 110662306a36Sopenharmony_ci 110762306a36Sopenharmony_ci if (drm_dev_is_unplugged(dev)) 110862306a36Sopenharmony_ci return -ENODEV; 110962306a36Sopenharmony_ci 111062306a36Sopenharmony_ci drm_vma_offset_lock_lookup(dev->vma_offset_manager); 111162306a36Sopenharmony_ci node = drm_vma_offset_exact_lookup_locked(dev->vma_offset_manager, 111262306a36Sopenharmony_ci vma->vm_pgoff, 111362306a36Sopenharmony_ci vma_pages(vma)); 111462306a36Sopenharmony_ci if (likely(node)) { 111562306a36Sopenharmony_ci obj = container_of(node, struct drm_gem_object, vma_node); 111662306a36Sopenharmony_ci /* 111762306a36Sopenharmony_ci * When the object is being freed, after it hits 0-refcnt it 111862306a36Sopenharmony_ci * proceeds to tear down the object. In the process it will 111962306a36Sopenharmony_ci * attempt to remove the VMA offset and so acquire this 112062306a36Sopenharmony_ci * mgr->vm_lock. Therefore if we find an object with a 0-refcnt 112162306a36Sopenharmony_ci * that matches our range, we know it is in the process of being 112262306a36Sopenharmony_ci * destroyed and will be freed as soon as we release the lock - 112362306a36Sopenharmony_ci * so we have to check for the 0-refcnted object and treat it as 112462306a36Sopenharmony_ci * invalid. 112562306a36Sopenharmony_ci */ 112662306a36Sopenharmony_ci if (!kref_get_unless_zero(&obj->refcount)) 112762306a36Sopenharmony_ci obj = NULL; 112862306a36Sopenharmony_ci } 112962306a36Sopenharmony_ci drm_vma_offset_unlock_lookup(dev->vma_offset_manager); 113062306a36Sopenharmony_ci 113162306a36Sopenharmony_ci if (!obj) 113262306a36Sopenharmony_ci return -EINVAL; 113362306a36Sopenharmony_ci 113462306a36Sopenharmony_ci if (!drm_vma_node_is_allowed(node, priv)) { 113562306a36Sopenharmony_ci drm_gem_object_put(obj); 113662306a36Sopenharmony_ci return -EACCES; 113762306a36Sopenharmony_ci } 113862306a36Sopenharmony_ci 113962306a36Sopenharmony_ci ret = drm_gem_mmap_obj(obj, drm_vma_node_size(node) << PAGE_SHIFT, 114062306a36Sopenharmony_ci vma); 114162306a36Sopenharmony_ci 114262306a36Sopenharmony_ci drm_gem_object_put(obj); 114362306a36Sopenharmony_ci 114462306a36Sopenharmony_ci return ret; 114562306a36Sopenharmony_ci} 114662306a36Sopenharmony_ciEXPORT_SYMBOL(drm_gem_mmap); 114762306a36Sopenharmony_ci 114862306a36Sopenharmony_civoid drm_gem_print_info(struct drm_printer *p, unsigned int indent, 114962306a36Sopenharmony_ci const struct drm_gem_object *obj) 115062306a36Sopenharmony_ci{ 115162306a36Sopenharmony_ci drm_printf_indent(p, indent, "name=%d\n", obj->name); 115262306a36Sopenharmony_ci drm_printf_indent(p, indent, "refcount=%u\n", 115362306a36Sopenharmony_ci kref_read(&obj->refcount)); 115462306a36Sopenharmony_ci drm_printf_indent(p, indent, "start=%08lx\n", 115562306a36Sopenharmony_ci drm_vma_node_start(&obj->vma_node)); 115662306a36Sopenharmony_ci drm_printf_indent(p, indent, "size=%zu\n", obj->size); 115762306a36Sopenharmony_ci drm_printf_indent(p, indent, "imported=%s\n", 115862306a36Sopenharmony_ci str_yes_no(obj->import_attach)); 115962306a36Sopenharmony_ci 116062306a36Sopenharmony_ci if (obj->funcs->print_info) 116162306a36Sopenharmony_ci obj->funcs->print_info(p, indent, obj); 116262306a36Sopenharmony_ci} 116362306a36Sopenharmony_ci 116462306a36Sopenharmony_ciint drm_gem_pin(struct drm_gem_object *obj) 116562306a36Sopenharmony_ci{ 116662306a36Sopenharmony_ci if (obj->funcs->pin) 116762306a36Sopenharmony_ci return obj->funcs->pin(obj); 116862306a36Sopenharmony_ci 116962306a36Sopenharmony_ci return 0; 117062306a36Sopenharmony_ci} 117162306a36Sopenharmony_ci 117262306a36Sopenharmony_civoid drm_gem_unpin(struct drm_gem_object *obj) 117362306a36Sopenharmony_ci{ 117462306a36Sopenharmony_ci if (obj->funcs->unpin) 117562306a36Sopenharmony_ci obj->funcs->unpin(obj); 117662306a36Sopenharmony_ci} 117762306a36Sopenharmony_ci 117862306a36Sopenharmony_ciint drm_gem_vmap(struct drm_gem_object *obj, struct iosys_map *map) 117962306a36Sopenharmony_ci{ 118062306a36Sopenharmony_ci int ret; 118162306a36Sopenharmony_ci 118262306a36Sopenharmony_ci dma_resv_assert_held(obj->resv); 118362306a36Sopenharmony_ci 118462306a36Sopenharmony_ci if (!obj->funcs->vmap) 118562306a36Sopenharmony_ci return -EOPNOTSUPP; 118662306a36Sopenharmony_ci 118762306a36Sopenharmony_ci ret = obj->funcs->vmap(obj, map); 118862306a36Sopenharmony_ci if (ret) 118962306a36Sopenharmony_ci return ret; 119062306a36Sopenharmony_ci else if (iosys_map_is_null(map)) 119162306a36Sopenharmony_ci return -ENOMEM; 119262306a36Sopenharmony_ci 119362306a36Sopenharmony_ci return 0; 119462306a36Sopenharmony_ci} 119562306a36Sopenharmony_ciEXPORT_SYMBOL(drm_gem_vmap); 119662306a36Sopenharmony_ci 119762306a36Sopenharmony_civoid drm_gem_vunmap(struct drm_gem_object *obj, struct iosys_map *map) 119862306a36Sopenharmony_ci{ 119962306a36Sopenharmony_ci dma_resv_assert_held(obj->resv); 120062306a36Sopenharmony_ci 120162306a36Sopenharmony_ci if (iosys_map_is_null(map)) 120262306a36Sopenharmony_ci return; 120362306a36Sopenharmony_ci 120462306a36Sopenharmony_ci if (obj->funcs->vunmap) 120562306a36Sopenharmony_ci obj->funcs->vunmap(obj, map); 120662306a36Sopenharmony_ci 120762306a36Sopenharmony_ci /* Always set the mapping to NULL. Callers may rely on this. */ 120862306a36Sopenharmony_ci iosys_map_clear(map); 120962306a36Sopenharmony_ci} 121062306a36Sopenharmony_ciEXPORT_SYMBOL(drm_gem_vunmap); 121162306a36Sopenharmony_ci 121262306a36Sopenharmony_ciint drm_gem_vmap_unlocked(struct drm_gem_object *obj, struct iosys_map *map) 121362306a36Sopenharmony_ci{ 121462306a36Sopenharmony_ci int ret; 121562306a36Sopenharmony_ci 121662306a36Sopenharmony_ci dma_resv_lock(obj->resv, NULL); 121762306a36Sopenharmony_ci ret = drm_gem_vmap(obj, map); 121862306a36Sopenharmony_ci dma_resv_unlock(obj->resv); 121962306a36Sopenharmony_ci 122062306a36Sopenharmony_ci return ret; 122162306a36Sopenharmony_ci} 122262306a36Sopenharmony_ciEXPORT_SYMBOL(drm_gem_vmap_unlocked); 122362306a36Sopenharmony_ci 122462306a36Sopenharmony_civoid drm_gem_vunmap_unlocked(struct drm_gem_object *obj, struct iosys_map *map) 122562306a36Sopenharmony_ci{ 122662306a36Sopenharmony_ci dma_resv_lock(obj->resv, NULL); 122762306a36Sopenharmony_ci drm_gem_vunmap(obj, map); 122862306a36Sopenharmony_ci dma_resv_unlock(obj->resv); 122962306a36Sopenharmony_ci} 123062306a36Sopenharmony_ciEXPORT_SYMBOL(drm_gem_vunmap_unlocked); 123162306a36Sopenharmony_ci 123262306a36Sopenharmony_ci/** 123362306a36Sopenharmony_ci * drm_gem_lock_reservations - Sets up the ww context and acquires 123462306a36Sopenharmony_ci * the lock on an array of GEM objects. 123562306a36Sopenharmony_ci * 123662306a36Sopenharmony_ci * Once you've locked your reservations, you'll want to set up space 123762306a36Sopenharmony_ci * for your shared fences (if applicable), submit your job, then 123862306a36Sopenharmony_ci * drm_gem_unlock_reservations(). 123962306a36Sopenharmony_ci * 124062306a36Sopenharmony_ci * @objs: drm_gem_objects to lock 124162306a36Sopenharmony_ci * @count: Number of objects in @objs 124262306a36Sopenharmony_ci * @acquire_ctx: struct ww_acquire_ctx that will be initialized as 124362306a36Sopenharmony_ci * part of tracking this set of locked reservations. 124462306a36Sopenharmony_ci */ 124562306a36Sopenharmony_ciint 124662306a36Sopenharmony_cidrm_gem_lock_reservations(struct drm_gem_object **objs, int count, 124762306a36Sopenharmony_ci struct ww_acquire_ctx *acquire_ctx) 124862306a36Sopenharmony_ci{ 124962306a36Sopenharmony_ci int contended = -1; 125062306a36Sopenharmony_ci int i, ret; 125162306a36Sopenharmony_ci 125262306a36Sopenharmony_ci ww_acquire_init(acquire_ctx, &reservation_ww_class); 125362306a36Sopenharmony_ci 125462306a36Sopenharmony_ciretry: 125562306a36Sopenharmony_ci if (contended != -1) { 125662306a36Sopenharmony_ci struct drm_gem_object *obj = objs[contended]; 125762306a36Sopenharmony_ci 125862306a36Sopenharmony_ci ret = dma_resv_lock_slow_interruptible(obj->resv, 125962306a36Sopenharmony_ci acquire_ctx); 126062306a36Sopenharmony_ci if (ret) { 126162306a36Sopenharmony_ci ww_acquire_fini(acquire_ctx); 126262306a36Sopenharmony_ci return ret; 126362306a36Sopenharmony_ci } 126462306a36Sopenharmony_ci } 126562306a36Sopenharmony_ci 126662306a36Sopenharmony_ci for (i = 0; i < count; i++) { 126762306a36Sopenharmony_ci if (i == contended) 126862306a36Sopenharmony_ci continue; 126962306a36Sopenharmony_ci 127062306a36Sopenharmony_ci ret = dma_resv_lock_interruptible(objs[i]->resv, 127162306a36Sopenharmony_ci acquire_ctx); 127262306a36Sopenharmony_ci if (ret) { 127362306a36Sopenharmony_ci int j; 127462306a36Sopenharmony_ci 127562306a36Sopenharmony_ci for (j = 0; j < i; j++) 127662306a36Sopenharmony_ci dma_resv_unlock(objs[j]->resv); 127762306a36Sopenharmony_ci 127862306a36Sopenharmony_ci if (contended != -1 && contended >= i) 127962306a36Sopenharmony_ci dma_resv_unlock(objs[contended]->resv); 128062306a36Sopenharmony_ci 128162306a36Sopenharmony_ci if (ret == -EDEADLK) { 128262306a36Sopenharmony_ci contended = i; 128362306a36Sopenharmony_ci goto retry; 128462306a36Sopenharmony_ci } 128562306a36Sopenharmony_ci 128662306a36Sopenharmony_ci ww_acquire_fini(acquire_ctx); 128762306a36Sopenharmony_ci return ret; 128862306a36Sopenharmony_ci } 128962306a36Sopenharmony_ci } 129062306a36Sopenharmony_ci 129162306a36Sopenharmony_ci ww_acquire_done(acquire_ctx); 129262306a36Sopenharmony_ci 129362306a36Sopenharmony_ci return 0; 129462306a36Sopenharmony_ci} 129562306a36Sopenharmony_ciEXPORT_SYMBOL(drm_gem_lock_reservations); 129662306a36Sopenharmony_ci 129762306a36Sopenharmony_civoid 129862306a36Sopenharmony_cidrm_gem_unlock_reservations(struct drm_gem_object **objs, int count, 129962306a36Sopenharmony_ci struct ww_acquire_ctx *acquire_ctx) 130062306a36Sopenharmony_ci{ 130162306a36Sopenharmony_ci int i; 130262306a36Sopenharmony_ci 130362306a36Sopenharmony_ci for (i = 0; i < count; i++) 130462306a36Sopenharmony_ci dma_resv_unlock(objs[i]->resv); 130562306a36Sopenharmony_ci 130662306a36Sopenharmony_ci ww_acquire_fini(acquire_ctx); 130762306a36Sopenharmony_ci} 130862306a36Sopenharmony_ciEXPORT_SYMBOL(drm_gem_unlock_reservations); 130962306a36Sopenharmony_ci 131062306a36Sopenharmony_ci/** 131162306a36Sopenharmony_ci * drm_gem_lru_init - initialize a LRU 131262306a36Sopenharmony_ci * 131362306a36Sopenharmony_ci * @lru: The LRU to initialize 131462306a36Sopenharmony_ci * @lock: The lock protecting the LRU 131562306a36Sopenharmony_ci */ 131662306a36Sopenharmony_civoid 131762306a36Sopenharmony_cidrm_gem_lru_init(struct drm_gem_lru *lru, struct mutex *lock) 131862306a36Sopenharmony_ci{ 131962306a36Sopenharmony_ci lru->lock = lock; 132062306a36Sopenharmony_ci lru->count = 0; 132162306a36Sopenharmony_ci INIT_LIST_HEAD(&lru->list); 132262306a36Sopenharmony_ci} 132362306a36Sopenharmony_ciEXPORT_SYMBOL(drm_gem_lru_init); 132462306a36Sopenharmony_ci 132562306a36Sopenharmony_cistatic void 132662306a36Sopenharmony_cidrm_gem_lru_remove_locked(struct drm_gem_object *obj) 132762306a36Sopenharmony_ci{ 132862306a36Sopenharmony_ci obj->lru->count -= obj->size >> PAGE_SHIFT; 132962306a36Sopenharmony_ci WARN_ON(obj->lru->count < 0); 133062306a36Sopenharmony_ci list_del(&obj->lru_node); 133162306a36Sopenharmony_ci obj->lru = NULL; 133262306a36Sopenharmony_ci} 133362306a36Sopenharmony_ci 133462306a36Sopenharmony_ci/** 133562306a36Sopenharmony_ci * drm_gem_lru_remove - remove object from whatever LRU it is in 133662306a36Sopenharmony_ci * 133762306a36Sopenharmony_ci * If the object is currently in any LRU, remove it. 133862306a36Sopenharmony_ci * 133962306a36Sopenharmony_ci * @obj: The GEM object to remove from current LRU 134062306a36Sopenharmony_ci */ 134162306a36Sopenharmony_civoid 134262306a36Sopenharmony_cidrm_gem_lru_remove(struct drm_gem_object *obj) 134362306a36Sopenharmony_ci{ 134462306a36Sopenharmony_ci struct drm_gem_lru *lru = obj->lru; 134562306a36Sopenharmony_ci 134662306a36Sopenharmony_ci if (!lru) 134762306a36Sopenharmony_ci return; 134862306a36Sopenharmony_ci 134962306a36Sopenharmony_ci mutex_lock(lru->lock); 135062306a36Sopenharmony_ci drm_gem_lru_remove_locked(obj); 135162306a36Sopenharmony_ci mutex_unlock(lru->lock); 135262306a36Sopenharmony_ci} 135362306a36Sopenharmony_ciEXPORT_SYMBOL(drm_gem_lru_remove); 135462306a36Sopenharmony_ci 135562306a36Sopenharmony_ci/** 135662306a36Sopenharmony_ci * drm_gem_lru_move_tail_locked - move the object to the tail of the LRU 135762306a36Sopenharmony_ci * 135862306a36Sopenharmony_ci * Like &drm_gem_lru_move_tail but lru lock must be held 135962306a36Sopenharmony_ci * 136062306a36Sopenharmony_ci * @lru: The LRU to move the object into. 136162306a36Sopenharmony_ci * @obj: The GEM object to move into this LRU 136262306a36Sopenharmony_ci */ 136362306a36Sopenharmony_civoid 136462306a36Sopenharmony_cidrm_gem_lru_move_tail_locked(struct drm_gem_lru *lru, struct drm_gem_object *obj) 136562306a36Sopenharmony_ci{ 136662306a36Sopenharmony_ci lockdep_assert_held_once(lru->lock); 136762306a36Sopenharmony_ci 136862306a36Sopenharmony_ci if (obj->lru) 136962306a36Sopenharmony_ci drm_gem_lru_remove_locked(obj); 137062306a36Sopenharmony_ci 137162306a36Sopenharmony_ci lru->count += obj->size >> PAGE_SHIFT; 137262306a36Sopenharmony_ci list_add_tail(&obj->lru_node, &lru->list); 137362306a36Sopenharmony_ci obj->lru = lru; 137462306a36Sopenharmony_ci} 137562306a36Sopenharmony_ciEXPORT_SYMBOL(drm_gem_lru_move_tail_locked); 137662306a36Sopenharmony_ci 137762306a36Sopenharmony_ci/** 137862306a36Sopenharmony_ci * drm_gem_lru_move_tail - move the object to the tail of the LRU 137962306a36Sopenharmony_ci * 138062306a36Sopenharmony_ci * If the object is already in this LRU it will be moved to the 138162306a36Sopenharmony_ci * tail. Otherwise it will be removed from whichever other LRU 138262306a36Sopenharmony_ci * it is in (if any) and moved into this LRU. 138362306a36Sopenharmony_ci * 138462306a36Sopenharmony_ci * @lru: The LRU to move the object into. 138562306a36Sopenharmony_ci * @obj: The GEM object to move into this LRU 138662306a36Sopenharmony_ci */ 138762306a36Sopenharmony_civoid 138862306a36Sopenharmony_cidrm_gem_lru_move_tail(struct drm_gem_lru *lru, struct drm_gem_object *obj) 138962306a36Sopenharmony_ci{ 139062306a36Sopenharmony_ci mutex_lock(lru->lock); 139162306a36Sopenharmony_ci drm_gem_lru_move_tail_locked(lru, obj); 139262306a36Sopenharmony_ci mutex_unlock(lru->lock); 139362306a36Sopenharmony_ci} 139462306a36Sopenharmony_ciEXPORT_SYMBOL(drm_gem_lru_move_tail); 139562306a36Sopenharmony_ci 139662306a36Sopenharmony_ci/** 139762306a36Sopenharmony_ci * drm_gem_lru_scan - helper to implement shrinker.scan_objects 139862306a36Sopenharmony_ci * 139962306a36Sopenharmony_ci * If the shrink callback succeeds, it is expected that the driver 140062306a36Sopenharmony_ci * move the object out of this LRU. 140162306a36Sopenharmony_ci * 140262306a36Sopenharmony_ci * If the LRU possibly contain active buffers, it is the responsibility 140362306a36Sopenharmony_ci * of the shrink callback to check for this (ie. dma_resv_test_signaled()) 140462306a36Sopenharmony_ci * or if necessary block until the buffer becomes idle. 140562306a36Sopenharmony_ci * 140662306a36Sopenharmony_ci * @lru: The LRU to scan 140762306a36Sopenharmony_ci * @nr_to_scan: The number of pages to try to reclaim 140862306a36Sopenharmony_ci * @remaining: The number of pages left to reclaim, should be initialized by caller 140962306a36Sopenharmony_ci * @shrink: Callback to try to shrink/reclaim the object. 141062306a36Sopenharmony_ci */ 141162306a36Sopenharmony_ciunsigned long 141262306a36Sopenharmony_cidrm_gem_lru_scan(struct drm_gem_lru *lru, 141362306a36Sopenharmony_ci unsigned int nr_to_scan, 141462306a36Sopenharmony_ci unsigned long *remaining, 141562306a36Sopenharmony_ci bool (*shrink)(struct drm_gem_object *obj)) 141662306a36Sopenharmony_ci{ 141762306a36Sopenharmony_ci struct drm_gem_lru still_in_lru; 141862306a36Sopenharmony_ci struct drm_gem_object *obj; 141962306a36Sopenharmony_ci unsigned freed = 0; 142062306a36Sopenharmony_ci 142162306a36Sopenharmony_ci drm_gem_lru_init(&still_in_lru, lru->lock); 142262306a36Sopenharmony_ci 142362306a36Sopenharmony_ci mutex_lock(lru->lock); 142462306a36Sopenharmony_ci 142562306a36Sopenharmony_ci while (freed < nr_to_scan) { 142662306a36Sopenharmony_ci obj = list_first_entry_or_null(&lru->list, typeof(*obj), lru_node); 142762306a36Sopenharmony_ci 142862306a36Sopenharmony_ci if (!obj) 142962306a36Sopenharmony_ci break; 143062306a36Sopenharmony_ci 143162306a36Sopenharmony_ci drm_gem_lru_move_tail_locked(&still_in_lru, obj); 143262306a36Sopenharmony_ci 143362306a36Sopenharmony_ci /* 143462306a36Sopenharmony_ci * If it's in the process of being freed, gem_object->free() 143562306a36Sopenharmony_ci * may be blocked on lock waiting to remove it. So just 143662306a36Sopenharmony_ci * skip it. 143762306a36Sopenharmony_ci */ 143862306a36Sopenharmony_ci if (!kref_get_unless_zero(&obj->refcount)) 143962306a36Sopenharmony_ci continue; 144062306a36Sopenharmony_ci 144162306a36Sopenharmony_ci /* 144262306a36Sopenharmony_ci * Now that we own a reference, we can drop the lock for the 144362306a36Sopenharmony_ci * rest of the loop body, to reduce contention with other 144462306a36Sopenharmony_ci * code paths that need the LRU lock 144562306a36Sopenharmony_ci */ 144662306a36Sopenharmony_ci mutex_unlock(lru->lock); 144762306a36Sopenharmony_ci 144862306a36Sopenharmony_ci /* 144962306a36Sopenharmony_ci * Note that this still needs to be trylock, since we can 145062306a36Sopenharmony_ci * hit shrinker in response to trying to get backing pages 145162306a36Sopenharmony_ci * for this obj (ie. while it's lock is already held) 145262306a36Sopenharmony_ci */ 145362306a36Sopenharmony_ci if (!dma_resv_trylock(obj->resv)) { 145462306a36Sopenharmony_ci *remaining += obj->size >> PAGE_SHIFT; 145562306a36Sopenharmony_ci goto tail; 145662306a36Sopenharmony_ci } 145762306a36Sopenharmony_ci 145862306a36Sopenharmony_ci if (shrink(obj)) { 145962306a36Sopenharmony_ci freed += obj->size >> PAGE_SHIFT; 146062306a36Sopenharmony_ci 146162306a36Sopenharmony_ci /* 146262306a36Sopenharmony_ci * If we succeeded in releasing the object's backing 146362306a36Sopenharmony_ci * pages, we expect the driver to have moved the object 146462306a36Sopenharmony_ci * out of this LRU 146562306a36Sopenharmony_ci */ 146662306a36Sopenharmony_ci WARN_ON(obj->lru == &still_in_lru); 146762306a36Sopenharmony_ci WARN_ON(obj->lru == lru); 146862306a36Sopenharmony_ci } 146962306a36Sopenharmony_ci 147062306a36Sopenharmony_ci dma_resv_unlock(obj->resv); 147162306a36Sopenharmony_ci 147262306a36Sopenharmony_citail: 147362306a36Sopenharmony_ci drm_gem_object_put(obj); 147462306a36Sopenharmony_ci mutex_lock(lru->lock); 147562306a36Sopenharmony_ci } 147662306a36Sopenharmony_ci 147762306a36Sopenharmony_ci /* 147862306a36Sopenharmony_ci * Move objects we've skipped over out of the temporary still_in_lru 147962306a36Sopenharmony_ci * back into this LRU 148062306a36Sopenharmony_ci */ 148162306a36Sopenharmony_ci list_for_each_entry (obj, &still_in_lru.list, lru_node) 148262306a36Sopenharmony_ci obj->lru = lru; 148362306a36Sopenharmony_ci list_splice_tail(&still_in_lru.list, &lru->list); 148462306a36Sopenharmony_ci lru->count += still_in_lru.count; 148562306a36Sopenharmony_ci 148662306a36Sopenharmony_ci mutex_unlock(lru->lock); 148762306a36Sopenharmony_ci 148862306a36Sopenharmony_ci return freed; 148962306a36Sopenharmony_ci} 149062306a36Sopenharmony_ciEXPORT_SYMBOL(drm_gem_lru_scan); 149162306a36Sopenharmony_ci 149262306a36Sopenharmony_ci/** 149362306a36Sopenharmony_ci * drm_gem_evict - helper to evict backing pages for a GEM object 149462306a36Sopenharmony_ci * @obj: obj in question 149562306a36Sopenharmony_ci */ 149662306a36Sopenharmony_ciint drm_gem_evict(struct drm_gem_object *obj) 149762306a36Sopenharmony_ci{ 149862306a36Sopenharmony_ci dma_resv_assert_held(obj->resv); 149962306a36Sopenharmony_ci 150062306a36Sopenharmony_ci if (!dma_resv_test_signaled(obj->resv, DMA_RESV_USAGE_READ)) 150162306a36Sopenharmony_ci return -EBUSY; 150262306a36Sopenharmony_ci 150362306a36Sopenharmony_ci if (obj->funcs->evict) 150462306a36Sopenharmony_ci return obj->funcs->evict(obj); 150562306a36Sopenharmony_ci 150662306a36Sopenharmony_ci return 0; 150762306a36Sopenharmony_ci} 150862306a36Sopenharmony_ciEXPORT_SYMBOL(drm_gem_evict); 1509