18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 OR MIT */
28c2ecf20Sopenharmony_ci/**************************************************************************
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Copyright (c) 2009-2013 VMware, Inc., Palo Alto, CA., USA
58c2ecf20Sopenharmony_ci * All Rights Reserved.
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
88c2ecf20Sopenharmony_ci * copy of this software and associated documentation files (the
98c2ecf20Sopenharmony_ci * "Software"), to deal in the Software without restriction, including
108c2ecf20Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish,
118c2ecf20Sopenharmony_ci * distribute, sub license, and/or sell copies of the Software, and to
128c2ecf20Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to
138c2ecf20Sopenharmony_ci * the following conditions:
148c2ecf20Sopenharmony_ci *
158c2ecf20Sopenharmony_ci * The above copyright notice and this permission notice (including the
168c2ecf20Sopenharmony_ci * next paragraph) shall be included in all copies or substantial portions
178c2ecf20Sopenharmony_ci * of the Software.
188c2ecf20Sopenharmony_ci *
198c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
208c2ecf20Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
218c2ecf20Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
228c2ecf20Sopenharmony_ci * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
238c2ecf20Sopenharmony_ci * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
248c2ecf20Sopenharmony_ci * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
258c2ecf20Sopenharmony_ci * USE OR OTHER DEALINGS IN THE SOFTWARE.
268c2ecf20Sopenharmony_ci *
278c2ecf20Sopenharmony_ci **************************************************************************/
288c2ecf20Sopenharmony_ci/*
298c2ecf20Sopenharmony_ci * Authors: Thomas Hellstrom <thellstrom-at-vmware-dot-com>
308c2ecf20Sopenharmony_ci *
318c2ecf20Sopenharmony_ci * While no substantial code is shared, the prime code is inspired by
328c2ecf20Sopenharmony_ci * drm_prime.c, with
338c2ecf20Sopenharmony_ci * Authors:
348c2ecf20Sopenharmony_ci *      Dave Airlie <airlied@redhat.com>
358c2ecf20Sopenharmony_ci *      Rob Clark <rob.clark@linaro.org>
368c2ecf20Sopenharmony_ci */
378c2ecf20Sopenharmony_ci/** @file ttm_ref_object.c
388c2ecf20Sopenharmony_ci *
398c2ecf20Sopenharmony_ci * Base- and reference object implementation for the various
408c2ecf20Sopenharmony_ci * ttm objects. Implements reference counting, minimal security checks
418c2ecf20Sopenharmony_ci * and release on file close.
428c2ecf20Sopenharmony_ci */
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci/**
468c2ecf20Sopenharmony_ci * struct ttm_object_file
478c2ecf20Sopenharmony_ci *
488c2ecf20Sopenharmony_ci * @tdev: Pointer to the ttm_object_device.
498c2ecf20Sopenharmony_ci *
508c2ecf20Sopenharmony_ci * @lock: Lock that protects the ref_list list and the
518c2ecf20Sopenharmony_ci * ref_hash hash tables.
528c2ecf20Sopenharmony_ci *
538c2ecf20Sopenharmony_ci * @ref_list: List of ttm_ref_objects to be destroyed at
548c2ecf20Sopenharmony_ci * file release.
558c2ecf20Sopenharmony_ci *
568c2ecf20Sopenharmony_ci * @ref_hash: Hash tables of ref objects, one per ttm_ref_type,
578c2ecf20Sopenharmony_ci * for fast lookup of ref objects given a base object.
588c2ecf20Sopenharmony_ci */
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci#define pr_fmt(fmt) "[TTM] " fmt
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci#include <drm/ttm/ttm_module.h>
638c2ecf20Sopenharmony_ci#include <linux/list.h>
648c2ecf20Sopenharmony_ci#include <linux/spinlock.h>
658c2ecf20Sopenharmony_ci#include <linux/slab.h>
668c2ecf20Sopenharmony_ci#include <linux/atomic.h>
678c2ecf20Sopenharmony_ci#include "ttm_object.h"
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_cistruct ttm_object_file {
708c2ecf20Sopenharmony_ci	struct ttm_object_device *tdev;
718c2ecf20Sopenharmony_ci	spinlock_t lock;
728c2ecf20Sopenharmony_ci	struct list_head ref_list;
738c2ecf20Sopenharmony_ci	struct drm_open_hash ref_hash[TTM_REF_NUM];
748c2ecf20Sopenharmony_ci	struct kref refcount;
758c2ecf20Sopenharmony_ci};
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci/**
788c2ecf20Sopenharmony_ci * struct ttm_object_device
798c2ecf20Sopenharmony_ci *
808c2ecf20Sopenharmony_ci * @object_lock: lock that protects the object_hash hash table.
818c2ecf20Sopenharmony_ci *
828c2ecf20Sopenharmony_ci * @object_hash: hash table for fast lookup of object global names.
838c2ecf20Sopenharmony_ci *
848c2ecf20Sopenharmony_ci * @object_count: Per device object count.
858c2ecf20Sopenharmony_ci *
868c2ecf20Sopenharmony_ci * This is the per-device data structure needed for ttm object management.
878c2ecf20Sopenharmony_ci */
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_cistruct ttm_object_device {
908c2ecf20Sopenharmony_ci	spinlock_t object_lock;
918c2ecf20Sopenharmony_ci	struct drm_open_hash object_hash;
928c2ecf20Sopenharmony_ci	atomic_t object_count;
938c2ecf20Sopenharmony_ci	struct ttm_mem_global *mem_glob;
948c2ecf20Sopenharmony_ci	struct dma_buf_ops ops;
958c2ecf20Sopenharmony_ci	void (*dmabuf_release)(struct dma_buf *dma_buf);
968c2ecf20Sopenharmony_ci	size_t dma_buf_size;
978c2ecf20Sopenharmony_ci	struct idr idr;
988c2ecf20Sopenharmony_ci};
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci/**
1018c2ecf20Sopenharmony_ci * struct ttm_ref_object
1028c2ecf20Sopenharmony_ci *
1038c2ecf20Sopenharmony_ci * @hash: Hash entry for the per-file object reference hash.
1048c2ecf20Sopenharmony_ci *
1058c2ecf20Sopenharmony_ci * @head: List entry for the per-file list of ref-objects.
1068c2ecf20Sopenharmony_ci *
1078c2ecf20Sopenharmony_ci * @kref: Ref count.
1088c2ecf20Sopenharmony_ci *
1098c2ecf20Sopenharmony_ci * @obj: Base object this ref object is referencing.
1108c2ecf20Sopenharmony_ci *
1118c2ecf20Sopenharmony_ci * @ref_type: Type of ref object.
1128c2ecf20Sopenharmony_ci *
1138c2ecf20Sopenharmony_ci * This is similar to an idr object, but it also has a hash table entry
1148c2ecf20Sopenharmony_ci * that allows lookup with a pointer to the referenced object as a key. In
1158c2ecf20Sopenharmony_ci * that way, one can easily detect whether a base object is referenced by
1168c2ecf20Sopenharmony_ci * a particular ttm_object_file. It also carries a ref count to avoid creating
1178c2ecf20Sopenharmony_ci * multiple ref objects if a ttm_object_file references the same base
1188c2ecf20Sopenharmony_ci * object more than once.
1198c2ecf20Sopenharmony_ci */
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_cistruct ttm_ref_object {
1228c2ecf20Sopenharmony_ci	struct rcu_head rcu_head;
1238c2ecf20Sopenharmony_ci	struct drm_hash_item hash;
1248c2ecf20Sopenharmony_ci	struct list_head head;
1258c2ecf20Sopenharmony_ci	struct kref kref;
1268c2ecf20Sopenharmony_ci	enum ttm_ref_type ref_type;
1278c2ecf20Sopenharmony_ci	struct ttm_base_object *obj;
1288c2ecf20Sopenharmony_ci	struct ttm_object_file *tfile;
1298c2ecf20Sopenharmony_ci};
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_cistatic void ttm_prime_dmabuf_release(struct dma_buf *dma_buf);
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_cistatic inline struct ttm_object_file *
1348c2ecf20Sopenharmony_cittm_object_file_ref(struct ttm_object_file *tfile)
1358c2ecf20Sopenharmony_ci{
1368c2ecf20Sopenharmony_ci	kref_get(&tfile->refcount);
1378c2ecf20Sopenharmony_ci	return tfile;
1388c2ecf20Sopenharmony_ci}
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_cistatic void ttm_object_file_destroy(struct kref *kref)
1418c2ecf20Sopenharmony_ci{
1428c2ecf20Sopenharmony_ci	struct ttm_object_file *tfile =
1438c2ecf20Sopenharmony_ci		container_of(kref, struct ttm_object_file, refcount);
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci	kfree(tfile);
1468c2ecf20Sopenharmony_ci}
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_cistatic inline void ttm_object_file_unref(struct ttm_object_file **p_tfile)
1508c2ecf20Sopenharmony_ci{
1518c2ecf20Sopenharmony_ci	struct ttm_object_file *tfile = *p_tfile;
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	*p_tfile = NULL;
1548c2ecf20Sopenharmony_ci	kref_put(&tfile->refcount, ttm_object_file_destroy);
1558c2ecf20Sopenharmony_ci}
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ciint ttm_base_object_init(struct ttm_object_file *tfile,
1598c2ecf20Sopenharmony_ci			 struct ttm_base_object *base,
1608c2ecf20Sopenharmony_ci			 bool shareable,
1618c2ecf20Sopenharmony_ci			 enum ttm_object_type object_type,
1628c2ecf20Sopenharmony_ci			 void (*refcount_release) (struct ttm_base_object **),
1638c2ecf20Sopenharmony_ci			 void (*ref_obj_release) (struct ttm_base_object *,
1648c2ecf20Sopenharmony_ci						  enum ttm_ref_type ref_type))
1658c2ecf20Sopenharmony_ci{
1668c2ecf20Sopenharmony_ci	struct ttm_object_device *tdev = tfile->tdev;
1678c2ecf20Sopenharmony_ci	int ret;
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	base->shareable = shareable;
1708c2ecf20Sopenharmony_ci	base->tfile = ttm_object_file_ref(tfile);
1718c2ecf20Sopenharmony_ci	base->refcount_release = refcount_release;
1728c2ecf20Sopenharmony_ci	base->ref_obj_release = ref_obj_release;
1738c2ecf20Sopenharmony_ci	base->object_type = object_type;
1748c2ecf20Sopenharmony_ci	kref_init(&base->refcount);
1758c2ecf20Sopenharmony_ci	idr_preload(GFP_KERNEL);
1768c2ecf20Sopenharmony_ci	spin_lock(&tdev->object_lock);
1778c2ecf20Sopenharmony_ci	ret = idr_alloc(&tdev->idr, base, 1, 0, GFP_NOWAIT);
1788c2ecf20Sopenharmony_ci	spin_unlock(&tdev->object_lock);
1798c2ecf20Sopenharmony_ci	idr_preload_end();
1808c2ecf20Sopenharmony_ci	if (ret < 0)
1818c2ecf20Sopenharmony_ci		return ret;
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci	base->handle = ret;
1848c2ecf20Sopenharmony_ci	ret = ttm_ref_object_add(tfile, base, TTM_REF_USAGE, NULL, false);
1858c2ecf20Sopenharmony_ci	if (unlikely(ret != 0))
1868c2ecf20Sopenharmony_ci		goto out_err1;
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci	ttm_base_object_unref(&base);
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci	return 0;
1918c2ecf20Sopenharmony_ciout_err1:
1928c2ecf20Sopenharmony_ci	spin_lock(&tdev->object_lock);
1938c2ecf20Sopenharmony_ci	idr_remove(&tdev->idr, base->handle);
1948c2ecf20Sopenharmony_ci	spin_unlock(&tdev->object_lock);
1958c2ecf20Sopenharmony_ci	return ret;
1968c2ecf20Sopenharmony_ci}
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_cistatic void ttm_release_base(struct kref *kref)
1998c2ecf20Sopenharmony_ci{
2008c2ecf20Sopenharmony_ci	struct ttm_base_object *base =
2018c2ecf20Sopenharmony_ci	    container_of(kref, struct ttm_base_object, refcount);
2028c2ecf20Sopenharmony_ci	struct ttm_object_device *tdev = base->tfile->tdev;
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci	spin_lock(&tdev->object_lock);
2058c2ecf20Sopenharmony_ci	idr_remove(&tdev->idr, base->handle);
2068c2ecf20Sopenharmony_ci	spin_unlock(&tdev->object_lock);
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci	/*
2098c2ecf20Sopenharmony_ci	 * Note: We don't use synchronize_rcu() here because it's far
2108c2ecf20Sopenharmony_ci	 * too slow. It's up to the user to free the object using
2118c2ecf20Sopenharmony_ci	 * call_rcu() or ttm_base_object_kfree().
2128c2ecf20Sopenharmony_ci	 */
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci	ttm_object_file_unref(&base->tfile);
2158c2ecf20Sopenharmony_ci	if (base->refcount_release)
2168c2ecf20Sopenharmony_ci		base->refcount_release(&base);
2178c2ecf20Sopenharmony_ci}
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_civoid ttm_base_object_unref(struct ttm_base_object **p_base)
2208c2ecf20Sopenharmony_ci{
2218c2ecf20Sopenharmony_ci	struct ttm_base_object *base = *p_base;
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci	*p_base = NULL;
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci	kref_put(&base->refcount, ttm_release_base);
2268c2ecf20Sopenharmony_ci}
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci/**
2298c2ecf20Sopenharmony_ci * ttm_base_object_noref_lookup - look up a base object without reference
2308c2ecf20Sopenharmony_ci * @tfile: The struct ttm_object_file the object is registered with.
2318c2ecf20Sopenharmony_ci * @key: The object handle.
2328c2ecf20Sopenharmony_ci *
2338c2ecf20Sopenharmony_ci * This function looks up a ttm base object and returns a pointer to it
2348c2ecf20Sopenharmony_ci * without refcounting the pointer. The returned pointer is only valid
2358c2ecf20Sopenharmony_ci * until ttm_base_object_noref_release() is called, and the object
2368c2ecf20Sopenharmony_ci * pointed to by the returned pointer may be doomed. Any persistent usage
2378c2ecf20Sopenharmony_ci * of the object requires a refcount to be taken using kref_get_unless_zero().
2388c2ecf20Sopenharmony_ci * Iff this function returns successfully it needs to be paired with
2398c2ecf20Sopenharmony_ci * ttm_base_object_noref_release() and no sleeping- or scheduling functions
2408c2ecf20Sopenharmony_ci * may be called inbetween these function callse.
2418c2ecf20Sopenharmony_ci *
2428c2ecf20Sopenharmony_ci * Return: A pointer to the object if successful or NULL otherwise.
2438c2ecf20Sopenharmony_ci */
2448c2ecf20Sopenharmony_cistruct ttm_base_object *
2458c2ecf20Sopenharmony_cittm_base_object_noref_lookup(struct ttm_object_file *tfile, uint32_t key)
2468c2ecf20Sopenharmony_ci{
2478c2ecf20Sopenharmony_ci	struct drm_hash_item *hash;
2488c2ecf20Sopenharmony_ci	struct drm_open_hash *ht = &tfile->ref_hash[TTM_REF_USAGE];
2498c2ecf20Sopenharmony_ci	int ret;
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci	rcu_read_lock();
2528c2ecf20Sopenharmony_ci	ret = drm_ht_find_item_rcu(ht, key, &hash);
2538c2ecf20Sopenharmony_ci	if (ret) {
2548c2ecf20Sopenharmony_ci		rcu_read_unlock();
2558c2ecf20Sopenharmony_ci		return NULL;
2568c2ecf20Sopenharmony_ci	}
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci	__release(RCU);
2598c2ecf20Sopenharmony_ci	return drm_hash_entry(hash, struct ttm_ref_object, hash)->obj;
2608c2ecf20Sopenharmony_ci}
2618c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ttm_base_object_noref_lookup);
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_cistruct ttm_base_object *ttm_base_object_lookup(struct ttm_object_file *tfile,
2648c2ecf20Sopenharmony_ci					       uint32_t key)
2658c2ecf20Sopenharmony_ci{
2668c2ecf20Sopenharmony_ci	struct ttm_base_object *base = NULL;
2678c2ecf20Sopenharmony_ci	struct drm_hash_item *hash;
2688c2ecf20Sopenharmony_ci	struct drm_open_hash *ht = &tfile->ref_hash[TTM_REF_USAGE];
2698c2ecf20Sopenharmony_ci	int ret;
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci	rcu_read_lock();
2728c2ecf20Sopenharmony_ci	ret = drm_ht_find_item_rcu(ht, key, &hash);
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	if (likely(ret == 0)) {
2758c2ecf20Sopenharmony_ci		base = drm_hash_entry(hash, struct ttm_ref_object, hash)->obj;
2768c2ecf20Sopenharmony_ci		if (!kref_get_unless_zero(&base->refcount))
2778c2ecf20Sopenharmony_ci			base = NULL;
2788c2ecf20Sopenharmony_ci	}
2798c2ecf20Sopenharmony_ci	rcu_read_unlock();
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci	return base;
2828c2ecf20Sopenharmony_ci}
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_cistruct ttm_base_object *
2858c2ecf20Sopenharmony_cittm_base_object_lookup_for_ref(struct ttm_object_device *tdev, uint32_t key)
2868c2ecf20Sopenharmony_ci{
2878c2ecf20Sopenharmony_ci	struct ttm_base_object *base;
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci	rcu_read_lock();
2908c2ecf20Sopenharmony_ci	base = idr_find(&tdev->idr, key);
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci	if (base && !kref_get_unless_zero(&base->refcount))
2938c2ecf20Sopenharmony_ci		base = NULL;
2948c2ecf20Sopenharmony_ci	rcu_read_unlock();
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	return base;
2978c2ecf20Sopenharmony_ci}
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci/**
3008c2ecf20Sopenharmony_ci * ttm_ref_object_exists - Check whether a caller has a valid ref object
3018c2ecf20Sopenharmony_ci * (has opened) a base object.
3028c2ecf20Sopenharmony_ci *
3038c2ecf20Sopenharmony_ci * @tfile: Pointer to a struct ttm_object_file identifying the caller.
3048c2ecf20Sopenharmony_ci * @base: Pointer to a struct base object.
3058c2ecf20Sopenharmony_ci *
3068c2ecf20Sopenharmony_ci * Checks wether the caller identified by @tfile has put a valid USAGE
3078c2ecf20Sopenharmony_ci * reference object on the base object identified by @base.
3088c2ecf20Sopenharmony_ci */
3098c2ecf20Sopenharmony_cibool ttm_ref_object_exists(struct ttm_object_file *tfile,
3108c2ecf20Sopenharmony_ci			   struct ttm_base_object *base)
3118c2ecf20Sopenharmony_ci{
3128c2ecf20Sopenharmony_ci	struct drm_open_hash *ht = &tfile->ref_hash[TTM_REF_USAGE];
3138c2ecf20Sopenharmony_ci	struct drm_hash_item *hash;
3148c2ecf20Sopenharmony_ci	struct ttm_ref_object *ref;
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci	rcu_read_lock();
3178c2ecf20Sopenharmony_ci	if (unlikely(drm_ht_find_item_rcu(ht, base->handle, &hash) != 0))
3188c2ecf20Sopenharmony_ci		goto out_false;
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci	/*
3218c2ecf20Sopenharmony_ci	 * Verify that the ref object is really pointing to our base object.
3228c2ecf20Sopenharmony_ci	 * Our base object could actually be dead, and the ref object pointing
3238c2ecf20Sopenharmony_ci	 * to another base object with the same handle.
3248c2ecf20Sopenharmony_ci	 */
3258c2ecf20Sopenharmony_ci	ref = drm_hash_entry(hash, struct ttm_ref_object, hash);
3268c2ecf20Sopenharmony_ci	if (unlikely(base != ref->obj))
3278c2ecf20Sopenharmony_ci		goto out_false;
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci	/*
3308c2ecf20Sopenharmony_ci	 * Verify that the ref->obj pointer was actually valid!
3318c2ecf20Sopenharmony_ci	 */
3328c2ecf20Sopenharmony_ci	rmb();
3338c2ecf20Sopenharmony_ci	if (unlikely(kref_read(&ref->kref) == 0))
3348c2ecf20Sopenharmony_ci		goto out_false;
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci	rcu_read_unlock();
3378c2ecf20Sopenharmony_ci	return true;
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci out_false:
3408c2ecf20Sopenharmony_ci	rcu_read_unlock();
3418c2ecf20Sopenharmony_ci	return false;
3428c2ecf20Sopenharmony_ci}
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ciint ttm_ref_object_add(struct ttm_object_file *tfile,
3458c2ecf20Sopenharmony_ci		       struct ttm_base_object *base,
3468c2ecf20Sopenharmony_ci		       enum ttm_ref_type ref_type, bool *existed,
3478c2ecf20Sopenharmony_ci		       bool require_existed)
3488c2ecf20Sopenharmony_ci{
3498c2ecf20Sopenharmony_ci	struct drm_open_hash *ht = &tfile->ref_hash[ref_type];
3508c2ecf20Sopenharmony_ci	struct ttm_ref_object *ref;
3518c2ecf20Sopenharmony_ci	struct drm_hash_item *hash;
3528c2ecf20Sopenharmony_ci	struct ttm_mem_global *mem_glob = tfile->tdev->mem_glob;
3538c2ecf20Sopenharmony_ci	struct ttm_operation_ctx ctx = {
3548c2ecf20Sopenharmony_ci		.interruptible = false,
3558c2ecf20Sopenharmony_ci		.no_wait_gpu = false
3568c2ecf20Sopenharmony_ci	};
3578c2ecf20Sopenharmony_ci	int ret = -EINVAL;
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci	if (base->tfile != tfile && !base->shareable)
3608c2ecf20Sopenharmony_ci		return -EPERM;
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci	if (existed != NULL)
3638c2ecf20Sopenharmony_ci		*existed = true;
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci	while (ret == -EINVAL) {
3668c2ecf20Sopenharmony_ci		rcu_read_lock();
3678c2ecf20Sopenharmony_ci		ret = drm_ht_find_item_rcu(ht, base->handle, &hash);
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci		if (ret == 0) {
3708c2ecf20Sopenharmony_ci			ref = drm_hash_entry(hash, struct ttm_ref_object, hash);
3718c2ecf20Sopenharmony_ci			if (kref_get_unless_zero(&ref->kref)) {
3728c2ecf20Sopenharmony_ci				rcu_read_unlock();
3738c2ecf20Sopenharmony_ci				break;
3748c2ecf20Sopenharmony_ci			}
3758c2ecf20Sopenharmony_ci		}
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci		rcu_read_unlock();
3788c2ecf20Sopenharmony_ci		if (require_existed)
3798c2ecf20Sopenharmony_ci			return -EPERM;
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci		ret = ttm_mem_global_alloc(mem_glob, sizeof(*ref),
3828c2ecf20Sopenharmony_ci					   &ctx);
3838c2ecf20Sopenharmony_ci		if (unlikely(ret != 0))
3848c2ecf20Sopenharmony_ci			return ret;
3858c2ecf20Sopenharmony_ci		ref = kmalloc(sizeof(*ref), GFP_KERNEL);
3868c2ecf20Sopenharmony_ci		if (unlikely(ref == NULL)) {
3878c2ecf20Sopenharmony_ci			ttm_mem_global_free(mem_glob, sizeof(*ref));
3888c2ecf20Sopenharmony_ci			return -ENOMEM;
3898c2ecf20Sopenharmony_ci		}
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci		ref->hash.key = base->handle;
3928c2ecf20Sopenharmony_ci		ref->obj = base;
3938c2ecf20Sopenharmony_ci		ref->tfile = tfile;
3948c2ecf20Sopenharmony_ci		ref->ref_type = ref_type;
3958c2ecf20Sopenharmony_ci		kref_init(&ref->kref);
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ci		spin_lock(&tfile->lock);
3988c2ecf20Sopenharmony_ci		ret = drm_ht_insert_item_rcu(ht, &ref->hash);
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_ci		if (likely(ret == 0)) {
4018c2ecf20Sopenharmony_ci			list_add_tail(&ref->head, &tfile->ref_list);
4028c2ecf20Sopenharmony_ci			kref_get(&base->refcount);
4038c2ecf20Sopenharmony_ci			spin_unlock(&tfile->lock);
4048c2ecf20Sopenharmony_ci			if (existed != NULL)
4058c2ecf20Sopenharmony_ci				*existed = false;
4068c2ecf20Sopenharmony_ci			break;
4078c2ecf20Sopenharmony_ci		}
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci		spin_unlock(&tfile->lock);
4108c2ecf20Sopenharmony_ci		BUG_ON(ret != -EINVAL);
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci		ttm_mem_global_free(mem_glob, sizeof(*ref));
4138c2ecf20Sopenharmony_ci		kfree(ref);
4148c2ecf20Sopenharmony_ci	}
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_ci	return ret;
4178c2ecf20Sopenharmony_ci}
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_cistatic void __releases(tfile->lock) __acquires(tfile->lock)
4208c2ecf20Sopenharmony_cittm_ref_object_release(struct kref *kref)
4218c2ecf20Sopenharmony_ci{
4228c2ecf20Sopenharmony_ci	struct ttm_ref_object *ref =
4238c2ecf20Sopenharmony_ci	    container_of(kref, struct ttm_ref_object, kref);
4248c2ecf20Sopenharmony_ci	struct ttm_base_object *base = ref->obj;
4258c2ecf20Sopenharmony_ci	struct ttm_object_file *tfile = ref->tfile;
4268c2ecf20Sopenharmony_ci	struct drm_open_hash *ht;
4278c2ecf20Sopenharmony_ci	struct ttm_mem_global *mem_glob = tfile->tdev->mem_glob;
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_ci	ht = &tfile->ref_hash[ref->ref_type];
4308c2ecf20Sopenharmony_ci	(void)drm_ht_remove_item_rcu(ht, &ref->hash);
4318c2ecf20Sopenharmony_ci	list_del(&ref->head);
4328c2ecf20Sopenharmony_ci	spin_unlock(&tfile->lock);
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci	if (ref->ref_type != TTM_REF_USAGE && base->ref_obj_release)
4358c2ecf20Sopenharmony_ci		base->ref_obj_release(base, ref->ref_type);
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ci	ttm_base_object_unref(&ref->obj);
4388c2ecf20Sopenharmony_ci	ttm_mem_global_free(mem_glob, sizeof(*ref));
4398c2ecf20Sopenharmony_ci	kfree_rcu(ref, rcu_head);
4408c2ecf20Sopenharmony_ci	spin_lock(&tfile->lock);
4418c2ecf20Sopenharmony_ci}
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_ciint ttm_ref_object_base_unref(struct ttm_object_file *tfile,
4448c2ecf20Sopenharmony_ci			      unsigned long key, enum ttm_ref_type ref_type)
4458c2ecf20Sopenharmony_ci{
4468c2ecf20Sopenharmony_ci	struct drm_open_hash *ht = &tfile->ref_hash[ref_type];
4478c2ecf20Sopenharmony_ci	struct ttm_ref_object *ref;
4488c2ecf20Sopenharmony_ci	struct drm_hash_item *hash;
4498c2ecf20Sopenharmony_ci	int ret;
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ci	spin_lock(&tfile->lock);
4528c2ecf20Sopenharmony_ci	ret = drm_ht_find_item(ht, key, &hash);
4538c2ecf20Sopenharmony_ci	if (unlikely(ret != 0)) {
4548c2ecf20Sopenharmony_ci		spin_unlock(&tfile->lock);
4558c2ecf20Sopenharmony_ci		return -EINVAL;
4568c2ecf20Sopenharmony_ci	}
4578c2ecf20Sopenharmony_ci	ref = drm_hash_entry(hash, struct ttm_ref_object, hash);
4588c2ecf20Sopenharmony_ci	kref_put(&ref->kref, ttm_ref_object_release);
4598c2ecf20Sopenharmony_ci	spin_unlock(&tfile->lock);
4608c2ecf20Sopenharmony_ci	return 0;
4618c2ecf20Sopenharmony_ci}
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_civoid ttm_object_file_release(struct ttm_object_file **p_tfile)
4648c2ecf20Sopenharmony_ci{
4658c2ecf20Sopenharmony_ci	struct ttm_ref_object *ref;
4668c2ecf20Sopenharmony_ci	struct list_head *list;
4678c2ecf20Sopenharmony_ci	unsigned int i;
4688c2ecf20Sopenharmony_ci	struct ttm_object_file *tfile = *p_tfile;
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_ci	*p_tfile = NULL;
4718c2ecf20Sopenharmony_ci	spin_lock(&tfile->lock);
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_ci	/*
4748c2ecf20Sopenharmony_ci	 * Since we release the lock within the loop, we have to
4758c2ecf20Sopenharmony_ci	 * restart it from the beginning each time.
4768c2ecf20Sopenharmony_ci	 */
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_ci	while (!list_empty(&tfile->ref_list)) {
4798c2ecf20Sopenharmony_ci		list = tfile->ref_list.next;
4808c2ecf20Sopenharmony_ci		ref = list_entry(list, struct ttm_ref_object, head);
4818c2ecf20Sopenharmony_ci		ttm_ref_object_release(&ref->kref);
4828c2ecf20Sopenharmony_ci	}
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_ci	spin_unlock(&tfile->lock);
4858c2ecf20Sopenharmony_ci	for (i = 0; i < TTM_REF_NUM; ++i)
4868c2ecf20Sopenharmony_ci		drm_ht_remove(&tfile->ref_hash[i]);
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_ci	ttm_object_file_unref(&tfile);
4898c2ecf20Sopenharmony_ci}
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_cistruct ttm_object_file *ttm_object_file_init(struct ttm_object_device *tdev,
4928c2ecf20Sopenharmony_ci					     unsigned int hash_order)
4938c2ecf20Sopenharmony_ci{
4948c2ecf20Sopenharmony_ci	struct ttm_object_file *tfile = kmalloc(sizeof(*tfile), GFP_KERNEL);
4958c2ecf20Sopenharmony_ci	unsigned int i;
4968c2ecf20Sopenharmony_ci	unsigned int j = 0;
4978c2ecf20Sopenharmony_ci	int ret;
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ci	if (unlikely(tfile == NULL))
5008c2ecf20Sopenharmony_ci		return NULL;
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_ci	spin_lock_init(&tfile->lock);
5038c2ecf20Sopenharmony_ci	tfile->tdev = tdev;
5048c2ecf20Sopenharmony_ci	kref_init(&tfile->refcount);
5058c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&tfile->ref_list);
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_ci	for (i = 0; i < TTM_REF_NUM; ++i) {
5088c2ecf20Sopenharmony_ci		ret = drm_ht_create(&tfile->ref_hash[i], hash_order);
5098c2ecf20Sopenharmony_ci		if (ret) {
5108c2ecf20Sopenharmony_ci			j = i;
5118c2ecf20Sopenharmony_ci			goto out_err;
5128c2ecf20Sopenharmony_ci		}
5138c2ecf20Sopenharmony_ci	}
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_ci	return tfile;
5168c2ecf20Sopenharmony_ciout_err:
5178c2ecf20Sopenharmony_ci	for (i = 0; i < j; ++i)
5188c2ecf20Sopenharmony_ci		drm_ht_remove(&tfile->ref_hash[i]);
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_ci	kfree(tfile);
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_ci	return NULL;
5238c2ecf20Sopenharmony_ci}
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_cistruct ttm_object_device *
5268c2ecf20Sopenharmony_cittm_object_device_init(struct ttm_mem_global *mem_glob,
5278c2ecf20Sopenharmony_ci		       unsigned int hash_order,
5288c2ecf20Sopenharmony_ci		       const struct dma_buf_ops *ops)
5298c2ecf20Sopenharmony_ci{
5308c2ecf20Sopenharmony_ci	struct ttm_object_device *tdev = kmalloc(sizeof(*tdev), GFP_KERNEL);
5318c2ecf20Sopenharmony_ci	int ret;
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_ci	if (unlikely(tdev == NULL))
5348c2ecf20Sopenharmony_ci		return NULL;
5358c2ecf20Sopenharmony_ci
5368c2ecf20Sopenharmony_ci	tdev->mem_glob = mem_glob;
5378c2ecf20Sopenharmony_ci	spin_lock_init(&tdev->object_lock);
5388c2ecf20Sopenharmony_ci	atomic_set(&tdev->object_count, 0);
5398c2ecf20Sopenharmony_ci	ret = drm_ht_create(&tdev->object_hash, hash_order);
5408c2ecf20Sopenharmony_ci	if (ret != 0)
5418c2ecf20Sopenharmony_ci		goto out_no_object_hash;
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ci	idr_init(&tdev->idr);
5448c2ecf20Sopenharmony_ci	tdev->ops = *ops;
5458c2ecf20Sopenharmony_ci	tdev->dmabuf_release = tdev->ops.release;
5468c2ecf20Sopenharmony_ci	tdev->ops.release = ttm_prime_dmabuf_release;
5478c2ecf20Sopenharmony_ci	tdev->dma_buf_size = ttm_round_pot(sizeof(struct dma_buf)) +
5488c2ecf20Sopenharmony_ci		ttm_round_pot(sizeof(struct file));
5498c2ecf20Sopenharmony_ci	return tdev;
5508c2ecf20Sopenharmony_ci
5518c2ecf20Sopenharmony_ciout_no_object_hash:
5528c2ecf20Sopenharmony_ci	kfree(tdev);
5538c2ecf20Sopenharmony_ci	return NULL;
5548c2ecf20Sopenharmony_ci}
5558c2ecf20Sopenharmony_ci
5568c2ecf20Sopenharmony_civoid ttm_object_device_release(struct ttm_object_device **p_tdev)
5578c2ecf20Sopenharmony_ci{
5588c2ecf20Sopenharmony_ci	struct ttm_object_device *tdev = *p_tdev;
5598c2ecf20Sopenharmony_ci
5608c2ecf20Sopenharmony_ci	*p_tdev = NULL;
5618c2ecf20Sopenharmony_ci
5628c2ecf20Sopenharmony_ci	WARN_ON_ONCE(!idr_is_empty(&tdev->idr));
5638c2ecf20Sopenharmony_ci	idr_destroy(&tdev->idr);
5648c2ecf20Sopenharmony_ci	drm_ht_remove(&tdev->object_hash);
5658c2ecf20Sopenharmony_ci
5668c2ecf20Sopenharmony_ci	kfree(tdev);
5678c2ecf20Sopenharmony_ci}
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_ci/**
5708c2ecf20Sopenharmony_ci * get_dma_buf_unless_doomed - get a dma_buf reference if possible.
5718c2ecf20Sopenharmony_ci *
5728c2ecf20Sopenharmony_ci * @dma_buf: Non-refcounted pointer to a struct dma-buf.
5738c2ecf20Sopenharmony_ci *
5748c2ecf20Sopenharmony_ci * Obtain a file reference from a lookup structure that doesn't refcount
5758c2ecf20Sopenharmony_ci * the file, but synchronizes with its release method to make sure it has
5768c2ecf20Sopenharmony_ci * not been freed yet. See for example kref_get_unless_zero documentation.
5778c2ecf20Sopenharmony_ci * Returns true if refcounting succeeds, false otherwise.
5788c2ecf20Sopenharmony_ci *
5798c2ecf20Sopenharmony_ci * Nobody really wants this as a public API yet, so let it mature here
5808c2ecf20Sopenharmony_ci * for some time...
5818c2ecf20Sopenharmony_ci */
5828c2ecf20Sopenharmony_cistatic bool __must_check get_dma_buf_unless_doomed(struct dma_buf *dmabuf)
5838c2ecf20Sopenharmony_ci{
5848c2ecf20Sopenharmony_ci	return atomic_long_inc_not_zero(&dmabuf->file->f_count) != 0L;
5858c2ecf20Sopenharmony_ci}
5868c2ecf20Sopenharmony_ci
5878c2ecf20Sopenharmony_ci/**
5888c2ecf20Sopenharmony_ci * ttm_prime_refcount_release - refcount release method for a prime object.
5898c2ecf20Sopenharmony_ci *
5908c2ecf20Sopenharmony_ci * @p_base: Pointer to ttm_base_object pointer.
5918c2ecf20Sopenharmony_ci *
5928c2ecf20Sopenharmony_ci * This is a wrapper that calls the refcount_release founction of the
5938c2ecf20Sopenharmony_ci * underlying object. At the same time it cleans up the prime object.
5948c2ecf20Sopenharmony_ci * This function is called when all references to the base object we
5958c2ecf20Sopenharmony_ci * derive from are gone.
5968c2ecf20Sopenharmony_ci */
5978c2ecf20Sopenharmony_cistatic void ttm_prime_refcount_release(struct ttm_base_object **p_base)
5988c2ecf20Sopenharmony_ci{
5998c2ecf20Sopenharmony_ci	struct ttm_base_object *base = *p_base;
6008c2ecf20Sopenharmony_ci	struct ttm_prime_object *prime;
6018c2ecf20Sopenharmony_ci
6028c2ecf20Sopenharmony_ci	*p_base = NULL;
6038c2ecf20Sopenharmony_ci	prime = container_of(base, struct ttm_prime_object, base);
6048c2ecf20Sopenharmony_ci	BUG_ON(prime->dma_buf != NULL);
6058c2ecf20Sopenharmony_ci	mutex_destroy(&prime->mutex);
6068c2ecf20Sopenharmony_ci	if (prime->refcount_release)
6078c2ecf20Sopenharmony_ci		prime->refcount_release(&base);
6088c2ecf20Sopenharmony_ci}
6098c2ecf20Sopenharmony_ci
6108c2ecf20Sopenharmony_ci/**
6118c2ecf20Sopenharmony_ci * ttm_prime_dmabuf_release - Release method for the dma-bufs we export
6128c2ecf20Sopenharmony_ci *
6138c2ecf20Sopenharmony_ci * @dma_buf:
6148c2ecf20Sopenharmony_ci *
6158c2ecf20Sopenharmony_ci * This function first calls the dma_buf release method the driver
6168c2ecf20Sopenharmony_ci * provides. Then it cleans up our dma_buf pointer used for lookup,
6178c2ecf20Sopenharmony_ci * and finally releases the reference the dma_buf has on our base
6188c2ecf20Sopenharmony_ci * object.
6198c2ecf20Sopenharmony_ci */
6208c2ecf20Sopenharmony_cistatic void ttm_prime_dmabuf_release(struct dma_buf *dma_buf)
6218c2ecf20Sopenharmony_ci{
6228c2ecf20Sopenharmony_ci	struct ttm_prime_object *prime =
6238c2ecf20Sopenharmony_ci		(struct ttm_prime_object *) dma_buf->priv;
6248c2ecf20Sopenharmony_ci	struct ttm_base_object *base = &prime->base;
6258c2ecf20Sopenharmony_ci	struct ttm_object_device *tdev = base->tfile->tdev;
6268c2ecf20Sopenharmony_ci
6278c2ecf20Sopenharmony_ci	if (tdev->dmabuf_release)
6288c2ecf20Sopenharmony_ci		tdev->dmabuf_release(dma_buf);
6298c2ecf20Sopenharmony_ci	mutex_lock(&prime->mutex);
6308c2ecf20Sopenharmony_ci	if (prime->dma_buf == dma_buf)
6318c2ecf20Sopenharmony_ci		prime->dma_buf = NULL;
6328c2ecf20Sopenharmony_ci	mutex_unlock(&prime->mutex);
6338c2ecf20Sopenharmony_ci	ttm_mem_global_free(tdev->mem_glob, tdev->dma_buf_size);
6348c2ecf20Sopenharmony_ci	ttm_base_object_unref(&base);
6358c2ecf20Sopenharmony_ci}
6368c2ecf20Sopenharmony_ci
6378c2ecf20Sopenharmony_ci/**
6388c2ecf20Sopenharmony_ci * ttm_prime_fd_to_handle - Get a base object handle from a prime fd
6398c2ecf20Sopenharmony_ci *
6408c2ecf20Sopenharmony_ci * @tfile: A struct ttm_object_file identifying the caller.
6418c2ecf20Sopenharmony_ci * @fd: The prime / dmabuf fd.
6428c2ecf20Sopenharmony_ci * @handle: The returned handle.
6438c2ecf20Sopenharmony_ci *
6448c2ecf20Sopenharmony_ci * This function returns a handle to an object that previously exported
6458c2ecf20Sopenharmony_ci * a dma-buf. Note that we don't handle imports yet, because we simply
6468c2ecf20Sopenharmony_ci * have no consumers of that implementation.
6478c2ecf20Sopenharmony_ci */
6488c2ecf20Sopenharmony_ciint ttm_prime_fd_to_handle(struct ttm_object_file *tfile,
6498c2ecf20Sopenharmony_ci			   int fd, u32 *handle)
6508c2ecf20Sopenharmony_ci{
6518c2ecf20Sopenharmony_ci	struct ttm_object_device *tdev = tfile->tdev;
6528c2ecf20Sopenharmony_ci	struct dma_buf *dma_buf;
6538c2ecf20Sopenharmony_ci	struct ttm_prime_object *prime;
6548c2ecf20Sopenharmony_ci	struct ttm_base_object *base;
6558c2ecf20Sopenharmony_ci	int ret;
6568c2ecf20Sopenharmony_ci
6578c2ecf20Sopenharmony_ci	dma_buf = dma_buf_get(fd);
6588c2ecf20Sopenharmony_ci	if (IS_ERR(dma_buf))
6598c2ecf20Sopenharmony_ci		return PTR_ERR(dma_buf);
6608c2ecf20Sopenharmony_ci
6618c2ecf20Sopenharmony_ci	if (dma_buf->ops != &tdev->ops)
6628c2ecf20Sopenharmony_ci		return -ENOSYS;
6638c2ecf20Sopenharmony_ci
6648c2ecf20Sopenharmony_ci	prime = (struct ttm_prime_object *) dma_buf->priv;
6658c2ecf20Sopenharmony_ci	base = &prime->base;
6668c2ecf20Sopenharmony_ci	*handle = base->handle;
6678c2ecf20Sopenharmony_ci	ret = ttm_ref_object_add(tfile, base, TTM_REF_USAGE, NULL, false);
6688c2ecf20Sopenharmony_ci
6698c2ecf20Sopenharmony_ci	dma_buf_put(dma_buf);
6708c2ecf20Sopenharmony_ci
6718c2ecf20Sopenharmony_ci	return ret;
6728c2ecf20Sopenharmony_ci}
6738c2ecf20Sopenharmony_ci
6748c2ecf20Sopenharmony_ci/**
6758c2ecf20Sopenharmony_ci * ttm_prime_handle_to_fd - Return a dma_buf fd from a ttm prime object
6768c2ecf20Sopenharmony_ci *
6778c2ecf20Sopenharmony_ci * @tfile: Struct ttm_object_file identifying the caller.
6788c2ecf20Sopenharmony_ci * @handle: Handle to the object we're exporting from.
6798c2ecf20Sopenharmony_ci * @flags: flags for dma-buf creation. We just pass them on.
6808c2ecf20Sopenharmony_ci * @prime_fd: The returned file descriptor.
6818c2ecf20Sopenharmony_ci *
6828c2ecf20Sopenharmony_ci */
6838c2ecf20Sopenharmony_ciint ttm_prime_handle_to_fd(struct ttm_object_file *tfile,
6848c2ecf20Sopenharmony_ci			   uint32_t handle, uint32_t flags,
6858c2ecf20Sopenharmony_ci			   int *prime_fd)
6868c2ecf20Sopenharmony_ci{
6878c2ecf20Sopenharmony_ci	struct ttm_object_device *tdev = tfile->tdev;
6888c2ecf20Sopenharmony_ci	struct ttm_base_object *base;
6898c2ecf20Sopenharmony_ci	struct dma_buf *dma_buf;
6908c2ecf20Sopenharmony_ci	struct ttm_prime_object *prime;
6918c2ecf20Sopenharmony_ci	int ret;
6928c2ecf20Sopenharmony_ci
6938c2ecf20Sopenharmony_ci	base = ttm_base_object_lookup(tfile, handle);
6948c2ecf20Sopenharmony_ci	if (unlikely(base == NULL ||
6958c2ecf20Sopenharmony_ci		     base->object_type != ttm_prime_type)) {
6968c2ecf20Sopenharmony_ci		ret = -ENOENT;
6978c2ecf20Sopenharmony_ci		goto out_unref;
6988c2ecf20Sopenharmony_ci	}
6998c2ecf20Sopenharmony_ci
7008c2ecf20Sopenharmony_ci	prime = container_of(base, struct ttm_prime_object, base);
7018c2ecf20Sopenharmony_ci	if (unlikely(!base->shareable)) {
7028c2ecf20Sopenharmony_ci		ret = -EPERM;
7038c2ecf20Sopenharmony_ci		goto out_unref;
7048c2ecf20Sopenharmony_ci	}
7058c2ecf20Sopenharmony_ci
7068c2ecf20Sopenharmony_ci	ret = mutex_lock_interruptible(&prime->mutex);
7078c2ecf20Sopenharmony_ci	if (unlikely(ret != 0)) {
7088c2ecf20Sopenharmony_ci		ret = -ERESTARTSYS;
7098c2ecf20Sopenharmony_ci		goto out_unref;
7108c2ecf20Sopenharmony_ci	}
7118c2ecf20Sopenharmony_ci
7128c2ecf20Sopenharmony_ci	dma_buf = prime->dma_buf;
7138c2ecf20Sopenharmony_ci	if (!dma_buf || !get_dma_buf_unless_doomed(dma_buf)) {
7148c2ecf20Sopenharmony_ci		DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
7158c2ecf20Sopenharmony_ci		struct ttm_operation_ctx ctx = {
7168c2ecf20Sopenharmony_ci			.interruptible = true,
7178c2ecf20Sopenharmony_ci			.no_wait_gpu = false
7188c2ecf20Sopenharmony_ci		};
7198c2ecf20Sopenharmony_ci		exp_info.ops = &tdev->ops;
7208c2ecf20Sopenharmony_ci		exp_info.size = prime->size;
7218c2ecf20Sopenharmony_ci		exp_info.flags = flags;
7228c2ecf20Sopenharmony_ci		exp_info.priv = prime;
7238c2ecf20Sopenharmony_ci
7248c2ecf20Sopenharmony_ci		/*
7258c2ecf20Sopenharmony_ci		 * Need to create a new dma_buf, with memory accounting.
7268c2ecf20Sopenharmony_ci		 */
7278c2ecf20Sopenharmony_ci		ret = ttm_mem_global_alloc(tdev->mem_glob, tdev->dma_buf_size,
7288c2ecf20Sopenharmony_ci					   &ctx);
7298c2ecf20Sopenharmony_ci		if (unlikely(ret != 0)) {
7308c2ecf20Sopenharmony_ci			mutex_unlock(&prime->mutex);
7318c2ecf20Sopenharmony_ci			goto out_unref;
7328c2ecf20Sopenharmony_ci		}
7338c2ecf20Sopenharmony_ci
7348c2ecf20Sopenharmony_ci		dma_buf = dma_buf_export(&exp_info);
7358c2ecf20Sopenharmony_ci		if (IS_ERR(dma_buf)) {
7368c2ecf20Sopenharmony_ci			ret = PTR_ERR(dma_buf);
7378c2ecf20Sopenharmony_ci			ttm_mem_global_free(tdev->mem_glob,
7388c2ecf20Sopenharmony_ci					    tdev->dma_buf_size);
7398c2ecf20Sopenharmony_ci			mutex_unlock(&prime->mutex);
7408c2ecf20Sopenharmony_ci			goto out_unref;
7418c2ecf20Sopenharmony_ci		}
7428c2ecf20Sopenharmony_ci
7438c2ecf20Sopenharmony_ci		/*
7448c2ecf20Sopenharmony_ci		 * dma_buf has taken the base object reference
7458c2ecf20Sopenharmony_ci		 */
7468c2ecf20Sopenharmony_ci		base = NULL;
7478c2ecf20Sopenharmony_ci		prime->dma_buf = dma_buf;
7488c2ecf20Sopenharmony_ci	}
7498c2ecf20Sopenharmony_ci	mutex_unlock(&prime->mutex);
7508c2ecf20Sopenharmony_ci
7518c2ecf20Sopenharmony_ci	ret = dma_buf_fd(dma_buf, flags);
7528c2ecf20Sopenharmony_ci	if (ret >= 0) {
7538c2ecf20Sopenharmony_ci		*prime_fd = ret;
7548c2ecf20Sopenharmony_ci		ret = 0;
7558c2ecf20Sopenharmony_ci	} else
7568c2ecf20Sopenharmony_ci		dma_buf_put(dma_buf);
7578c2ecf20Sopenharmony_ci
7588c2ecf20Sopenharmony_ciout_unref:
7598c2ecf20Sopenharmony_ci	if (base)
7608c2ecf20Sopenharmony_ci		ttm_base_object_unref(&base);
7618c2ecf20Sopenharmony_ci	return ret;
7628c2ecf20Sopenharmony_ci}
7638c2ecf20Sopenharmony_ci
7648c2ecf20Sopenharmony_ci/**
7658c2ecf20Sopenharmony_ci * ttm_prime_object_init - Initialize a ttm_prime_object
7668c2ecf20Sopenharmony_ci *
7678c2ecf20Sopenharmony_ci * @tfile: struct ttm_object_file identifying the caller
7688c2ecf20Sopenharmony_ci * @size: The size of the dma_bufs we export.
7698c2ecf20Sopenharmony_ci * @prime: The object to be initialized.
7708c2ecf20Sopenharmony_ci * @shareable: See ttm_base_object_init
7718c2ecf20Sopenharmony_ci * @type: See ttm_base_object_init
7728c2ecf20Sopenharmony_ci * @refcount_release: See ttm_base_object_init
7738c2ecf20Sopenharmony_ci * @ref_obj_release: See ttm_base_object_init
7748c2ecf20Sopenharmony_ci *
7758c2ecf20Sopenharmony_ci * Initializes an object which is compatible with the drm_prime model
7768c2ecf20Sopenharmony_ci * for data sharing between processes and devices.
7778c2ecf20Sopenharmony_ci */
7788c2ecf20Sopenharmony_ciint ttm_prime_object_init(struct ttm_object_file *tfile, size_t size,
7798c2ecf20Sopenharmony_ci			  struct ttm_prime_object *prime, bool shareable,
7808c2ecf20Sopenharmony_ci			  enum ttm_object_type type,
7818c2ecf20Sopenharmony_ci			  void (*refcount_release) (struct ttm_base_object **),
7828c2ecf20Sopenharmony_ci			  void (*ref_obj_release) (struct ttm_base_object *,
7838c2ecf20Sopenharmony_ci						   enum ttm_ref_type ref_type))
7848c2ecf20Sopenharmony_ci{
7858c2ecf20Sopenharmony_ci	mutex_init(&prime->mutex);
7868c2ecf20Sopenharmony_ci	prime->size = PAGE_ALIGN(size);
7878c2ecf20Sopenharmony_ci	prime->real_type = type;
7888c2ecf20Sopenharmony_ci	prime->dma_buf = NULL;
7898c2ecf20Sopenharmony_ci	prime->refcount_release = refcount_release;
7908c2ecf20Sopenharmony_ci	return ttm_base_object_init(tfile, &prime->base, shareable,
7918c2ecf20Sopenharmony_ci				    ttm_prime_type,
7928c2ecf20Sopenharmony_ci				    ttm_prime_refcount_release,
7938c2ecf20Sopenharmony_ci				    ref_obj_release);
7948c2ecf20Sopenharmony_ci}
795