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 450b8762e9SThomas Hellstrom /** 460b8762e9SThomas Hellstrom * struct ttm_object_file 470b8762e9SThomas Hellstrom * 480b8762e9SThomas Hellstrom * @tdev: Pointer to the ttm_object_device. 490b8762e9SThomas Hellstrom * 500b8762e9SThomas Hellstrom * @lock: Lock that protects the ref_list list and the 510b8762e9SThomas Hellstrom * ref_hash hash tables. 520b8762e9SThomas Hellstrom * 530b8762e9SThomas Hellstrom * @ref_list: List of ttm_ref_objects to be destroyed at 540b8762e9SThomas Hellstrom * file release. 550b8762e9SThomas Hellstrom * 560b8762e9SThomas Hellstrom * @ref_hash: Hash tables of ref objects, one per ttm_ref_type, 570b8762e9SThomas Hellstrom * for fast lookup of ref objects given a base object. 580b8762e9SThomas Hellstrom */ 590b8762e9SThomas Hellstrom 600b8762e9SThomas Hellstrom #define pr_fmt(fmt) "[TTM] " fmt 610b8762e9SThomas Hellstrom 620b8762e9SThomas Hellstrom #include <drm/ttm/ttm_module.h> 630b8762e9SThomas Hellstrom #include <linux/list.h> 640b8762e9SThomas Hellstrom #include <linux/spinlock.h> 650b8762e9SThomas Hellstrom #include <linux/slab.h> 660b8762e9SThomas Hellstrom #include <linux/atomic.h> 670b8762e9SThomas Hellstrom #include "ttm_object.h" 680b8762e9SThomas Hellstrom 690b8762e9SThomas Hellstrom struct ttm_object_file { 700b8762e9SThomas Hellstrom struct ttm_object_device *tdev; 710b8762e9SThomas Hellstrom spinlock_t lock; 720b8762e9SThomas Hellstrom struct list_head ref_list; 730b8762e9SThomas Hellstrom struct drm_open_hash ref_hash[TTM_REF_NUM]; 740b8762e9SThomas Hellstrom struct kref refcount; 750b8762e9SThomas Hellstrom }; 760b8762e9SThomas Hellstrom 770b8762e9SThomas Hellstrom /** 780b8762e9SThomas Hellstrom * struct ttm_object_device 790b8762e9SThomas Hellstrom * 800b8762e9SThomas Hellstrom * @object_lock: lock that protects the object_hash hash table. 810b8762e9SThomas Hellstrom * 820b8762e9SThomas Hellstrom * @object_hash: hash table for fast lookup of object global names. 830b8762e9SThomas Hellstrom * 840b8762e9SThomas Hellstrom * @object_count: Per device object count. 850b8762e9SThomas Hellstrom * 860b8762e9SThomas Hellstrom * This is the per-device data structure needed for ttm object management. 870b8762e9SThomas Hellstrom */ 880b8762e9SThomas Hellstrom 890b8762e9SThomas Hellstrom struct ttm_object_device { 900b8762e9SThomas Hellstrom spinlock_t object_lock; 910b8762e9SThomas Hellstrom struct drm_open_hash object_hash; 920b8762e9SThomas Hellstrom atomic_t object_count; 930b8762e9SThomas Hellstrom struct ttm_mem_global *mem_glob; 940b8762e9SThomas Hellstrom struct dma_buf_ops ops; 950b8762e9SThomas Hellstrom void (*dmabuf_release)(struct dma_buf *dma_buf); 960b8762e9SThomas Hellstrom size_t dma_buf_size; 97c7eae626SThomas Hellstrom struct idr idr; 980b8762e9SThomas Hellstrom }; 990b8762e9SThomas Hellstrom 1000b8762e9SThomas Hellstrom /** 1010b8762e9SThomas Hellstrom * struct ttm_ref_object 1020b8762e9SThomas Hellstrom * 1030b8762e9SThomas Hellstrom * @hash: Hash entry for the per-file object reference hash. 1040b8762e9SThomas Hellstrom * 1050b8762e9SThomas Hellstrom * @head: List entry for the per-file list of ref-objects. 1060b8762e9SThomas Hellstrom * 1070b8762e9SThomas Hellstrom * @kref: Ref count. 1080b8762e9SThomas Hellstrom * 1090b8762e9SThomas Hellstrom * @obj: Base object this ref object is referencing. 1100b8762e9SThomas Hellstrom * 1110b8762e9SThomas Hellstrom * @ref_type: Type of ref object. 1120b8762e9SThomas Hellstrom * 1130b8762e9SThomas Hellstrom * This is similar to an idr object, but it also has a hash table entry 1140b8762e9SThomas Hellstrom * that allows lookup with a pointer to the referenced object as a key. In 1150b8762e9SThomas Hellstrom * that way, one can easily detect whether a base object is referenced by 1160b8762e9SThomas Hellstrom * a particular ttm_object_file. It also carries a ref count to avoid creating 1170b8762e9SThomas Hellstrom * multiple ref objects if a ttm_object_file references the same base 1180b8762e9SThomas Hellstrom * object more than once. 1190b8762e9SThomas Hellstrom */ 1200b8762e9SThomas Hellstrom 1210b8762e9SThomas Hellstrom struct ttm_ref_object { 1220b8762e9SThomas Hellstrom struct rcu_head rcu_head; 1230b8762e9SThomas Hellstrom struct drm_hash_item hash; 1240b8762e9SThomas Hellstrom struct list_head head; 1250b8762e9SThomas Hellstrom struct kref kref; 1260b8762e9SThomas Hellstrom enum ttm_ref_type ref_type; 1270b8762e9SThomas Hellstrom struct ttm_base_object *obj; 1280b8762e9SThomas Hellstrom struct ttm_object_file *tfile; 1290b8762e9SThomas Hellstrom }; 1300b8762e9SThomas Hellstrom 1310b8762e9SThomas Hellstrom static void ttm_prime_dmabuf_release(struct dma_buf *dma_buf); 1320b8762e9SThomas Hellstrom 1330b8762e9SThomas Hellstrom static inline struct ttm_object_file * 1340b8762e9SThomas Hellstrom ttm_object_file_ref(struct ttm_object_file *tfile) 1350b8762e9SThomas Hellstrom { 1360b8762e9SThomas Hellstrom kref_get(&tfile->refcount); 1370b8762e9SThomas Hellstrom return tfile; 1380b8762e9SThomas Hellstrom } 1390b8762e9SThomas Hellstrom 1400b8762e9SThomas Hellstrom static void ttm_object_file_destroy(struct kref *kref) 1410b8762e9SThomas Hellstrom { 1420b8762e9SThomas Hellstrom struct ttm_object_file *tfile = 1430b8762e9SThomas Hellstrom container_of(kref, struct ttm_object_file, refcount); 1440b8762e9SThomas Hellstrom 1450b8762e9SThomas Hellstrom kfree(tfile); 1460b8762e9SThomas Hellstrom } 1470b8762e9SThomas Hellstrom 1480b8762e9SThomas Hellstrom 1490b8762e9SThomas Hellstrom static inline void ttm_object_file_unref(struct ttm_object_file **p_tfile) 1500b8762e9SThomas Hellstrom { 1510b8762e9SThomas Hellstrom struct ttm_object_file *tfile = *p_tfile; 1520b8762e9SThomas Hellstrom 1530b8762e9SThomas Hellstrom *p_tfile = NULL; 1540b8762e9SThomas Hellstrom kref_put(&tfile->refcount, ttm_object_file_destroy); 1550b8762e9SThomas Hellstrom } 1560b8762e9SThomas Hellstrom 1570b8762e9SThomas Hellstrom 1580b8762e9SThomas Hellstrom int ttm_base_object_init(struct ttm_object_file *tfile, 1590b8762e9SThomas Hellstrom struct ttm_base_object *base, 1600b8762e9SThomas Hellstrom bool shareable, 1610b8762e9SThomas Hellstrom enum ttm_object_type object_type, 1620b8762e9SThomas Hellstrom void (*refcount_release) (struct ttm_base_object **), 1630b8762e9SThomas Hellstrom void (*ref_obj_release) (struct ttm_base_object *, 1640b8762e9SThomas Hellstrom enum ttm_ref_type ref_type)) 1650b8762e9SThomas Hellstrom { 1660b8762e9SThomas Hellstrom struct ttm_object_device *tdev = tfile->tdev; 1670b8762e9SThomas Hellstrom int ret; 1680b8762e9SThomas Hellstrom 1690b8762e9SThomas Hellstrom base->shareable = shareable; 1700b8762e9SThomas Hellstrom base->tfile = ttm_object_file_ref(tfile); 1710b8762e9SThomas Hellstrom base->refcount_release = refcount_release; 1720b8762e9SThomas Hellstrom base->ref_obj_release = ref_obj_release; 1730b8762e9SThomas Hellstrom base->object_type = object_type; 1740b8762e9SThomas Hellstrom kref_init(&base->refcount); 175c7eae626SThomas Hellstrom idr_preload(GFP_KERNEL); 1760b8762e9SThomas Hellstrom spin_lock(&tdev->object_lock); 177c7eae626SThomas Hellstrom ret = idr_alloc(&tdev->idr, base, 0, 0, GFP_NOWAIT); 1780b8762e9SThomas Hellstrom spin_unlock(&tdev->object_lock); 179c7eae626SThomas Hellstrom idr_preload_end(); 180c7eae626SThomas Hellstrom if (ret < 0) 181c7eae626SThomas Hellstrom return ret; 1820b8762e9SThomas Hellstrom 183c7eae626SThomas Hellstrom base->handle = ret; 1840b8762e9SThomas Hellstrom ret = ttm_ref_object_add(tfile, base, TTM_REF_USAGE, NULL, false); 1850b8762e9SThomas Hellstrom if (unlikely(ret != 0)) 1860b8762e9SThomas Hellstrom goto out_err1; 1870b8762e9SThomas Hellstrom 1880b8762e9SThomas Hellstrom ttm_base_object_unref(&base); 1890b8762e9SThomas Hellstrom 1900b8762e9SThomas Hellstrom return 0; 1910b8762e9SThomas Hellstrom out_err1: 1920b8762e9SThomas Hellstrom spin_lock(&tdev->object_lock); 193c7eae626SThomas Hellstrom idr_remove(&tdev->idr, base->handle); 1940b8762e9SThomas Hellstrom spin_unlock(&tdev->object_lock); 1950b8762e9SThomas Hellstrom return ret; 1960b8762e9SThomas Hellstrom } 1970b8762e9SThomas Hellstrom 1980b8762e9SThomas Hellstrom static void ttm_release_base(struct kref *kref) 1990b8762e9SThomas Hellstrom { 2000b8762e9SThomas Hellstrom struct ttm_base_object *base = 2010b8762e9SThomas Hellstrom container_of(kref, struct ttm_base_object, refcount); 2020b8762e9SThomas Hellstrom struct ttm_object_device *tdev = base->tfile->tdev; 2030b8762e9SThomas Hellstrom 2040b8762e9SThomas Hellstrom spin_lock(&tdev->object_lock); 205c7eae626SThomas Hellstrom idr_remove(&tdev->idr, base->handle); 2060b8762e9SThomas Hellstrom spin_unlock(&tdev->object_lock); 2070b8762e9SThomas Hellstrom 2080b8762e9SThomas Hellstrom /* 2090b8762e9SThomas Hellstrom * Note: We don't use synchronize_rcu() here because it's far 2100b8762e9SThomas Hellstrom * too slow. It's up to the user to free the object using 2110b8762e9SThomas Hellstrom * call_rcu() or ttm_base_object_kfree(). 2120b8762e9SThomas Hellstrom */ 2130b8762e9SThomas Hellstrom 2140b8762e9SThomas Hellstrom ttm_object_file_unref(&base->tfile); 2150b8762e9SThomas Hellstrom if (base->refcount_release) 2160b8762e9SThomas Hellstrom base->refcount_release(&base); 2170b8762e9SThomas Hellstrom } 2180b8762e9SThomas Hellstrom 2190b8762e9SThomas Hellstrom void ttm_base_object_unref(struct ttm_base_object **p_base) 2200b8762e9SThomas Hellstrom { 2210b8762e9SThomas Hellstrom struct ttm_base_object *base = *p_base; 2220b8762e9SThomas Hellstrom 2230b8762e9SThomas Hellstrom *p_base = NULL; 2240b8762e9SThomas Hellstrom 2250b8762e9SThomas Hellstrom kref_put(&base->refcount, ttm_release_base); 2260b8762e9SThomas Hellstrom } 2270b8762e9SThomas Hellstrom 2280b8762e9SThomas Hellstrom struct ttm_base_object *ttm_base_object_lookup(struct ttm_object_file *tfile, 2290b8762e9SThomas Hellstrom uint32_t key) 2300b8762e9SThomas Hellstrom { 2310b8762e9SThomas Hellstrom struct ttm_base_object *base = NULL; 2320b8762e9SThomas Hellstrom struct drm_hash_item *hash; 2330b8762e9SThomas Hellstrom struct drm_open_hash *ht = &tfile->ref_hash[TTM_REF_USAGE]; 2340b8762e9SThomas Hellstrom int ret; 2350b8762e9SThomas Hellstrom 2360b8762e9SThomas Hellstrom rcu_read_lock(); 2370b8762e9SThomas Hellstrom ret = drm_ht_find_item_rcu(ht, key, &hash); 2380b8762e9SThomas Hellstrom 2390b8762e9SThomas Hellstrom if (likely(ret == 0)) { 2400b8762e9SThomas Hellstrom base = drm_hash_entry(hash, struct ttm_ref_object, hash)->obj; 2410b8762e9SThomas Hellstrom if (!kref_get_unless_zero(&base->refcount)) 2420b8762e9SThomas Hellstrom base = NULL; 2430b8762e9SThomas Hellstrom } 2440b8762e9SThomas Hellstrom rcu_read_unlock(); 2450b8762e9SThomas Hellstrom 2460b8762e9SThomas Hellstrom return base; 2470b8762e9SThomas Hellstrom } 2480b8762e9SThomas Hellstrom 2490b8762e9SThomas Hellstrom struct ttm_base_object * 2500b8762e9SThomas Hellstrom ttm_base_object_lookup_for_ref(struct ttm_object_device *tdev, uint32_t key) 2510b8762e9SThomas Hellstrom { 252c7eae626SThomas Hellstrom struct ttm_base_object *base; 2530b8762e9SThomas Hellstrom 2540b8762e9SThomas Hellstrom rcu_read_lock(); 255c7eae626SThomas Hellstrom base = idr_find(&tdev->idr, key); 2560b8762e9SThomas Hellstrom 257c7eae626SThomas Hellstrom if (base && !kref_get_unless_zero(&base->refcount)) 2580b8762e9SThomas Hellstrom base = NULL; 2590b8762e9SThomas Hellstrom rcu_read_unlock(); 2600b8762e9SThomas Hellstrom 2610b8762e9SThomas Hellstrom return base; 2620b8762e9SThomas Hellstrom } 2630b8762e9SThomas Hellstrom 2640b8762e9SThomas Hellstrom /** 2650b8762e9SThomas Hellstrom * ttm_ref_object_exists - Check whether a caller has a valid ref object 2660b8762e9SThomas Hellstrom * (has opened) a base object. 2670b8762e9SThomas Hellstrom * 2680b8762e9SThomas Hellstrom * @tfile: Pointer to a struct ttm_object_file identifying the caller. 2690b8762e9SThomas Hellstrom * @base: Pointer to a struct base object. 2700b8762e9SThomas Hellstrom * 2710b8762e9SThomas Hellstrom * Checks wether the caller identified by @tfile has put a valid USAGE 2720b8762e9SThomas Hellstrom * reference object on the base object identified by @base. 2730b8762e9SThomas Hellstrom */ 2740b8762e9SThomas Hellstrom bool ttm_ref_object_exists(struct ttm_object_file *tfile, 2750b8762e9SThomas Hellstrom struct ttm_base_object *base) 2760b8762e9SThomas Hellstrom { 2770b8762e9SThomas Hellstrom struct drm_open_hash *ht = &tfile->ref_hash[TTM_REF_USAGE]; 2780b8762e9SThomas Hellstrom struct drm_hash_item *hash; 2790b8762e9SThomas Hellstrom struct ttm_ref_object *ref; 2800b8762e9SThomas Hellstrom 2810b8762e9SThomas Hellstrom rcu_read_lock(); 282c7eae626SThomas Hellstrom if (unlikely(drm_ht_find_item_rcu(ht, base->handle, &hash) != 0)) 2830b8762e9SThomas Hellstrom goto out_false; 2840b8762e9SThomas Hellstrom 2850b8762e9SThomas Hellstrom /* 2860b8762e9SThomas Hellstrom * Verify that the ref object is really pointing to our base object. 2870b8762e9SThomas Hellstrom * Our base object could actually be dead, and the ref object pointing 2880b8762e9SThomas Hellstrom * to another base object with the same handle. 2890b8762e9SThomas Hellstrom */ 2900b8762e9SThomas Hellstrom ref = drm_hash_entry(hash, struct ttm_ref_object, hash); 2910b8762e9SThomas Hellstrom if (unlikely(base != ref->obj)) 2920b8762e9SThomas Hellstrom goto out_false; 2930b8762e9SThomas Hellstrom 2940b8762e9SThomas Hellstrom /* 2950b8762e9SThomas Hellstrom * Verify that the ref->obj pointer was actually valid! 2960b8762e9SThomas Hellstrom */ 2970b8762e9SThomas Hellstrom rmb(); 2980b8762e9SThomas Hellstrom if (unlikely(kref_read(&ref->kref) == 0)) 2990b8762e9SThomas Hellstrom goto out_false; 3000b8762e9SThomas Hellstrom 3010b8762e9SThomas Hellstrom rcu_read_unlock(); 3020b8762e9SThomas Hellstrom return true; 3030b8762e9SThomas Hellstrom 3040b8762e9SThomas Hellstrom out_false: 3050b8762e9SThomas Hellstrom rcu_read_unlock(); 3060b8762e9SThomas Hellstrom return false; 3070b8762e9SThomas Hellstrom } 3080b8762e9SThomas Hellstrom 3090b8762e9SThomas Hellstrom int ttm_ref_object_add(struct ttm_object_file *tfile, 3100b8762e9SThomas Hellstrom struct ttm_base_object *base, 3110b8762e9SThomas Hellstrom enum ttm_ref_type ref_type, bool *existed, 3120b8762e9SThomas Hellstrom bool require_existed) 3130b8762e9SThomas Hellstrom { 3140b8762e9SThomas Hellstrom struct drm_open_hash *ht = &tfile->ref_hash[ref_type]; 3150b8762e9SThomas Hellstrom struct ttm_ref_object *ref; 3160b8762e9SThomas Hellstrom struct drm_hash_item *hash; 3170b8762e9SThomas Hellstrom struct ttm_mem_global *mem_glob = tfile->tdev->mem_glob; 3180b8762e9SThomas Hellstrom struct ttm_operation_ctx ctx = { 3190b8762e9SThomas Hellstrom .interruptible = false, 3200b8762e9SThomas Hellstrom .no_wait_gpu = false 3210b8762e9SThomas Hellstrom }; 3220b8762e9SThomas Hellstrom int ret = -EINVAL; 3230b8762e9SThomas Hellstrom 3240b8762e9SThomas Hellstrom if (base->tfile != tfile && !base->shareable) 3250b8762e9SThomas Hellstrom return -EPERM; 3260b8762e9SThomas Hellstrom 3270b8762e9SThomas Hellstrom if (existed != NULL) 3280b8762e9SThomas Hellstrom *existed = true; 3290b8762e9SThomas Hellstrom 3300b8762e9SThomas Hellstrom while (ret == -EINVAL) { 3310b8762e9SThomas Hellstrom rcu_read_lock(); 332c7eae626SThomas Hellstrom ret = drm_ht_find_item_rcu(ht, base->handle, &hash); 3330b8762e9SThomas Hellstrom 3340b8762e9SThomas Hellstrom if (ret == 0) { 3350b8762e9SThomas Hellstrom ref = drm_hash_entry(hash, struct ttm_ref_object, hash); 3360b8762e9SThomas Hellstrom if (kref_get_unless_zero(&ref->kref)) { 3370b8762e9SThomas Hellstrom rcu_read_unlock(); 3380b8762e9SThomas Hellstrom break; 3390b8762e9SThomas Hellstrom } 3400b8762e9SThomas Hellstrom } 3410b8762e9SThomas Hellstrom 3420b8762e9SThomas Hellstrom rcu_read_unlock(); 3430b8762e9SThomas Hellstrom if (require_existed) 3440b8762e9SThomas Hellstrom return -EPERM; 3450b8762e9SThomas Hellstrom 3460b8762e9SThomas Hellstrom ret = ttm_mem_global_alloc(mem_glob, sizeof(*ref), 3470b8762e9SThomas Hellstrom &ctx); 3480b8762e9SThomas Hellstrom if (unlikely(ret != 0)) 3490b8762e9SThomas Hellstrom return ret; 3500b8762e9SThomas Hellstrom ref = kmalloc(sizeof(*ref), GFP_KERNEL); 3510b8762e9SThomas Hellstrom if (unlikely(ref == NULL)) { 3520b8762e9SThomas Hellstrom ttm_mem_global_free(mem_glob, sizeof(*ref)); 3530b8762e9SThomas Hellstrom return -ENOMEM; 3540b8762e9SThomas Hellstrom } 3550b8762e9SThomas Hellstrom 356c7eae626SThomas Hellstrom ref->hash.key = base->handle; 3570b8762e9SThomas Hellstrom ref->obj = base; 3580b8762e9SThomas Hellstrom ref->tfile = tfile; 3590b8762e9SThomas Hellstrom ref->ref_type = ref_type; 3600b8762e9SThomas Hellstrom kref_init(&ref->kref); 3610b8762e9SThomas Hellstrom 3620b8762e9SThomas Hellstrom spin_lock(&tfile->lock); 3630b8762e9SThomas Hellstrom ret = drm_ht_insert_item_rcu(ht, &ref->hash); 3640b8762e9SThomas Hellstrom 3650b8762e9SThomas Hellstrom if (likely(ret == 0)) { 3660b8762e9SThomas Hellstrom list_add_tail(&ref->head, &tfile->ref_list); 3670b8762e9SThomas Hellstrom kref_get(&base->refcount); 3680b8762e9SThomas Hellstrom spin_unlock(&tfile->lock); 3690b8762e9SThomas Hellstrom if (existed != NULL) 3700b8762e9SThomas Hellstrom *existed = false; 3710b8762e9SThomas Hellstrom break; 3720b8762e9SThomas Hellstrom } 3730b8762e9SThomas Hellstrom 3740b8762e9SThomas Hellstrom spin_unlock(&tfile->lock); 3750b8762e9SThomas Hellstrom BUG_ON(ret != -EINVAL); 3760b8762e9SThomas Hellstrom 3770b8762e9SThomas Hellstrom ttm_mem_global_free(mem_glob, sizeof(*ref)); 3780b8762e9SThomas Hellstrom kfree(ref); 3790b8762e9SThomas Hellstrom } 3800b8762e9SThomas Hellstrom 3810b8762e9SThomas Hellstrom return ret; 3820b8762e9SThomas Hellstrom } 3830b8762e9SThomas Hellstrom 3840b8762e9SThomas Hellstrom static void __releases(tfile->lock) __acquires(tfile->lock) 3850b8762e9SThomas Hellstrom ttm_ref_object_release(struct kref *kref) 3860b8762e9SThomas Hellstrom { 3870b8762e9SThomas Hellstrom struct ttm_ref_object *ref = 3880b8762e9SThomas Hellstrom container_of(kref, struct ttm_ref_object, kref); 3890b8762e9SThomas Hellstrom struct ttm_base_object *base = ref->obj; 3900b8762e9SThomas Hellstrom struct ttm_object_file *tfile = ref->tfile; 3910b8762e9SThomas Hellstrom struct drm_open_hash *ht; 3920b8762e9SThomas Hellstrom struct ttm_mem_global *mem_glob = tfile->tdev->mem_glob; 3930b8762e9SThomas Hellstrom 3940b8762e9SThomas Hellstrom ht = &tfile->ref_hash[ref->ref_type]; 3950b8762e9SThomas Hellstrom (void)drm_ht_remove_item_rcu(ht, &ref->hash); 3960b8762e9SThomas Hellstrom list_del(&ref->head); 3970b8762e9SThomas Hellstrom spin_unlock(&tfile->lock); 3980b8762e9SThomas Hellstrom 3990b8762e9SThomas Hellstrom if (ref->ref_type != TTM_REF_USAGE && base->ref_obj_release) 4000b8762e9SThomas Hellstrom base->ref_obj_release(base, ref->ref_type); 4010b8762e9SThomas Hellstrom 4020b8762e9SThomas Hellstrom ttm_base_object_unref(&ref->obj); 4030b8762e9SThomas Hellstrom ttm_mem_global_free(mem_glob, sizeof(*ref)); 4040b8762e9SThomas Hellstrom kfree_rcu(ref, rcu_head); 4050b8762e9SThomas Hellstrom spin_lock(&tfile->lock); 4060b8762e9SThomas Hellstrom } 4070b8762e9SThomas Hellstrom 4080b8762e9SThomas Hellstrom int ttm_ref_object_base_unref(struct ttm_object_file *tfile, 4090b8762e9SThomas Hellstrom unsigned long key, enum ttm_ref_type ref_type) 4100b8762e9SThomas Hellstrom { 4110b8762e9SThomas Hellstrom struct drm_open_hash *ht = &tfile->ref_hash[ref_type]; 4120b8762e9SThomas Hellstrom struct ttm_ref_object *ref; 4130b8762e9SThomas Hellstrom struct drm_hash_item *hash; 4140b8762e9SThomas Hellstrom int ret; 4150b8762e9SThomas Hellstrom 4160b8762e9SThomas Hellstrom spin_lock(&tfile->lock); 4170b8762e9SThomas Hellstrom ret = drm_ht_find_item(ht, key, &hash); 4180b8762e9SThomas Hellstrom if (unlikely(ret != 0)) { 4190b8762e9SThomas Hellstrom spin_unlock(&tfile->lock); 4200b8762e9SThomas Hellstrom return -EINVAL; 4210b8762e9SThomas Hellstrom } 4220b8762e9SThomas Hellstrom ref = drm_hash_entry(hash, struct ttm_ref_object, hash); 4230b8762e9SThomas Hellstrom kref_put(&ref->kref, ttm_ref_object_release); 4240b8762e9SThomas Hellstrom spin_unlock(&tfile->lock); 4250b8762e9SThomas Hellstrom return 0; 4260b8762e9SThomas Hellstrom } 4270b8762e9SThomas Hellstrom 4280b8762e9SThomas Hellstrom void ttm_object_file_release(struct ttm_object_file **p_tfile) 4290b8762e9SThomas Hellstrom { 4300b8762e9SThomas Hellstrom struct ttm_ref_object *ref; 4310b8762e9SThomas Hellstrom struct list_head *list; 4320b8762e9SThomas Hellstrom unsigned int i; 4330b8762e9SThomas Hellstrom struct ttm_object_file *tfile = *p_tfile; 4340b8762e9SThomas Hellstrom 4350b8762e9SThomas Hellstrom *p_tfile = NULL; 4360b8762e9SThomas Hellstrom spin_lock(&tfile->lock); 4370b8762e9SThomas Hellstrom 4380b8762e9SThomas Hellstrom /* 4390b8762e9SThomas Hellstrom * Since we release the lock within the loop, we have to 4400b8762e9SThomas Hellstrom * restart it from the beginning each time. 4410b8762e9SThomas Hellstrom */ 4420b8762e9SThomas Hellstrom 4430b8762e9SThomas Hellstrom while (!list_empty(&tfile->ref_list)) { 4440b8762e9SThomas Hellstrom list = tfile->ref_list.next; 4450b8762e9SThomas Hellstrom ref = list_entry(list, struct ttm_ref_object, head); 4460b8762e9SThomas Hellstrom ttm_ref_object_release(&ref->kref); 4470b8762e9SThomas Hellstrom } 4480b8762e9SThomas Hellstrom 4490b8762e9SThomas Hellstrom spin_unlock(&tfile->lock); 4500b8762e9SThomas Hellstrom for (i = 0; i < TTM_REF_NUM; ++i) 4510b8762e9SThomas Hellstrom drm_ht_remove(&tfile->ref_hash[i]); 4520b8762e9SThomas Hellstrom 4530b8762e9SThomas Hellstrom ttm_object_file_unref(&tfile); 4540b8762e9SThomas Hellstrom } 4550b8762e9SThomas Hellstrom 4560b8762e9SThomas Hellstrom struct ttm_object_file *ttm_object_file_init(struct ttm_object_device *tdev, 4570b8762e9SThomas Hellstrom unsigned int hash_order) 4580b8762e9SThomas Hellstrom { 4590b8762e9SThomas Hellstrom struct ttm_object_file *tfile = kmalloc(sizeof(*tfile), GFP_KERNEL); 4600b8762e9SThomas Hellstrom unsigned int i; 4610b8762e9SThomas Hellstrom unsigned int j = 0; 4620b8762e9SThomas Hellstrom int ret; 4630b8762e9SThomas Hellstrom 4640b8762e9SThomas Hellstrom if (unlikely(tfile == NULL)) 4650b8762e9SThomas Hellstrom return NULL; 4660b8762e9SThomas Hellstrom 4670b8762e9SThomas Hellstrom spin_lock_init(&tfile->lock); 4680b8762e9SThomas Hellstrom tfile->tdev = tdev; 4690b8762e9SThomas Hellstrom kref_init(&tfile->refcount); 4700b8762e9SThomas Hellstrom INIT_LIST_HEAD(&tfile->ref_list); 4710b8762e9SThomas Hellstrom 4720b8762e9SThomas Hellstrom for (i = 0; i < TTM_REF_NUM; ++i) { 4730b8762e9SThomas Hellstrom ret = drm_ht_create(&tfile->ref_hash[i], hash_order); 4740b8762e9SThomas Hellstrom if (ret) { 4750b8762e9SThomas Hellstrom j = i; 4760b8762e9SThomas Hellstrom goto out_err; 4770b8762e9SThomas Hellstrom } 4780b8762e9SThomas Hellstrom } 4790b8762e9SThomas Hellstrom 4800b8762e9SThomas Hellstrom return tfile; 4810b8762e9SThomas Hellstrom out_err: 4820b8762e9SThomas Hellstrom for (i = 0; i < j; ++i) 4830b8762e9SThomas Hellstrom drm_ht_remove(&tfile->ref_hash[i]); 4840b8762e9SThomas Hellstrom 4850b8762e9SThomas Hellstrom kfree(tfile); 4860b8762e9SThomas Hellstrom 4870b8762e9SThomas Hellstrom return NULL; 4880b8762e9SThomas Hellstrom } 4890b8762e9SThomas Hellstrom 4900b8762e9SThomas Hellstrom struct ttm_object_device * 4910b8762e9SThomas Hellstrom ttm_object_device_init(struct ttm_mem_global *mem_glob, 4920b8762e9SThomas Hellstrom unsigned int hash_order, 4930b8762e9SThomas Hellstrom const struct dma_buf_ops *ops) 4940b8762e9SThomas Hellstrom { 4950b8762e9SThomas Hellstrom struct ttm_object_device *tdev = kmalloc(sizeof(*tdev), GFP_KERNEL); 4960b8762e9SThomas Hellstrom int ret; 4970b8762e9SThomas Hellstrom 4980b8762e9SThomas Hellstrom if (unlikely(tdev == NULL)) 4990b8762e9SThomas Hellstrom return NULL; 5000b8762e9SThomas Hellstrom 5010b8762e9SThomas Hellstrom tdev->mem_glob = mem_glob; 5020b8762e9SThomas Hellstrom spin_lock_init(&tdev->object_lock); 5030b8762e9SThomas Hellstrom atomic_set(&tdev->object_count, 0); 5040b8762e9SThomas Hellstrom ret = drm_ht_create(&tdev->object_hash, hash_order); 5050b8762e9SThomas Hellstrom if (ret != 0) 5060b8762e9SThomas Hellstrom goto out_no_object_hash; 5070b8762e9SThomas Hellstrom 508c7eae626SThomas Hellstrom idr_init(&tdev->idr); 5090b8762e9SThomas Hellstrom tdev->ops = *ops; 5100b8762e9SThomas Hellstrom tdev->dmabuf_release = tdev->ops.release; 5110b8762e9SThomas Hellstrom tdev->ops.release = ttm_prime_dmabuf_release; 5120b8762e9SThomas Hellstrom tdev->dma_buf_size = ttm_round_pot(sizeof(struct dma_buf)) + 5130b8762e9SThomas Hellstrom ttm_round_pot(sizeof(struct file)); 5140b8762e9SThomas Hellstrom return tdev; 5150b8762e9SThomas Hellstrom 5160b8762e9SThomas Hellstrom out_no_object_hash: 5170b8762e9SThomas Hellstrom kfree(tdev); 5180b8762e9SThomas Hellstrom return NULL; 5190b8762e9SThomas Hellstrom } 5200b8762e9SThomas Hellstrom 5210b8762e9SThomas Hellstrom void ttm_object_device_release(struct ttm_object_device **p_tdev) 5220b8762e9SThomas Hellstrom { 5230b8762e9SThomas Hellstrom struct ttm_object_device *tdev = *p_tdev; 5240b8762e9SThomas Hellstrom 5250b8762e9SThomas Hellstrom *p_tdev = NULL; 5260b8762e9SThomas Hellstrom 527c7eae626SThomas Hellstrom WARN_ON_ONCE(!idr_is_empty(&tdev->idr)); 528c7eae626SThomas Hellstrom idr_destroy(&tdev->idr); 5290b8762e9SThomas Hellstrom drm_ht_remove(&tdev->object_hash); 5300b8762e9SThomas Hellstrom 5310b8762e9SThomas Hellstrom kfree(tdev); 5320b8762e9SThomas Hellstrom } 5330b8762e9SThomas Hellstrom 5340b8762e9SThomas Hellstrom /** 5350b8762e9SThomas Hellstrom * get_dma_buf_unless_doomed - get a dma_buf reference if possible. 5360b8762e9SThomas Hellstrom * 5370b8762e9SThomas Hellstrom * @dma_buf: Non-refcounted pointer to a struct dma-buf. 5380b8762e9SThomas Hellstrom * 5390b8762e9SThomas Hellstrom * Obtain a file reference from a lookup structure that doesn't refcount 5400b8762e9SThomas Hellstrom * the file, but synchronizes with its release method to make sure it has 5410b8762e9SThomas Hellstrom * not been freed yet. See for example kref_get_unless_zero documentation. 5420b8762e9SThomas Hellstrom * Returns true if refcounting succeeds, false otherwise. 5430b8762e9SThomas Hellstrom * 5440b8762e9SThomas Hellstrom * Nobody really wants this as a public API yet, so let it mature here 5450b8762e9SThomas Hellstrom * for some time... 5460b8762e9SThomas Hellstrom */ 5470b8762e9SThomas Hellstrom static bool __must_check get_dma_buf_unless_doomed(struct dma_buf *dmabuf) 5480b8762e9SThomas Hellstrom { 5490b8762e9SThomas Hellstrom return atomic_long_inc_not_zero(&dmabuf->file->f_count) != 0L; 5500b8762e9SThomas Hellstrom } 5510b8762e9SThomas Hellstrom 5520b8762e9SThomas Hellstrom /** 5530b8762e9SThomas Hellstrom * ttm_prime_refcount_release - refcount release method for a prime object. 5540b8762e9SThomas Hellstrom * 5550b8762e9SThomas Hellstrom * @p_base: Pointer to ttm_base_object pointer. 5560b8762e9SThomas Hellstrom * 5570b8762e9SThomas Hellstrom * This is a wrapper that calls the refcount_release founction of the 5580b8762e9SThomas Hellstrom * underlying object. At the same time it cleans up the prime object. 5590b8762e9SThomas Hellstrom * This function is called when all references to the base object we 5600b8762e9SThomas Hellstrom * derive from are gone. 5610b8762e9SThomas Hellstrom */ 5620b8762e9SThomas Hellstrom static void ttm_prime_refcount_release(struct ttm_base_object **p_base) 5630b8762e9SThomas Hellstrom { 5640b8762e9SThomas Hellstrom struct ttm_base_object *base = *p_base; 5650b8762e9SThomas Hellstrom struct ttm_prime_object *prime; 5660b8762e9SThomas Hellstrom 5670b8762e9SThomas Hellstrom *p_base = NULL; 5680b8762e9SThomas Hellstrom prime = container_of(base, struct ttm_prime_object, base); 5690b8762e9SThomas Hellstrom BUG_ON(prime->dma_buf != NULL); 5700b8762e9SThomas Hellstrom mutex_destroy(&prime->mutex); 5710b8762e9SThomas Hellstrom if (prime->refcount_release) 5720b8762e9SThomas Hellstrom prime->refcount_release(&base); 5730b8762e9SThomas Hellstrom } 5740b8762e9SThomas Hellstrom 5750b8762e9SThomas Hellstrom /** 5760b8762e9SThomas Hellstrom * ttm_prime_dmabuf_release - Release method for the dma-bufs we export 5770b8762e9SThomas Hellstrom * 5780b8762e9SThomas Hellstrom * @dma_buf: 5790b8762e9SThomas Hellstrom * 5800b8762e9SThomas Hellstrom * This function first calls the dma_buf release method the driver 5810b8762e9SThomas Hellstrom * provides. Then it cleans up our dma_buf pointer used for lookup, 5820b8762e9SThomas Hellstrom * and finally releases the reference the dma_buf has on our base 5830b8762e9SThomas Hellstrom * object. 5840b8762e9SThomas Hellstrom */ 5850b8762e9SThomas Hellstrom static void ttm_prime_dmabuf_release(struct dma_buf *dma_buf) 5860b8762e9SThomas Hellstrom { 5870b8762e9SThomas Hellstrom struct ttm_prime_object *prime = 5880b8762e9SThomas Hellstrom (struct ttm_prime_object *) dma_buf->priv; 5890b8762e9SThomas Hellstrom struct ttm_base_object *base = &prime->base; 5900b8762e9SThomas Hellstrom struct ttm_object_device *tdev = base->tfile->tdev; 5910b8762e9SThomas Hellstrom 5920b8762e9SThomas Hellstrom if (tdev->dmabuf_release) 5930b8762e9SThomas Hellstrom tdev->dmabuf_release(dma_buf); 5940b8762e9SThomas Hellstrom mutex_lock(&prime->mutex); 5950b8762e9SThomas Hellstrom if (prime->dma_buf == dma_buf) 5960b8762e9SThomas Hellstrom prime->dma_buf = NULL; 5970b8762e9SThomas Hellstrom mutex_unlock(&prime->mutex); 5980b8762e9SThomas Hellstrom ttm_mem_global_free(tdev->mem_glob, tdev->dma_buf_size); 5990b8762e9SThomas Hellstrom ttm_base_object_unref(&base); 6000b8762e9SThomas Hellstrom } 6010b8762e9SThomas Hellstrom 6020b8762e9SThomas Hellstrom /** 6030b8762e9SThomas Hellstrom * ttm_prime_fd_to_handle - Get a base object handle from a prime fd 6040b8762e9SThomas Hellstrom * 6050b8762e9SThomas Hellstrom * @tfile: A struct ttm_object_file identifying the caller. 6060b8762e9SThomas Hellstrom * @fd: The prime / dmabuf fd. 6070b8762e9SThomas Hellstrom * @handle: The returned handle. 6080b8762e9SThomas Hellstrom * 6090b8762e9SThomas Hellstrom * This function returns a handle to an object that previously exported 6100b8762e9SThomas Hellstrom * a dma-buf. Note that we don't handle imports yet, because we simply 6110b8762e9SThomas Hellstrom * have no consumers of that implementation. 6120b8762e9SThomas Hellstrom */ 6130b8762e9SThomas Hellstrom int ttm_prime_fd_to_handle(struct ttm_object_file *tfile, 6140b8762e9SThomas Hellstrom int fd, u32 *handle) 6150b8762e9SThomas Hellstrom { 6160b8762e9SThomas Hellstrom struct ttm_object_device *tdev = tfile->tdev; 6170b8762e9SThomas Hellstrom struct dma_buf *dma_buf; 6180b8762e9SThomas Hellstrom struct ttm_prime_object *prime; 6190b8762e9SThomas Hellstrom struct ttm_base_object *base; 6200b8762e9SThomas Hellstrom int ret; 6210b8762e9SThomas Hellstrom 6220b8762e9SThomas Hellstrom dma_buf = dma_buf_get(fd); 6230b8762e9SThomas Hellstrom if (IS_ERR(dma_buf)) 6240b8762e9SThomas Hellstrom return PTR_ERR(dma_buf); 6250b8762e9SThomas Hellstrom 6260b8762e9SThomas Hellstrom if (dma_buf->ops != &tdev->ops) 6270b8762e9SThomas Hellstrom return -ENOSYS; 6280b8762e9SThomas Hellstrom 6290b8762e9SThomas Hellstrom prime = (struct ttm_prime_object *) dma_buf->priv; 6300b8762e9SThomas Hellstrom base = &prime->base; 631c7eae626SThomas Hellstrom *handle = base->handle; 6320b8762e9SThomas Hellstrom ret = ttm_ref_object_add(tfile, base, TTM_REF_USAGE, NULL, false); 6330b8762e9SThomas Hellstrom 6340b8762e9SThomas Hellstrom dma_buf_put(dma_buf); 6350b8762e9SThomas Hellstrom 6360b8762e9SThomas Hellstrom return ret; 6370b8762e9SThomas Hellstrom } 6380b8762e9SThomas Hellstrom 6390b8762e9SThomas Hellstrom /** 6400b8762e9SThomas Hellstrom * ttm_prime_handle_to_fd - Return a dma_buf fd from a ttm prime object 6410b8762e9SThomas Hellstrom * 6420b8762e9SThomas Hellstrom * @tfile: Struct ttm_object_file identifying the caller. 6430b8762e9SThomas Hellstrom * @handle: Handle to the object we're exporting from. 6440b8762e9SThomas Hellstrom * @flags: flags for dma-buf creation. We just pass them on. 6450b8762e9SThomas Hellstrom * @prime_fd: The returned file descriptor. 6460b8762e9SThomas Hellstrom * 6470b8762e9SThomas Hellstrom */ 6480b8762e9SThomas Hellstrom int ttm_prime_handle_to_fd(struct ttm_object_file *tfile, 6490b8762e9SThomas Hellstrom uint32_t handle, uint32_t flags, 6500b8762e9SThomas Hellstrom int *prime_fd) 6510b8762e9SThomas Hellstrom { 6520b8762e9SThomas Hellstrom struct ttm_object_device *tdev = tfile->tdev; 6530b8762e9SThomas Hellstrom struct ttm_base_object *base; 6540b8762e9SThomas Hellstrom struct dma_buf *dma_buf; 6550b8762e9SThomas Hellstrom struct ttm_prime_object *prime; 6560b8762e9SThomas Hellstrom int ret; 6570b8762e9SThomas Hellstrom 6580b8762e9SThomas Hellstrom base = ttm_base_object_lookup(tfile, handle); 6590b8762e9SThomas Hellstrom if (unlikely(base == NULL || 6600b8762e9SThomas Hellstrom base->object_type != ttm_prime_type)) { 6610b8762e9SThomas Hellstrom ret = -ENOENT; 6620b8762e9SThomas Hellstrom goto out_unref; 6630b8762e9SThomas Hellstrom } 6640b8762e9SThomas Hellstrom 6650b8762e9SThomas Hellstrom prime = container_of(base, struct ttm_prime_object, base); 6660b8762e9SThomas Hellstrom if (unlikely(!base->shareable)) { 6670b8762e9SThomas Hellstrom ret = -EPERM; 6680b8762e9SThomas Hellstrom goto out_unref; 6690b8762e9SThomas Hellstrom } 6700b8762e9SThomas Hellstrom 6710b8762e9SThomas Hellstrom ret = mutex_lock_interruptible(&prime->mutex); 6720b8762e9SThomas Hellstrom if (unlikely(ret != 0)) { 6730b8762e9SThomas Hellstrom ret = -ERESTARTSYS; 6740b8762e9SThomas Hellstrom goto out_unref; 6750b8762e9SThomas Hellstrom } 6760b8762e9SThomas Hellstrom 6770b8762e9SThomas Hellstrom dma_buf = prime->dma_buf; 6780b8762e9SThomas Hellstrom if (!dma_buf || !get_dma_buf_unless_doomed(dma_buf)) { 6790b8762e9SThomas Hellstrom DEFINE_DMA_BUF_EXPORT_INFO(exp_info); 6800b8762e9SThomas Hellstrom struct ttm_operation_ctx ctx = { 6810b8762e9SThomas Hellstrom .interruptible = true, 6820b8762e9SThomas Hellstrom .no_wait_gpu = false 6830b8762e9SThomas Hellstrom }; 6840b8762e9SThomas Hellstrom exp_info.ops = &tdev->ops; 6850b8762e9SThomas Hellstrom exp_info.size = prime->size; 6860b8762e9SThomas Hellstrom exp_info.flags = flags; 6870b8762e9SThomas Hellstrom exp_info.priv = prime; 6880b8762e9SThomas Hellstrom 6890b8762e9SThomas Hellstrom /* 6900b8762e9SThomas Hellstrom * Need to create a new dma_buf, with memory accounting. 6910b8762e9SThomas Hellstrom */ 6920b8762e9SThomas Hellstrom ret = ttm_mem_global_alloc(tdev->mem_glob, tdev->dma_buf_size, 6930b8762e9SThomas Hellstrom &ctx); 6940b8762e9SThomas Hellstrom if (unlikely(ret != 0)) { 6950b8762e9SThomas Hellstrom mutex_unlock(&prime->mutex); 6960b8762e9SThomas Hellstrom goto out_unref; 6970b8762e9SThomas Hellstrom } 6980b8762e9SThomas Hellstrom 6990b8762e9SThomas Hellstrom dma_buf = dma_buf_export(&exp_info); 7000b8762e9SThomas Hellstrom if (IS_ERR(dma_buf)) { 7010b8762e9SThomas Hellstrom ret = PTR_ERR(dma_buf); 7020b8762e9SThomas Hellstrom ttm_mem_global_free(tdev->mem_glob, 7030b8762e9SThomas Hellstrom tdev->dma_buf_size); 7040b8762e9SThomas Hellstrom mutex_unlock(&prime->mutex); 7050b8762e9SThomas Hellstrom goto out_unref; 7060b8762e9SThomas Hellstrom } 7070b8762e9SThomas Hellstrom 7080b8762e9SThomas Hellstrom /* 7090b8762e9SThomas Hellstrom * dma_buf has taken the base object reference 7100b8762e9SThomas Hellstrom */ 7110b8762e9SThomas Hellstrom base = NULL; 7120b8762e9SThomas Hellstrom prime->dma_buf = dma_buf; 7130b8762e9SThomas Hellstrom } 7140b8762e9SThomas Hellstrom mutex_unlock(&prime->mutex); 7150b8762e9SThomas Hellstrom 7160b8762e9SThomas Hellstrom ret = dma_buf_fd(dma_buf, flags); 7170b8762e9SThomas Hellstrom if (ret >= 0) { 7180b8762e9SThomas Hellstrom *prime_fd = ret; 7190b8762e9SThomas Hellstrom ret = 0; 7200b8762e9SThomas Hellstrom } else 7210b8762e9SThomas Hellstrom dma_buf_put(dma_buf); 7220b8762e9SThomas Hellstrom 7230b8762e9SThomas Hellstrom out_unref: 7240b8762e9SThomas Hellstrom if (base) 7250b8762e9SThomas Hellstrom ttm_base_object_unref(&base); 7260b8762e9SThomas Hellstrom return ret; 7270b8762e9SThomas Hellstrom } 7280b8762e9SThomas Hellstrom 7290b8762e9SThomas Hellstrom /** 7300b8762e9SThomas Hellstrom * ttm_prime_object_init - Initialize a ttm_prime_object 7310b8762e9SThomas Hellstrom * 7320b8762e9SThomas Hellstrom * @tfile: struct ttm_object_file identifying the caller 7330b8762e9SThomas Hellstrom * @size: The size of the dma_bufs we export. 7340b8762e9SThomas Hellstrom * @prime: The object to be initialized. 7350b8762e9SThomas Hellstrom * @shareable: See ttm_base_object_init 7360b8762e9SThomas Hellstrom * @type: See ttm_base_object_init 7370b8762e9SThomas Hellstrom * @refcount_release: See ttm_base_object_init 7380b8762e9SThomas Hellstrom * @ref_obj_release: See ttm_base_object_init 7390b8762e9SThomas Hellstrom * 7400b8762e9SThomas Hellstrom * Initializes an object which is compatible with the drm_prime model 7410b8762e9SThomas Hellstrom * for data sharing between processes and devices. 7420b8762e9SThomas Hellstrom */ 7430b8762e9SThomas Hellstrom int ttm_prime_object_init(struct ttm_object_file *tfile, size_t size, 7440b8762e9SThomas Hellstrom struct ttm_prime_object *prime, bool shareable, 7450b8762e9SThomas Hellstrom enum ttm_object_type type, 7460b8762e9SThomas Hellstrom void (*refcount_release) (struct ttm_base_object **), 7470b8762e9SThomas Hellstrom void (*ref_obj_release) (struct ttm_base_object *, 7480b8762e9SThomas Hellstrom enum ttm_ref_type ref_type)) 7490b8762e9SThomas Hellstrom { 7500b8762e9SThomas Hellstrom mutex_init(&prime->mutex); 7510b8762e9SThomas Hellstrom prime->size = PAGE_ALIGN(size); 7520b8762e9SThomas Hellstrom prime->real_type = type; 7530b8762e9SThomas Hellstrom prime->dma_buf = NULL; 7540b8762e9SThomas Hellstrom prime->refcount_release = refcount_release; 7550b8762e9SThomas Hellstrom return ttm_base_object_init(tfile, &prime->base, shareable, 7560b8762e9SThomas Hellstrom ttm_prime_type, 7570b8762e9SThomas Hellstrom ttm_prime_refcount_release, 7580b8762e9SThomas Hellstrom ref_obj_release); 7590b8762e9SThomas Hellstrom } 760