xref: /kernel/linux/linux-6.6/drivers/gpu/drm/drm_gem.c (revision 62306a36)
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