10b8762e9SThomas Hellstrom /* SPDX-License-Identifier: GPL-2.0 OR MIT */ 20b8762e9SThomas Hellstrom /************************************************************************** 30b8762e9SThomas Hellstrom * 40b8762e9SThomas Hellstrom * Copyright (c) 2009-2013 VMware, Inc., Palo Alto, CA., USA 50b8762e9SThomas Hellstrom * All Rights Reserved. 60b8762e9SThomas Hellstrom * 70b8762e9SThomas Hellstrom * Permission is hereby granted, free of charge, to any person obtaining a 80b8762e9SThomas Hellstrom * copy of this software and associated documentation files (the 90b8762e9SThomas Hellstrom * "Software"), to deal in the Software without restriction, including 100b8762e9SThomas Hellstrom * without limitation the rights to use, copy, modify, merge, publish, 110b8762e9SThomas Hellstrom * distribute, sub license, and/or sell copies of the Software, and to 120b8762e9SThomas Hellstrom * permit persons to whom the Software is furnished to do so, subject to 130b8762e9SThomas Hellstrom * the following conditions: 140b8762e9SThomas Hellstrom * 150b8762e9SThomas Hellstrom * The above copyright notice and this permission notice (including the 160b8762e9SThomas Hellstrom * next paragraph) shall be included in all copies or substantial portions 170b8762e9SThomas Hellstrom * of the Software. 180b8762e9SThomas Hellstrom * 190b8762e9SThomas Hellstrom * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 200b8762e9SThomas Hellstrom * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 210b8762e9SThomas Hellstrom * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 220b8762e9SThomas Hellstrom * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 230b8762e9SThomas Hellstrom * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 240b8762e9SThomas Hellstrom * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 250b8762e9SThomas Hellstrom * USE OR OTHER DEALINGS IN THE SOFTWARE. 260b8762e9SThomas Hellstrom * 270b8762e9SThomas Hellstrom **************************************************************************/ 280b8762e9SThomas Hellstrom /* 290b8762e9SThomas Hellstrom * Authors: Thomas Hellstrom <thellstrom-at-vmware-dot-com> 300b8762e9SThomas Hellstrom * 310b8762e9SThomas Hellstrom * While no substantial code is shared, the prime code is inspired by 320b8762e9SThomas Hellstrom * drm_prime.c, with 330b8762e9SThomas Hellstrom * Authors: 340b8762e9SThomas Hellstrom * Dave Airlie <airlied@redhat.com> 350b8762e9SThomas Hellstrom * Rob Clark <rob.clark@linaro.org> 360b8762e9SThomas Hellstrom */ 370b8762e9SThomas Hellstrom /** @file ttm_ref_object.c 380b8762e9SThomas Hellstrom * 390b8762e9SThomas Hellstrom * Base- and reference object implementation for the various 400b8762e9SThomas Hellstrom * ttm objects. Implements reference counting, minimal security checks 410b8762e9SThomas Hellstrom * and release on file close. 420b8762e9SThomas Hellstrom */ 430b8762e9SThomas Hellstrom 440b8762e9SThomas Hellstrom 45d1441394SLee Jones #define pr_fmt(fmt) "[TTM] " fmt 46d1441394SLee Jones 47d1441394SLee Jones #include <linux/list.h> 48d1441394SLee Jones #include <linux/spinlock.h> 49d1441394SLee Jones #include <linux/slab.h> 50d1441394SLee Jones #include <linux/atomic.h> 5116b0314aSGreg Kroah-Hartman #include <linux/module.h> 52d1441394SLee Jones #include "ttm_object.h" 53d1441394SLee Jones 5416b0314aSGreg Kroah-Hartman MODULE_IMPORT_NS(DMA_BUF); 5516b0314aSGreg Kroah-Hartman 560b8762e9SThomas Hellstrom /** 570b8762e9SThomas Hellstrom * struct ttm_object_file 580b8762e9SThomas Hellstrom * 590b8762e9SThomas Hellstrom * @tdev: Pointer to the ttm_object_device. 600b8762e9SThomas Hellstrom * 610b8762e9SThomas Hellstrom * @lock: Lock that protects the ref_list list and the 620b8762e9SThomas Hellstrom * ref_hash hash tables. 630b8762e9SThomas Hellstrom * 640b8762e9SThomas Hellstrom * @ref_list: List of ttm_ref_objects to be destroyed at 650b8762e9SThomas Hellstrom * file release. 660b8762e9SThomas Hellstrom * 670b8762e9SThomas Hellstrom * @ref_hash: Hash tables of ref objects, one per ttm_ref_type, 680b8762e9SThomas Hellstrom * for fast lookup of ref objects given a base object. 69d1441394SLee Jones * 70d1441394SLee Jones * @refcount: reference/usage count 710b8762e9SThomas Hellstrom */ 720b8762e9SThomas Hellstrom struct ttm_object_file { 730b8762e9SThomas Hellstrom struct ttm_object_device *tdev; 740b8762e9SThomas Hellstrom spinlock_t lock; 750b8762e9SThomas Hellstrom struct list_head ref_list; 762985c964SThomas Zimmermann struct vmwgfx_open_hash ref_hash[TTM_REF_NUM]; 770b8762e9SThomas Hellstrom struct kref refcount; 780b8762e9SThomas Hellstrom }; 790b8762e9SThomas Hellstrom 80f322f32aSLee Jones /* 810b8762e9SThomas Hellstrom * struct ttm_object_device 820b8762e9SThomas Hellstrom * 830b8762e9SThomas Hellstrom * @object_lock: lock that protects the object_hash hash table. 840b8762e9SThomas Hellstrom * 850b8762e9SThomas Hellstrom * @object_hash: hash table for fast lookup of object global names. 860b8762e9SThomas Hellstrom * 870b8762e9SThomas Hellstrom * @object_count: Per device object count. 880b8762e9SThomas Hellstrom * 890b8762e9SThomas Hellstrom * This is the per-device data structure needed for ttm object management. 900b8762e9SThomas Hellstrom */ 910b8762e9SThomas Hellstrom 920b8762e9SThomas Hellstrom struct ttm_object_device { 930b8762e9SThomas Hellstrom spinlock_t object_lock; 942985c964SThomas Zimmermann struct vmwgfx_open_hash object_hash; 950b8762e9SThomas Hellstrom atomic_t object_count; 960b8762e9SThomas Hellstrom struct dma_buf_ops ops; 970b8762e9SThomas Hellstrom void (*dmabuf_release)(struct dma_buf *dma_buf); 98c7eae626SThomas Hellstrom struct idr idr; 990b8762e9SThomas Hellstrom }; 1000b8762e9SThomas Hellstrom 101f322f32aSLee Jones /* 1020b8762e9SThomas Hellstrom * struct ttm_ref_object 1030b8762e9SThomas Hellstrom * 1040b8762e9SThomas Hellstrom * @hash: Hash entry for the per-file object reference hash. 1050b8762e9SThomas Hellstrom * 1060b8762e9SThomas Hellstrom * @head: List entry for the per-file list of ref-objects. 1070b8762e9SThomas Hellstrom * 1080b8762e9SThomas Hellstrom * @kref: Ref count. 1090b8762e9SThomas Hellstrom * 1100b8762e9SThomas Hellstrom * @obj: Base object this ref object is referencing. 1110b8762e9SThomas Hellstrom * 1120b8762e9SThomas Hellstrom * @ref_type: Type of ref object. 1130b8762e9SThomas Hellstrom * 1140b8762e9SThomas Hellstrom * This is similar to an idr object, but it also has a hash table entry 1150b8762e9SThomas Hellstrom * that allows lookup with a pointer to the referenced object as a key. In 1160b8762e9SThomas Hellstrom * that way, one can easily detect whether a base object is referenced by 1170b8762e9SThomas Hellstrom * a particular ttm_object_file. It also carries a ref count to avoid creating 1180b8762e9SThomas Hellstrom * multiple ref objects if a ttm_object_file references the same base 1190b8762e9SThomas Hellstrom * object more than once. 1200b8762e9SThomas Hellstrom */ 1210b8762e9SThomas Hellstrom 1220b8762e9SThomas Hellstrom struct ttm_ref_object { 1230b8762e9SThomas Hellstrom struct rcu_head rcu_head; 1242985c964SThomas Zimmermann struct vmwgfx_hash_item hash; 1250b8762e9SThomas Hellstrom struct list_head head; 1260b8762e9SThomas Hellstrom struct kref kref; 1270b8762e9SThomas Hellstrom enum ttm_ref_type ref_type; 1280b8762e9SThomas Hellstrom struct ttm_base_object *obj; 1290b8762e9SThomas Hellstrom struct ttm_object_file *tfile; 1300b8762e9SThomas Hellstrom }; 1310b8762e9SThomas Hellstrom 1320b8762e9SThomas Hellstrom static void ttm_prime_dmabuf_release(struct dma_buf *dma_buf); 1330b8762e9SThomas Hellstrom 1340b8762e9SThomas Hellstrom static inline struct ttm_object_file * 1350b8762e9SThomas Hellstrom ttm_object_file_ref(struct ttm_object_file *tfile) 1360b8762e9SThomas Hellstrom { 1370b8762e9SThomas Hellstrom kref_get(&tfile->refcount); 1380b8762e9SThomas Hellstrom return tfile; 1390b8762e9SThomas Hellstrom } 1400b8762e9SThomas Hellstrom 1410b8762e9SThomas Hellstrom static void ttm_object_file_destroy(struct kref *kref) 1420b8762e9SThomas Hellstrom { 1430b8762e9SThomas Hellstrom struct ttm_object_file *tfile = 1440b8762e9SThomas Hellstrom container_of(kref, struct ttm_object_file, refcount); 1450b8762e9SThomas Hellstrom 1460b8762e9SThomas Hellstrom kfree(tfile); 1470b8762e9SThomas Hellstrom } 1480b8762e9SThomas Hellstrom 1490b8762e9SThomas Hellstrom 1500b8762e9SThomas Hellstrom static inline void ttm_object_file_unref(struct ttm_object_file **p_tfile) 1510b8762e9SThomas Hellstrom { 1520b8762e9SThomas Hellstrom struct ttm_object_file *tfile = *p_tfile; 1530b8762e9SThomas Hellstrom 1540b8762e9SThomas Hellstrom *p_tfile = NULL; 1550b8762e9SThomas Hellstrom kref_put(&tfile->refcount, ttm_object_file_destroy); 1560b8762e9SThomas Hellstrom } 1570b8762e9SThomas Hellstrom 1580b8762e9SThomas Hellstrom 1590b8762e9SThomas Hellstrom int ttm_base_object_init(struct ttm_object_file *tfile, 1600b8762e9SThomas Hellstrom struct ttm_base_object *base, 1610b8762e9SThomas Hellstrom bool shareable, 1620b8762e9SThomas Hellstrom enum ttm_object_type object_type, 1630b8762e9SThomas Hellstrom void (*refcount_release) (struct ttm_base_object **), 1640b8762e9SThomas Hellstrom void (*ref_obj_release) (struct ttm_base_object *, 1650b8762e9SThomas Hellstrom enum ttm_ref_type ref_type)) 1660b8762e9SThomas Hellstrom { 1670b8762e9SThomas Hellstrom struct ttm_object_device *tdev = tfile->tdev; 1680b8762e9SThomas Hellstrom int ret; 1690b8762e9SThomas Hellstrom 1700b8762e9SThomas Hellstrom base->shareable = shareable; 1710b8762e9SThomas Hellstrom base->tfile = ttm_object_file_ref(tfile); 1720b8762e9SThomas Hellstrom base->refcount_release = refcount_release; 1730b8762e9SThomas Hellstrom base->ref_obj_release = ref_obj_release; 1740b8762e9SThomas Hellstrom base->object_type = object_type; 1750b8762e9SThomas Hellstrom kref_init(&base->refcount); 176c7eae626SThomas Hellstrom idr_preload(GFP_KERNEL); 1770b8762e9SThomas Hellstrom spin_lock(&tdev->object_lock); 1788407f8a1SThomas Hellstrom ret = idr_alloc(&tdev->idr, base, 1, 0, GFP_NOWAIT); 1790b8762e9SThomas Hellstrom spin_unlock(&tdev->object_lock); 180c7eae626SThomas Hellstrom idr_preload_end(); 181c7eae626SThomas Hellstrom if (ret < 0) 182c7eae626SThomas Hellstrom return ret; 1830b8762e9SThomas Hellstrom 184c7eae626SThomas Hellstrom base->handle = ret; 1850b8762e9SThomas Hellstrom ret = ttm_ref_object_add(tfile, base, TTM_REF_USAGE, NULL, false); 1860b8762e9SThomas Hellstrom if (unlikely(ret != 0)) 1870b8762e9SThomas Hellstrom goto out_err1; 1880b8762e9SThomas Hellstrom 1890b8762e9SThomas Hellstrom ttm_base_object_unref(&base); 1900b8762e9SThomas Hellstrom 1910b8762e9SThomas Hellstrom return 0; 1920b8762e9SThomas Hellstrom out_err1: 1930b8762e9SThomas Hellstrom spin_lock(&tdev->object_lock); 194c7eae626SThomas Hellstrom idr_remove(&tdev->idr, base->handle); 1950b8762e9SThomas Hellstrom spin_unlock(&tdev->object_lock); 1960b8762e9SThomas Hellstrom return ret; 1970b8762e9SThomas Hellstrom } 1980b8762e9SThomas Hellstrom 1990b8762e9SThomas Hellstrom static void ttm_release_base(struct kref *kref) 2000b8762e9SThomas Hellstrom { 2010b8762e9SThomas Hellstrom struct ttm_base_object *base = 2020b8762e9SThomas Hellstrom container_of(kref, struct ttm_base_object, refcount); 2030b8762e9SThomas Hellstrom struct ttm_object_device *tdev = base->tfile->tdev; 2040b8762e9SThomas Hellstrom 2050b8762e9SThomas Hellstrom spin_lock(&tdev->object_lock); 206c7eae626SThomas Hellstrom idr_remove(&tdev->idr, base->handle); 2070b8762e9SThomas Hellstrom spin_unlock(&tdev->object_lock); 2080b8762e9SThomas Hellstrom 2090b8762e9SThomas Hellstrom /* 2100b8762e9SThomas Hellstrom * Note: We don't use synchronize_rcu() here because it's far 2110b8762e9SThomas Hellstrom * too slow. It's up to the user to free the object using 2120b8762e9SThomas Hellstrom * call_rcu() or ttm_base_object_kfree(). 2130b8762e9SThomas Hellstrom */ 2140b8762e9SThomas Hellstrom 2150b8762e9SThomas Hellstrom ttm_object_file_unref(&base->tfile); 2160b8762e9SThomas Hellstrom if (base->refcount_release) 2170b8762e9SThomas Hellstrom base->refcount_release(&base); 2180b8762e9SThomas Hellstrom } 2190b8762e9SThomas Hellstrom 2200b8762e9SThomas Hellstrom void ttm_base_object_unref(struct ttm_base_object **p_base) 2210b8762e9SThomas Hellstrom { 2220b8762e9SThomas Hellstrom struct ttm_base_object *base = *p_base; 2230b8762e9SThomas Hellstrom 2240b8762e9SThomas Hellstrom *p_base = NULL; 2250b8762e9SThomas Hellstrom 2260b8762e9SThomas Hellstrom kref_put(&base->refcount, ttm_release_base); 2270b8762e9SThomas Hellstrom } 2280b8762e9SThomas Hellstrom 229e14c02e6SThomas Hellstrom /** 230e14c02e6SThomas Hellstrom * ttm_base_object_noref_lookup - look up a base object without reference 231e14c02e6SThomas Hellstrom * @tfile: The struct ttm_object_file the object is registered with. 232e14c02e6SThomas Hellstrom * @key: The object handle. 233e14c02e6SThomas Hellstrom * 234e14c02e6SThomas Hellstrom * This function looks up a ttm base object and returns a pointer to it 235e14c02e6SThomas Hellstrom * without refcounting the pointer. The returned pointer is only valid 236e14c02e6SThomas Hellstrom * until ttm_base_object_noref_release() is called, and the object 237e14c02e6SThomas Hellstrom * pointed to by the returned pointer may be doomed. Any persistent usage 238e14c02e6SThomas Hellstrom * of the object requires a refcount to be taken using kref_get_unless_zero(). 239e14c02e6SThomas Hellstrom * Iff this function returns successfully it needs to be paired with 240e14c02e6SThomas Hellstrom * ttm_base_object_noref_release() and no sleeping- or scheduling functions 241e14c02e6SThomas Hellstrom * may be called inbetween these function callse. 242e14c02e6SThomas Hellstrom * 243e14c02e6SThomas Hellstrom * Return: A pointer to the object if successful or NULL otherwise. 244e14c02e6SThomas Hellstrom */ 245e14c02e6SThomas Hellstrom struct ttm_base_object * 246e14c02e6SThomas Hellstrom ttm_base_object_noref_lookup(struct ttm_object_file *tfile, uint32_t key) 247e14c02e6SThomas Hellstrom { 2482985c964SThomas Zimmermann struct vmwgfx_hash_item *hash; 2492985c964SThomas Zimmermann struct vmwgfx_open_hash *ht = &tfile->ref_hash[TTM_REF_USAGE]; 250e14c02e6SThomas Hellstrom int ret; 251e14c02e6SThomas Hellstrom 252e14c02e6SThomas Hellstrom rcu_read_lock(); 2532985c964SThomas Zimmermann ret = vmwgfx_ht_find_item_rcu(ht, key, &hash); 254e14c02e6SThomas Hellstrom if (ret) { 255e14c02e6SThomas Hellstrom rcu_read_unlock(); 256e14c02e6SThomas Hellstrom return NULL; 257e14c02e6SThomas Hellstrom } 258e14c02e6SThomas Hellstrom 259e14c02e6SThomas Hellstrom __release(RCU); 260e14c02e6SThomas Hellstrom return drm_hash_entry(hash, struct ttm_ref_object, hash)->obj; 261e14c02e6SThomas Hellstrom } 262e14c02e6SThomas Hellstrom EXPORT_SYMBOL(ttm_base_object_noref_lookup); 263e14c02e6SThomas Hellstrom 2640b8762e9SThomas Hellstrom struct ttm_base_object *ttm_base_object_lookup(struct ttm_object_file *tfile, 2650b8762e9SThomas Hellstrom uint32_t key) 2660b8762e9SThomas Hellstrom { 2670b8762e9SThomas Hellstrom struct ttm_base_object *base = NULL; 2682985c964SThomas Zimmermann struct vmwgfx_hash_item *hash; 2692985c964SThomas Zimmermann struct vmwgfx_open_hash *ht = &tfile->ref_hash[TTM_REF_USAGE]; 2700b8762e9SThomas Hellstrom int ret; 2710b8762e9SThomas Hellstrom 2720b8762e9SThomas Hellstrom rcu_read_lock(); 2732985c964SThomas Zimmermann ret = vmwgfx_ht_find_item_rcu(ht, key, &hash); 2740b8762e9SThomas Hellstrom 2750b8762e9SThomas Hellstrom if (likely(ret == 0)) { 2760b8762e9SThomas Hellstrom base = drm_hash_entry(hash, struct ttm_ref_object, hash)->obj; 2770b8762e9SThomas Hellstrom if (!kref_get_unless_zero(&base->refcount)) 2780b8762e9SThomas Hellstrom base = NULL; 2790b8762e9SThomas Hellstrom } 2800b8762e9SThomas Hellstrom rcu_read_unlock(); 2810b8762e9SThomas Hellstrom 2820b8762e9SThomas Hellstrom return base; 2830b8762e9SThomas Hellstrom } 2840b8762e9SThomas Hellstrom 2850b8762e9SThomas Hellstrom struct ttm_base_object * 2860b8762e9SThomas Hellstrom ttm_base_object_lookup_for_ref(struct ttm_object_device *tdev, uint32_t key) 2870b8762e9SThomas Hellstrom { 288c7eae626SThomas Hellstrom struct ttm_base_object *base; 2890b8762e9SThomas Hellstrom 2900b8762e9SThomas Hellstrom rcu_read_lock(); 291c7eae626SThomas Hellstrom base = idr_find(&tdev->idr, key); 2920b8762e9SThomas Hellstrom 293c7eae626SThomas Hellstrom if (base && !kref_get_unless_zero(&base->refcount)) 2940b8762e9SThomas Hellstrom base = NULL; 2950b8762e9SThomas Hellstrom rcu_read_unlock(); 2960b8762e9SThomas Hellstrom 2970b8762e9SThomas Hellstrom return base; 2980b8762e9SThomas Hellstrom } 2990b8762e9SThomas Hellstrom 3000b8762e9SThomas Hellstrom /** 3010b8762e9SThomas Hellstrom * ttm_ref_object_exists - Check whether a caller has a valid ref object 3020b8762e9SThomas Hellstrom * (has opened) a base object. 3030b8762e9SThomas Hellstrom * 3040b8762e9SThomas Hellstrom * @tfile: Pointer to a struct ttm_object_file identifying the caller. 3050b8762e9SThomas Hellstrom * @base: Pointer to a struct base object. 3060b8762e9SThomas Hellstrom * 3070b8762e9SThomas Hellstrom * Checks wether the caller identified by @tfile has put a valid USAGE 3080b8762e9SThomas Hellstrom * reference object on the base object identified by @base. 3090b8762e9SThomas Hellstrom */ 3100b8762e9SThomas Hellstrom bool ttm_ref_object_exists(struct ttm_object_file *tfile, 3110b8762e9SThomas Hellstrom struct ttm_base_object *base) 3120b8762e9SThomas Hellstrom { 3132985c964SThomas Zimmermann struct vmwgfx_open_hash *ht = &tfile->ref_hash[TTM_REF_USAGE]; 3142985c964SThomas Zimmermann struct vmwgfx_hash_item *hash; 3150b8762e9SThomas Hellstrom struct ttm_ref_object *ref; 3160b8762e9SThomas Hellstrom 3170b8762e9SThomas Hellstrom rcu_read_lock(); 3182985c964SThomas Zimmermann if (unlikely(vmwgfx_ht_find_item_rcu(ht, base->handle, &hash) != 0)) 3190b8762e9SThomas Hellstrom goto out_false; 3200b8762e9SThomas Hellstrom 3210b8762e9SThomas Hellstrom /* 3220b8762e9SThomas Hellstrom * Verify that the ref object is really pointing to our base object. 3230b8762e9SThomas Hellstrom * Our base object could actually be dead, and the ref object pointing 3240b8762e9SThomas Hellstrom * to another base object with the same handle. 3250b8762e9SThomas Hellstrom */ 3260b8762e9SThomas Hellstrom ref = drm_hash_entry(hash, struct ttm_ref_object, hash); 3270b8762e9SThomas Hellstrom if (unlikely(base != ref->obj)) 3280b8762e9SThomas Hellstrom goto out_false; 3290b8762e9SThomas Hellstrom 3300b8762e9SThomas Hellstrom /* 3310b8762e9SThomas Hellstrom * Verify that the ref->obj pointer was actually valid! 3320b8762e9SThomas Hellstrom */ 3330b8762e9SThomas Hellstrom rmb(); 3340b8762e9SThomas Hellstrom if (unlikely(kref_read(&ref->kref) == 0)) 3350b8762e9SThomas Hellstrom goto out_false; 3360b8762e9SThomas Hellstrom 3370b8762e9SThomas Hellstrom rcu_read_unlock(); 3380b8762e9SThomas Hellstrom return true; 3390b8762e9SThomas Hellstrom 3400b8762e9SThomas Hellstrom out_false: 3410b8762e9SThomas Hellstrom rcu_read_unlock(); 3420b8762e9SThomas Hellstrom return false; 3430b8762e9SThomas Hellstrom } 3440b8762e9SThomas Hellstrom 3450b8762e9SThomas Hellstrom int ttm_ref_object_add(struct ttm_object_file *tfile, 3460b8762e9SThomas Hellstrom struct ttm_base_object *base, 3470b8762e9SThomas Hellstrom enum ttm_ref_type ref_type, bool *existed, 3480b8762e9SThomas Hellstrom bool require_existed) 3490b8762e9SThomas Hellstrom { 3502985c964SThomas Zimmermann struct vmwgfx_open_hash *ht = &tfile->ref_hash[ref_type]; 3510b8762e9SThomas Hellstrom struct ttm_ref_object *ref; 3522985c964SThomas Zimmermann struct vmwgfx_hash_item *hash; 3530b8762e9SThomas Hellstrom int ret = -EINVAL; 3540b8762e9SThomas Hellstrom 3550b8762e9SThomas Hellstrom if (base->tfile != tfile && !base->shareable) 3560b8762e9SThomas Hellstrom return -EPERM; 3570b8762e9SThomas Hellstrom 3580b8762e9SThomas Hellstrom if (existed != NULL) 3590b8762e9SThomas Hellstrom *existed = true; 3600b8762e9SThomas Hellstrom 3610b8762e9SThomas Hellstrom while (ret == -EINVAL) { 3620b8762e9SThomas Hellstrom rcu_read_lock(); 3632985c964SThomas Zimmermann ret = vmwgfx_ht_find_item_rcu(ht, base->handle, &hash); 3640b8762e9SThomas Hellstrom 3650b8762e9SThomas Hellstrom if (ret == 0) { 3660b8762e9SThomas Hellstrom ref = drm_hash_entry(hash, struct ttm_ref_object, hash); 3670b8762e9SThomas Hellstrom if (kref_get_unless_zero(&ref->kref)) { 3680b8762e9SThomas Hellstrom rcu_read_unlock(); 3690b8762e9SThomas Hellstrom break; 3700b8762e9SThomas Hellstrom } 3710b8762e9SThomas Hellstrom } 3720b8762e9SThomas Hellstrom 3730b8762e9SThomas Hellstrom rcu_read_unlock(); 3740b8762e9SThomas Hellstrom if (require_existed) 3750b8762e9SThomas Hellstrom return -EPERM; 3760b8762e9SThomas Hellstrom 3770b8762e9SThomas Hellstrom ref = kmalloc(sizeof(*ref), GFP_KERNEL); 3780b8762e9SThomas Hellstrom if (unlikely(ref == NULL)) { 3790b8762e9SThomas Hellstrom return -ENOMEM; 3800b8762e9SThomas Hellstrom } 3810b8762e9SThomas Hellstrom 382c7eae626SThomas Hellstrom ref->hash.key = base->handle; 3830b8762e9SThomas Hellstrom ref->obj = base; 3840b8762e9SThomas Hellstrom ref->tfile = tfile; 3850b8762e9SThomas Hellstrom ref->ref_type = ref_type; 3860b8762e9SThomas Hellstrom kref_init(&ref->kref); 3870b8762e9SThomas Hellstrom 3880b8762e9SThomas Hellstrom spin_lock(&tfile->lock); 3892985c964SThomas Zimmermann ret = vmwgfx_ht_insert_item_rcu(ht, &ref->hash); 3900b8762e9SThomas Hellstrom 3910b8762e9SThomas Hellstrom if (likely(ret == 0)) { 3920b8762e9SThomas Hellstrom list_add_tail(&ref->head, &tfile->ref_list); 3930b8762e9SThomas Hellstrom kref_get(&base->refcount); 3940b8762e9SThomas Hellstrom spin_unlock(&tfile->lock); 3950b8762e9SThomas Hellstrom if (existed != NULL) 3960b8762e9SThomas Hellstrom *existed = false; 3970b8762e9SThomas Hellstrom break; 3980b8762e9SThomas Hellstrom } 3990b8762e9SThomas Hellstrom 4000b8762e9SThomas Hellstrom spin_unlock(&tfile->lock); 4010b8762e9SThomas Hellstrom BUG_ON(ret != -EINVAL); 4020b8762e9SThomas Hellstrom 4030b8762e9SThomas Hellstrom kfree(ref); 4040b8762e9SThomas Hellstrom } 4050b8762e9SThomas Hellstrom 4060b8762e9SThomas Hellstrom return ret; 4070b8762e9SThomas Hellstrom } 4080b8762e9SThomas Hellstrom 4090b8762e9SThomas Hellstrom static void __releases(tfile->lock) __acquires(tfile->lock) 4100b8762e9SThomas Hellstrom ttm_ref_object_release(struct kref *kref) 4110b8762e9SThomas Hellstrom { 4120b8762e9SThomas Hellstrom struct ttm_ref_object *ref = 4130b8762e9SThomas Hellstrom container_of(kref, struct ttm_ref_object, kref); 4140b8762e9SThomas Hellstrom struct ttm_base_object *base = ref->obj; 4150b8762e9SThomas Hellstrom struct ttm_object_file *tfile = ref->tfile; 4162985c964SThomas Zimmermann struct vmwgfx_open_hash *ht; 4170b8762e9SThomas Hellstrom 4180b8762e9SThomas Hellstrom ht = &tfile->ref_hash[ref->ref_type]; 4192985c964SThomas Zimmermann (void)vmwgfx_ht_remove_item_rcu(ht, &ref->hash); 4200b8762e9SThomas Hellstrom list_del(&ref->head); 4210b8762e9SThomas Hellstrom spin_unlock(&tfile->lock); 4220b8762e9SThomas Hellstrom 4230b8762e9SThomas Hellstrom if (ref->ref_type != TTM_REF_USAGE && base->ref_obj_release) 4240b8762e9SThomas Hellstrom base->ref_obj_release(base, ref->ref_type); 4250b8762e9SThomas Hellstrom 4260b8762e9SThomas Hellstrom ttm_base_object_unref(&ref->obj); 4270b8762e9SThomas Hellstrom kfree_rcu(ref, rcu_head); 4280b8762e9SThomas Hellstrom spin_lock(&tfile->lock); 4290b8762e9SThomas Hellstrom } 4300b8762e9SThomas Hellstrom 4310b8762e9SThomas Hellstrom int ttm_ref_object_base_unref(struct ttm_object_file *tfile, 4320b8762e9SThomas Hellstrom unsigned long key, enum ttm_ref_type ref_type) 4330b8762e9SThomas Hellstrom { 4342985c964SThomas Zimmermann struct vmwgfx_open_hash *ht = &tfile->ref_hash[ref_type]; 4350b8762e9SThomas Hellstrom struct ttm_ref_object *ref; 4362985c964SThomas Zimmermann struct vmwgfx_hash_item *hash; 4370b8762e9SThomas Hellstrom int ret; 4380b8762e9SThomas Hellstrom 4390b8762e9SThomas Hellstrom spin_lock(&tfile->lock); 4402985c964SThomas Zimmermann ret = vmwgfx_ht_find_item(ht, key, &hash); 4410b8762e9SThomas Hellstrom if (unlikely(ret != 0)) { 4420b8762e9SThomas Hellstrom spin_unlock(&tfile->lock); 4430b8762e9SThomas Hellstrom return -EINVAL; 4440b8762e9SThomas Hellstrom } 4450b8762e9SThomas Hellstrom ref = drm_hash_entry(hash, struct ttm_ref_object, hash); 4460b8762e9SThomas Hellstrom kref_put(&ref->kref, ttm_ref_object_release); 4470b8762e9SThomas Hellstrom spin_unlock(&tfile->lock); 4480b8762e9SThomas Hellstrom return 0; 4490b8762e9SThomas Hellstrom } 4500b8762e9SThomas Hellstrom 4510b8762e9SThomas Hellstrom void ttm_object_file_release(struct ttm_object_file **p_tfile) 4520b8762e9SThomas Hellstrom { 4530b8762e9SThomas Hellstrom struct ttm_ref_object *ref; 4540b8762e9SThomas Hellstrom struct list_head *list; 4550b8762e9SThomas Hellstrom unsigned int i; 4560b8762e9SThomas Hellstrom struct ttm_object_file *tfile = *p_tfile; 4570b8762e9SThomas Hellstrom 4580b8762e9SThomas Hellstrom *p_tfile = NULL; 4590b8762e9SThomas Hellstrom spin_lock(&tfile->lock); 4600b8762e9SThomas Hellstrom 4610b8762e9SThomas Hellstrom /* 4620b8762e9SThomas Hellstrom * Since we release the lock within the loop, we have to 4630b8762e9SThomas Hellstrom * restart it from the beginning each time. 4640b8762e9SThomas Hellstrom */ 4650b8762e9SThomas Hellstrom 4660b8762e9SThomas Hellstrom while (!list_empty(&tfile->ref_list)) { 4670b8762e9SThomas Hellstrom list = tfile->ref_list.next; 4680b8762e9SThomas Hellstrom ref = list_entry(list, struct ttm_ref_object, head); 4690b8762e9SThomas Hellstrom ttm_ref_object_release(&ref->kref); 4700b8762e9SThomas Hellstrom } 4710b8762e9SThomas Hellstrom 4720b8762e9SThomas Hellstrom spin_unlock(&tfile->lock); 4730b8762e9SThomas Hellstrom for (i = 0; i < TTM_REF_NUM; ++i) 4742985c964SThomas Zimmermann vmwgfx_ht_remove(&tfile->ref_hash[i]); 4750b8762e9SThomas Hellstrom 4760b8762e9SThomas Hellstrom ttm_object_file_unref(&tfile); 4770b8762e9SThomas Hellstrom } 4780b8762e9SThomas Hellstrom 4790b8762e9SThomas Hellstrom struct ttm_object_file *ttm_object_file_init(struct ttm_object_device *tdev, 4800b8762e9SThomas Hellstrom unsigned int hash_order) 4810b8762e9SThomas Hellstrom { 4820b8762e9SThomas Hellstrom struct ttm_object_file *tfile = kmalloc(sizeof(*tfile), GFP_KERNEL); 4830b8762e9SThomas Hellstrom unsigned int i; 4840b8762e9SThomas Hellstrom unsigned int j = 0; 4850b8762e9SThomas Hellstrom int ret; 4860b8762e9SThomas Hellstrom 4870b8762e9SThomas Hellstrom if (unlikely(tfile == NULL)) 4880b8762e9SThomas Hellstrom return NULL; 4890b8762e9SThomas Hellstrom 4900b8762e9SThomas Hellstrom spin_lock_init(&tfile->lock); 4910b8762e9SThomas Hellstrom tfile->tdev = tdev; 4920b8762e9SThomas Hellstrom kref_init(&tfile->refcount); 4930b8762e9SThomas Hellstrom INIT_LIST_HEAD(&tfile->ref_list); 4940b8762e9SThomas Hellstrom 4950b8762e9SThomas Hellstrom for (i = 0; i < TTM_REF_NUM; ++i) { 4962985c964SThomas Zimmermann ret = vmwgfx_ht_create(&tfile->ref_hash[i], hash_order); 4970b8762e9SThomas Hellstrom if (ret) { 4980b8762e9SThomas Hellstrom j = i; 4990b8762e9SThomas Hellstrom goto out_err; 5000b8762e9SThomas Hellstrom } 5010b8762e9SThomas Hellstrom } 5020b8762e9SThomas Hellstrom 5030b8762e9SThomas Hellstrom return tfile; 5040b8762e9SThomas Hellstrom out_err: 5050b8762e9SThomas Hellstrom for (i = 0; i < j; ++i) 5062985c964SThomas Zimmermann vmwgfx_ht_remove(&tfile->ref_hash[i]); 5070b8762e9SThomas Hellstrom 5080b8762e9SThomas Hellstrom kfree(tfile); 5090b8762e9SThomas Hellstrom 5100b8762e9SThomas Hellstrom return NULL; 5110b8762e9SThomas Hellstrom } 5120b8762e9SThomas Hellstrom 5130b8762e9SThomas Hellstrom struct ttm_object_device * 514*8aadeb8aSZack Rusin ttm_object_device_init(unsigned int hash_order, 5150b8762e9SThomas Hellstrom const struct dma_buf_ops *ops) 5160b8762e9SThomas Hellstrom { 5170b8762e9SThomas Hellstrom struct ttm_object_device *tdev = kmalloc(sizeof(*tdev), GFP_KERNEL); 5180b8762e9SThomas Hellstrom int ret; 5190b8762e9SThomas Hellstrom 5200b8762e9SThomas Hellstrom if (unlikely(tdev == NULL)) 5210b8762e9SThomas Hellstrom return NULL; 5220b8762e9SThomas Hellstrom 5230b8762e9SThomas Hellstrom spin_lock_init(&tdev->object_lock); 5240b8762e9SThomas Hellstrom atomic_set(&tdev->object_count, 0); 5252985c964SThomas Zimmermann ret = vmwgfx_ht_create(&tdev->object_hash, hash_order); 5260b8762e9SThomas Hellstrom if (ret != 0) 5270b8762e9SThomas Hellstrom goto out_no_object_hash; 5280b8762e9SThomas Hellstrom 529aec70c39SDeepak R Varma idr_init_base(&tdev->idr, 1); 5300b8762e9SThomas Hellstrom tdev->ops = *ops; 5310b8762e9SThomas Hellstrom tdev->dmabuf_release = tdev->ops.release; 5320b8762e9SThomas Hellstrom tdev->ops.release = ttm_prime_dmabuf_release; 5330b8762e9SThomas Hellstrom return tdev; 5340b8762e9SThomas Hellstrom 5350b8762e9SThomas Hellstrom out_no_object_hash: 5360b8762e9SThomas Hellstrom kfree(tdev); 5370b8762e9SThomas Hellstrom return NULL; 5380b8762e9SThomas Hellstrom } 5390b8762e9SThomas Hellstrom 5400b8762e9SThomas Hellstrom void ttm_object_device_release(struct ttm_object_device **p_tdev) 5410b8762e9SThomas Hellstrom { 5420b8762e9SThomas Hellstrom struct ttm_object_device *tdev = *p_tdev; 5430b8762e9SThomas Hellstrom 5440b8762e9SThomas Hellstrom *p_tdev = NULL; 5450b8762e9SThomas Hellstrom 546c7eae626SThomas Hellstrom WARN_ON_ONCE(!idr_is_empty(&tdev->idr)); 547c7eae626SThomas Hellstrom idr_destroy(&tdev->idr); 5482985c964SThomas Zimmermann vmwgfx_ht_remove(&tdev->object_hash); 5490b8762e9SThomas Hellstrom 5500b8762e9SThomas Hellstrom kfree(tdev); 5510b8762e9SThomas Hellstrom } 5520b8762e9SThomas Hellstrom 5530b8762e9SThomas Hellstrom /** 5540b8762e9SThomas Hellstrom * get_dma_buf_unless_doomed - get a dma_buf reference if possible. 5550b8762e9SThomas Hellstrom * 556f322f32aSLee Jones * @dmabuf: Non-refcounted pointer to a struct dma-buf. 5570b8762e9SThomas Hellstrom * 5580b8762e9SThomas Hellstrom * Obtain a file reference from a lookup structure that doesn't refcount 5590b8762e9SThomas Hellstrom * the file, but synchronizes with its release method to make sure it has 5600b8762e9SThomas Hellstrom * not been freed yet. See for example kref_get_unless_zero documentation. 5610b8762e9SThomas Hellstrom * Returns true if refcounting succeeds, false otherwise. 5620b8762e9SThomas Hellstrom * 5630b8762e9SThomas Hellstrom * Nobody really wants this as a public API yet, so let it mature here 5640b8762e9SThomas Hellstrom * for some time... 5650b8762e9SThomas Hellstrom */ 5660b8762e9SThomas Hellstrom static bool __must_check get_dma_buf_unless_doomed(struct dma_buf *dmabuf) 5670b8762e9SThomas Hellstrom { 5680b8762e9SThomas Hellstrom return atomic_long_inc_not_zero(&dmabuf->file->f_count) != 0L; 5690b8762e9SThomas Hellstrom } 5700b8762e9SThomas Hellstrom 5710b8762e9SThomas Hellstrom /** 5720b8762e9SThomas Hellstrom * ttm_prime_refcount_release - refcount release method for a prime object. 5730b8762e9SThomas Hellstrom * 5740b8762e9SThomas Hellstrom * @p_base: Pointer to ttm_base_object pointer. 5750b8762e9SThomas Hellstrom * 5760b8762e9SThomas Hellstrom * This is a wrapper that calls the refcount_release founction of the 5770b8762e9SThomas Hellstrom * underlying object. At the same time it cleans up the prime object. 5780b8762e9SThomas Hellstrom * This function is called when all references to the base object we 5790b8762e9SThomas Hellstrom * derive from are gone. 5800b8762e9SThomas Hellstrom */ 5810b8762e9SThomas Hellstrom static void ttm_prime_refcount_release(struct ttm_base_object **p_base) 5820b8762e9SThomas Hellstrom { 5830b8762e9SThomas Hellstrom struct ttm_base_object *base = *p_base; 5840b8762e9SThomas Hellstrom struct ttm_prime_object *prime; 5850b8762e9SThomas Hellstrom 5860b8762e9SThomas Hellstrom *p_base = NULL; 5870b8762e9SThomas Hellstrom prime = container_of(base, struct ttm_prime_object, base); 5880b8762e9SThomas Hellstrom BUG_ON(prime->dma_buf != NULL); 5890b8762e9SThomas Hellstrom mutex_destroy(&prime->mutex); 5900b8762e9SThomas Hellstrom if (prime->refcount_release) 5910b8762e9SThomas Hellstrom prime->refcount_release(&base); 5920b8762e9SThomas Hellstrom } 5930b8762e9SThomas Hellstrom 5940b8762e9SThomas Hellstrom /** 5950b8762e9SThomas Hellstrom * ttm_prime_dmabuf_release - Release method for the dma-bufs we export 5960b8762e9SThomas Hellstrom * 5970b8762e9SThomas Hellstrom * @dma_buf: 5980b8762e9SThomas Hellstrom * 5990b8762e9SThomas Hellstrom * This function first calls the dma_buf release method the driver 6000b8762e9SThomas Hellstrom * provides. Then it cleans up our dma_buf pointer used for lookup, 6010b8762e9SThomas Hellstrom * and finally releases the reference the dma_buf has on our base 6020b8762e9SThomas Hellstrom * object. 6030b8762e9SThomas Hellstrom */ 6040b8762e9SThomas Hellstrom static void ttm_prime_dmabuf_release(struct dma_buf *dma_buf) 6050b8762e9SThomas Hellstrom { 6060b8762e9SThomas Hellstrom struct ttm_prime_object *prime = 6070b8762e9SThomas Hellstrom (struct ttm_prime_object *) dma_buf->priv; 6080b8762e9SThomas Hellstrom struct ttm_base_object *base = &prime->base; 6090b8762e9SThomas Hellstrom struct ttm_object_device *tdev = base->tfile->tdev; 6100b8762e9SThomas Hellstrom 6110b8762e9SThomas Hellstrom if (tdev->dmabuf_release) 6120b8762e9SThomas Hellstrom tdev->dmabuf_release(dma_buf); 6130b8762e9SThomas Hellstrom mutex_lock(&prime->mutex); 6140b8762e9SThomas Hellstrom if (prime->dma_buf == dma_buf) 6150b8762e9SThomas Hellstrom prime->dma_buf = NULL; 6160b8762e9SThomas Hellstrom mutex_unlock(&prime->mutex); 6170b8762e9SThomas Hellstrom ttm_base_object_unref(&base); 6180b8762e9SThomas Hellstrom } 6190b8762e9SThomas Hellstrom 6200b8762e9SThomas Hellstrom /** 6210b8762e9SThomas Hellstrom * ttm_prime_fd_to_handle - Get a base object handle from a prime fd 6220b8762e9SThomas Hellstrom * 6230b8762e9SThomas Hellstrom * @tfile: A struct ttm_object_file identifying the caller. 6240b8762e9SThomas Hellstrom * @fd: The prime / dmabuf fd. 6250b8762e9SThomas Hellstrom * @handle: The returned handle. 6260b8762e9SThomas Hellstrom * 6270b8762e9SThomas Hellstrom * This function returns a handle to an object that previously exported 6280b8762e9SThomas Hellstrom * a dma-buf. Note that we don't handle imports yet, because we simply 6290b8762e9SThomas Hellstrom * have no consumers of that implementation. 6300b8762e9SThomas Hellstrom */ 6310b8762e9SThomas Hellstrom int ttm_prime_fd_to_handle(struct ttm_object_file *tfile, 6320b8762e9SThomas Hellstrom int fd, u32 *handle) 6330b8762e9SThomas Hellstrom { 6340b8762e9SThomas Hellstrom struct ttm_object_device *tdev = tfile->tdev; 6350b8762e9SThomas Hellstrom struct dma_buf *dma_buf; 6360b8762e9SThomas Hellstrom struct ttm_prime_object *prime; 6370b8762e9SThomas Hellstrom struct ttm_base_object *base; 6380b8762e9SThomas Hellstrom int ret; 6390b8762e9SThomas Hellstrom 6400b8762e9SThomas Hellstrom dma_buf = dma_buf_get(fd); 6410b8762e9SThomas Hellstrom if (IS_ERR(dma_buf)) 6420b8762e9SThomas Hellstrom return PTR_ERR(dma_buf); 6430b8762e9SThomas Hellstrom 6440b8762e9SThomas Hellstrom if (dma_buf->ops != &tdev->ops) 6450b8762e9SThomas Hellstrom return -ENOSYS; 6460b8762e9SThomas Hellstrom 6470b8762e9SThomas Hellstrom prime = (struct ttm_prime_object *) dma_buf->priv; 6480b8762e9SThomas Hellstrom base = &prime->base; 649c7eae626SThomas Hellstrom *handle = base->handle; 6500b8762e9SThomas Hellstrom ret = ttm_ref_object_add(tfile, base, TTM_REF_USAGE, NULL, false); 6510b8762e9SThomas Hellstrom 6520b8762e9SThomas Hellstrom dma_buf_put(dma_buf); 6530b8762e9SThomas Hellstrom 6540b8762e9SThomas Hellstrom return ret; 6550b8762e9SThomas Hellstrom } 6560b8762e9SThomas Hellstrom 6570b8762e9SThomas Hellstrom /** 6580b8762e9SThomas Hellstrom * ttm_prime_handle_to_fd - Return a dma_buf fd from a ttm prime object 6590b8762e9SThomas Hellstrom * 6600b8762e9SThomas Hellstrom * @tfile: Struct ttm_object_file identifying the caller. 6610b8762e9SThomas Hellstrom * @handle: Handle to the object we're exporting from. 6620b8762e9SThomas Hellstrom * @flags: flags for dma-buf creation. We just pass them on. 6630b8762e9SThomas Hellstrom * @prime_fd: The returned file descriptor. 6640b8762e9SThomas Hellstrom * 6650b8762e9SThomas Hellstrom */ 6660b8762e9SThomas Hellstrom int ttm_prime_handle_to_fd(struct ttm_object_file *tfile, 6670b8762e9SThomas Hellstrom uint32_t handle, uint32_t flags, 6680b8762e9SThomas Hellstrom int *prime_fd) 6690b8762e9SThomas Hellstrom { 6700b8762e9SThomas Hellstrom struct ttm_object_device *tdev = tfile->tdev; 6710b8762e9SThomas Hellstrom struct ttm_base_object *base; 6720b8762e9SThomas Hellstrom struct dma_buf *dma_buf; 6730b8762e9SThomas Hellstrom struct ttm_prime_object *prime; 6740b8762e9SThomas Hellstrom int ret; 6750b8762e9SThomas Hellstrom 6760b8762e9SThomas Hellstrom base = ttm_base_object_lookup(tfile, handle); 6770b8762e9SThomas Hellstrom if (unlikely(base == NULL || 6780b8762e9SThomas Hellstrom base->object_type != ttm_prime_type)) { 6790b8762e9SThomas Hellstrom ret = -ENOENT; 6800b8762e9SThomas Hellstrom goto out_unref; 6810b8762e9SThomas Hellstrom } 6820b8762e9SThomas Hellstrom 6830b8762e9SThomas Hellstrom prime = container_of(base, struct ttm_prime_object, base); 6840b8762e9SThomas Hellstrom if (unlikely(!base->shareable)) { 6850b8762e9SThomas Hellstrom ret = -EPERM; 6860b8762e9SThomas Hellstrom goto out_unref; 6870b8762e9SThomas Hellstrom } 6880b8762e9SThomas Hellstrom 6890b8762e9SThomas Hellstrom ret = mutex_lock_interruptible(&prime->mutex); 6900b8762e9SThomas Hellstrom if (unlikely(ret != 0)) { 6910b8762e9SThomas Hellstrom ret = -ERESTARTSYS; 6920b8762e9SThomas Hellstrom goto out_unref; 6930b8762e9SThomas Hellstrom } 6940b8762e9SThomas Hellstrom 6950b8762e9SThomas Hellstrom dma_buf = prime->dma_buf; 6960b8762e9SThomas Hellstrom if (!dma_buf || !get_dma_buf_unless_doomed(dma_buf)) { 6970b8762e9SThomas Hellstrom DEFINE_DMA_BUF_EXPORT_INFO(exp_info); 6980b8762e9SThomas Hellstrom exp_info.ops = &tdev->ops; 6990b8762e9SThomas Hellstrom exp_info.size = prime->size; 7000b8762e9SThomas Hellstrom exp_info.flags = flags; 7010b8762e9SThomas Hellstrom exp_info.priv = prime; 7020b8762e9SThomas Hellstrom 7030b8762e9SThomas Hellstrom /* 704*8aadeb8aSZack Rusin * Need to create a new dma_buf 7050b8762e9SThomas Hellstrom */ 7060b8762e9SThomas Hellstrom 7070b8762e9SThomas Hellstrom dma_buf = dma_buf_export(&exp_info); 7080b8762e9SThomas Hellstrom if (IS_ERR(dma_buf)) { 7090b8762e9SThomas Hellstrom ret = PTR_ERR(dma_buf); 7100b8762e9SThomas Hellstrom mutex_unlock(&prime->mutex); 7110b8762e9SThomas Hellstrom goto out_unref; 7120b8762e9SThomas Hellstrom } 7130b8762e9SThomas Hellstrom 7140b8762e9SThomas Hellstrom /* 7150b8762e9SThomas Hellstrom * dma_buf has taken the base object reference 7160b8762e9SThomas Hellstrom */ 7170b8762e9SThomas Hellstrom base = NULL; 7180b8762e9SThomas Hellstrom prime->dma_buf = dma_buf; 7190b8762e9SThomas Hellstrom } 7200b8762e9SThomas Hellstrom mutex_unlock(&prime->mutex); 7210b8762e9SThomas Hellstrom 7220b8762e9SThomas Hellstrom ret = dma_buf_fd(dma_buf, flags); 7230b8762e9SThomas Hellstrom if (ret >= 0) { 7240b8762e9SThomas Hellstrom *prime_fd = ret; 7250b8762e9SThomas Hellstrom ret = 0; 7260b8762e9SThomas Hellstrom } else 7270b8762e9SThomas Hellstrom dma_buf_put(dma_buf); 7280b8762e9SThomas Hellstrom 7290b8762e9SThomas Hellstrom out_unref: 7300b8762e9SThomas Hellstrom if (base) 7310b8762e9SThomas Hellstrom ttm_base_object_unref(&base); 7320b8762e9SThomas Hellstrom return ret; 7330b8762e9SThomas Hellstrom } 7340b8762e9SThomas Hellstrom 7350b8762e9SThomas Hellstrom /** 7360b8762e9SThomas Hellstrom * ttm_prime_object_init - Initialize a ttm_prime_object 7370b8762e9SThomas Hellstrom * 7380b8762e9SThomas Hellstrom * @tfile: struct ttm_object_file identifying the caller 7390b8762e9SThomas Hellstrom * @size: The size of the dma_bufs we export. 7400b8762e9SThomas Hellstrom * @prime: The object to be initialized. 7410b8762e9SThomas Hellstrom * @shareable: See ttm_base_object_init 7420b8762e9SThomas Hellstrom * @type: See ttm_base_object_init 7430b8762e9SThomas Hellstrom * @refcount_release: See ttm_base_object_init 7440b8762e9SThomas Hellstrom * @ref_obj_release: See ttm_base_object_init 7450b8762e9SThomas Hellstrom * 7460b8762e9SThomas Hellstrom * Initializes an object which is compatible with the drm_prime model 7470b8762e9SThomas Hellstrom * for data sharing between processes and devices. 7480b8762e9SThomas Hellstrom */ 7490b8762e9SThomas Hellstrom int ttm_prime_object_init(struct ttm_object_file *tfile, size_t size, 7500b8762e9SThomas Hellstrom struct ttm_prime_object *prime, bool shareable, 7510b8762e9SThomas Hellstrom enum ttm_object_type type, 7520b8762e9SThomas Hellstrom void (*refcount_release) (struct ttm_base_object **), 7530b8762e9SThomas Hellstrom void (*ref_obj_release) (struct ttm_base_object *, 7540b8762e9SThomas Hellstrom enum ttm_ref_type ref_type)) 7550b8762e9SThomas Hellstrom { 7560b8762e9SThomas Hellstrom mutex_init(&prime->mutex); 7570b8762e9SThomas Hellstrom prime->size = PAGE_ALIGN(size); 7580b8762e9SThomas Hellstrom prime->real_type = type; 7590b8762e9SThomas Hellstrom prime->dma_buf = NULL; 7600b8762e9SThomas Hellstrom prime->refcount_release = refcount_release; 7610b8762e9SThomas Hellstrom return ttm_base_object_init(tfile, &prime->base, shareable, 7620b8762e9SThomas Hellstrom ttm_prime_type, 7630b8762e9SThomas Hellstrom ttm_prime_refcount_release, 7640b8762e9SThomas Hellstrom ref_obj_release); 7650b8762e9SThomas Hellstrom } 766