1592ffb21SWarner Losh /************************************************************************** 2592ffb21SWarner Losh * 3592ffb21SWarner Losh * Copyright (c) 2009 VMware, Inc., Palo Alto, CA., USA 4592ffb21SWarner Losh * All Rights Reserved. 5592ffb21SWarner Losh * 6592ffb21SWarner Losh * Permission is hereby granted, free of charge, to any person obtaining a 7592ffb21SWarner Losh * copy of this software and associated documentation files (the 8592ffb21SWarner Losh * "Software"), to deal in the Software without restriction, including 9592ffb21SWarner Losh * without limitation the rights to use, copy, modify, merge, publish, 10592ffb21SWarner Losh * distribute, sub license, and/or sell copies of the Software, and to 11592ffb21SWarner Losh * permit persons to whom the Software is furnished to do so, subject to 12592ffb21SWarner Losh * the following conditions: 13592ffb21SWarner Losh * 14592ffb21SWarner Losh * The above copyright notice and this permission notice (including the 15592ffb21SWarner Losh * next paragraph) shall be included in all copies or substantial portions 16592ffb21SWarner Losh * of the Software. 17592ffb21SWarner Losh * 18592ffb21SWarner Losh * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19592ffb21SWarner Losh * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20592ffb21SWarner Losh * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 21592ffb21SWarner Losh * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 22592ffb21SWarner Losh * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 23592ffb21SWarner Losh * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 24592ffb21SWarner Losh * USE OR OTHER DEALINGS IN THE SOFTWARE. 25592ffb21SWarner Losh * 26592ffb21SWarner Losh **************************************************************************/ 27592ffb21SWarner Losh /* 28592ffb21SWarner Losh * Authors: Thomas Hellstrom <thellstrom-at-vmware-dot-com> 29592ffb21SWarner Losh */ 30592ffb21SWarner Losh /** @file ttm_ref_object.c 31592ffb21SWarner Losh * 32592ffb21SWarner Losh * Base- and reference object implementation for the various 33592ffb21SWarner Losh * ttm objects. Implements reference counting, minimal security checks 34592ffb21SWarner Losh * and release on file close. 35592ffb21SWarner Losh */ 36592ffb21SWarner Losh 37592ffb21SWarner Losh 38592ffb21SWarner Losh #include <sys/cdefs.h> 39592ffb21SWarner Losh __FBSDID("$FreeBSD$"); 40592ffb21SWarner Losh 41592ffb21SWarner Losh /** 42592ffb21SWarner Losh * struct ttm_object_file 43592ffb21SWarner Losh * 44592ffb21SWarner Losh * @tdev: Pointer to the ttm_object_device. 45592ffb21SWarner Losh * 46592ffb21SWarner Losh * @lock: Lock that protects the ref_list list and the 47592ffb21SWarner Losh * ref_hash hash tables. 48592ffb21SWarner Losh * 49592ffb21SWarner Losh * @ref_list: List of ttm_ref_objects to be destroyed at 50592ffb21SWarner Losh * file release. 51592ffb21SWarner Losh * 52592ffb21SWarner Losh * @ref_hash: Hash tables of ref objects, one per ttm_ref_type, 53592ffb21SWarner Losh * for fast lookup of ref objects given a base object. 54592ffb21SWarner Losh */ 55592ffb21SWarner Losh 56592ffb21SWarner Losh #define pr_fmt(fmt) "[TTM] " fmt 57592ffb21SWarner Losh 58592ffb21SWarner Losh #include <dev/drm2/drmP.h> 59592ffb21SWarner Losh #include <dev/drm2/drm.h> 60592ffb21SWarner Losh #include <sys/rwlock.h> 61592ffb21SWarner Losh #include <dev/drm2/ttm/ttm_object.h> 62592ffb21SWarner Losh #include <dev/drm2/ttm/ttm_module.h> 63592ffb21SWarner Losh 64592ffb21SWarner Losh struct ttm_object_file { 65592ffb21SWarner Losh struct ttm_object_device *tdev; 66592ffb21SWarner Losh struct rwlock lock; 67592ffb21SWarner Losh struct list_head ref_list; 68592ffb21SWarner Losh struct drm_open_hash ref_hash[TTM_REF_NUM]; 69592ffb21SWarner Losh u_int refcount; 70592ffb21SWarner Losh }; 71592ffb21SWarner Losh 72592ffb21SWarner Losh /** 73592ffb21SWarner Losh * struct ttm_object_device 74592ffb21SWarner Losh * 75592ffb21SWarner Losh * @object_lock: lock that protects the object_hash hash table. 76592ffb21SWarner Losh * 77592ffb21SWarner Losh * @object_hash: hash table for fast lookup of object global names. 78592ffb21SWarner Losh * 79592ffb21SWarner Losh * @object_count: Per device object count. 80592ffb21SWarner Losh * 81592ffb21SWarner Losh * This is the per-device data structure needed for ttm object management. 82592ffb21SWarner Losh */ 83592ffb21SWarner Losh 84592ffb21SWarner Losh struct ttm_object_device { 85592ffb21SWarner Losh struct rwlock object_lock; 86592ffb21SWarner Losh struct drm_open_hash object_hash; 87592ffb21SWarner Losh atomic_t object_count; 88592ffb21SWarner Losh struct ttm_mem_global *mem_glob; 89592ffb21SWarner Losh }; 90592ffb21SWarner Losh 91592ffb21SWarner Losh /** 92592ffb21SWarner Losh * struct ttm_ref_object 93592ffb21SWarner Losh * 94592ffb21SWarner Losh * @hash: Hash entry for the per-file object reference hash. 95592ffb21SWarner Losh * 96592ffb21SWarner Losh * @head: List entry for the per-file list of ref-objects. 97592ffb21SWarner Losh * 98592ffb21SWarner Losh * @kref: Ref count. 99592ffb21SWarner Losh * 100592ffb21SWarner Losh * @obj: Base object this ref object is referencing. 101592ffb21SWarner Losh * 102592ffb21SWarner Losh * @ref_type: Type of ref object. 103592ffb21SWarner Losh * 104592ffb21SWarner Losh * This is similar to an idr object, but it also has a hash table entry 105592ffb21SWarner Losh * that allows lookup with a pointer to the referenced object as a key. In 106592ffb21SWarner Losh * that way, one can easily detect whether a base object is referenced by 107592ffb21SWarner Losh * a particular ttm_object_file. It also carries a ref count to avoid creating 108592ffb21SWarner Losh * multiple ref objects if a ttm_object_file references the same base 109592ffb21SWarner Losh * object more than once. 110592ffb21SWarner Losh */ 111592ffb21SWarner Losh 112592ffb21SWarner Losh struct ttm_ref_object { 113592ffb21SWarner Losh struct drm_hash_item hash; 114592ffb21SWarner Losh struct list_head head; 115592ffb21SWarner Losh u_int kref; 116592ffb21SWarner Losh enum ttm_ref_type ref_type; 117592ffb21SWarner Losh struct ttm_base_object *obj; 118592ffb21SWarner Losh struct ttm_object_file *tfile; 119592ffb21SWarner Losh }; 120592ffb21SWarner Losh 121592ffb21SWarner Losh MALLOC_DEFINE(M_TTM_OBJ_FILE, "ttm_obj_file", "TTM File Objects"); 122592ffb21SWarner Losh 123592ffb21SWarner Losh static inline struct ttm_object_file * 124592ffb21SWarner Losh ttm_object_file_ref(struct ttm_object_file *tfile) 125592ffb21SWarner Losh { 126592ffb21SWarner Losh refcount_acquire(&tfile->refcount); 127592ffb21SWarner Losh return tfile; 128592ffb21SWarner Losh } 129592ffb21SWarner Losh 130592ffb21SWarner Losh static void ttm_object_file_destroy(struct ttm_object_file *tfile) 131592ffb21SWarner Losh { 132592ffb21SWarner Losh 133592ffb21SWarner Losh free(tfile, M_TTM_OBJ_FILE); 134592ffb21SWarner Losh } 135592ffb21SWarner Losh 136592ffb21SWarner Losh 137592ffb21SWarner Losh static inline void ttm_object_file_unref(struct ttm_object_file **p_tfile) 138592ffb21SWarner Losh { 139592ffb21SWarner Losh struct ttm_object_file *tfile = *p_tfile; 140592ffb21SWarner Losh 141592ffb21SWarner Losh *p_tfile = NULL; 142592ffb21SWarner Losh if (refcount_release(&tfile->refcount)) 143592ffb21SWarner Losh ttm_object_file_destroy(tfile); 144592ffb21SWarner Losh } 145592ffb21SWarner Losh 146592ffb21SWarner Losh 147592ffb21SWarner Losh int ttm_base_object_init(struct ttm_object_file *tfile, 148592ffb21SWarner Losh struct ttm_base_object *base, 149592ffb21SWarner Losh bool shareable, 150592ffb21SWarner Losh enum ttm_object_type object_type, 151592ffb21SWarner Losh void (*rcount_release) (struct ttm_base_object **), 152592ffb21SWarner Losh void (*ref_obj_release) (struct ttm_base_object *, 153592ffb21SWarner Losh enum ttm_ref_type ref_type)) 154592ffb21SWarner Losh { 155592ffb21SWarner Losh struct ttm_object_device *tdev = tfile->tdev; 156592ffb21SWarner Losh int ret; 157592ffb21SWarner Losh 158592ffb21SWarner Losh base->shareable = shareable; 159592ffb21SWarner Losh base->tfile = ttm_object_file_ref(tfile); 160592ffb21SWarner Losh base->refcount_release = rcount_release; 161592ffb21SWarner Losh base->ref_obj_release = ref_obj_release; 162592ffb21SWarner Losh base->object_type = object_type; 163592ffb21SWarner Losh refcount_init(&base->refcount, 1); 164592ffb21SWarner Losh rw_init(&tdev->object_lock, "ttmbao"); 165592ffb21SWarner Losh rw_wlock(&tdev->object_lock); 166592ffb21SWarner Losh ret = drm_ht_just_insert_please(&tdev->object_hash, 167592ffb21SWarner Losh &base->hash, 168592ffb21SWarner Losh (unsigned long)base, 31, 0, 0); 169592ffb21SWarner Losh rw_wunlock(&tdev->object_lock); 170592ffb21SWarner Losh if (unlikely(ret != 0)) 171592ffb21SWarner Losh goto out_err0; 172592ffb21SWarner Losh 173592ffb21SWarner Losh ret = ttm_ref_object_add(tfile, base, TTM_REF_USAGE, NULL); 174592ffb21SWarner Losh if (unlikely(ret != 0)) 175592ffb21SWarner Losh goto out_err1; 176592ffb21SWarner Losh 177592ffb21SWarner Losh ttm_base_object_unref(&base); 178592ffb21SWarner Losh 179592ffb21SWarner Losh return 0; 180592ffb21SWarner Losh out_err1: 181592ffb21SWarner Losh rw_wlock(&tdev->object_lock); 182592ffb21SWarner Losh (void)drm_ht_remove_item(&tdev->object_hash, &base->hash); 183592ffb21SWarner Losh rw_wunlock(&tdev->object_lock); 184592ffb21SWarner Losh out_err0: 185592ffb21SWarner Losh return ret; 186592ffb21SWarner Losh } 187592ffb21SWarner Losh 188592ffb21SWarner Losh static void ttm_release_base(struct ttm_base_object *base) 189592ffb21SWarner Losh { 190592ffb21SWarner Losh struct ttm_object_device *tdev = base->tfile->tdev; 191592ffb21SWarner Losh 192592ffb21SWarner Losh (void)drm_ht_remove_item(&tdev->object_hash, &base->hash); 193592ffb21SWarner Losh rw_wunlock(&tdev->object_lock); 194592ffb21SWarner Losh /* 195592ffb21SWarner Losh * Note: We don't use synchronize_rcu() here because it's far 196592ffb21SWarner Losh * too slow. It's up to the user to free the object using 197592ffb21SWarner Losh * call_rcu() or ttm_base_object_kfree(). 198592ffb21SWarner Losh */ 199592ffb21SWarner Losh 200592ffb21SWarner Losh if (base->refcount_release) { 201592ffb21SWarner Losh ttm_object_file_unref(&base->tfile); 202592ffb21SWarner Losh base->refcount_release(&base); 203592ffb21SWarner Losh } 204592ffb21SWarner Losh rw_wlock(&tdev->object_lock); 205592ffb21SWarner Losh } 206592ffb21SWarner Losh 207592ffb21SWarner Losh void ttm_base_object_unref(struct ttm_base_object **p_base) 208592ffb21SWarner Losh { 209592ffb21SWarner Losh struct ttm_base_object *base = *p_base; 210592ffb21SWarner Losh struct ttm_object_device *tdev = base->tfile->tdev; 211592ffb21SWarner Losh 212592ffb21SWarner Losh *p_base = NULL; 213592ffb21SWarner Losh 214592ffb21SWarner Losh /* 215592ffb21SWarner Losh * Need to take the lock here to avoid racing with 216592ffb21SWarner Losh * users trying to look up the object. 217592ffb21SWarner Losh */ 218592ffb21SWarner Losh 219592ffb21SWarner Losh rw_wlock(&tdev->object_lock); 220592ffb21SWarner Losh if (refcount_release(&base->refcount)) 221592ffb21SWarner Losh ttm_release_base(base); 222592ffb21SWarner Losh rw_wunlock(&tdev->object_lock); 223592ffb21SWarner Losh } 224592ffb21SWarner Losh 225592ffb21SWarner Losh struct ttm_base_object *ttm_base_object_lookup(struct ttm_object_file *tfile, 226592ffb21SWarner Losh uint32_t key) 227592ffb21SWarner Losh { 228592ffb21SWarner Losh struct ttm_object_device *tdev = tfile->tdev; 229592ffb21SWarner Losh struct ttm_base_object *base; 230592ffb21SWarner Losh struct drm_hash_item *hash; 231592ffb21SWarner Losh int ret; 232592ffb21SWarner Losh 233592ffb21SWarner Losh rw_rlock(&tdev->object_lock); 234592ffb21SWarner Losh ret = drm_ht_find_item(&tdev->object_hash, key, &hash); 235592ffb21SWarner Losh 236592ffb21SWarner Losh if (ret == 0) { 237592ffb21SWarner Losh base = drm_hash_entry(hash, struct ttm_base_object, hash); 238592ffb21SWarner Losh refcount_acquire(&base->refcount); 239592ffb21SWarner Losh } 240592ffb21SWarner Losh rw_runlock(&tdev->object_lock); 241592ffb21SWarner Losh 242592ffb21SWarner Losh if (unlikely(ret != 0)) 243592ffb21SWarner Losh return NULL; 244592ffb21SWarner Losh 245592ffb21SWarner Losh if (tfile != base->tfile && !base->shareable) { 246592ffb21SWarner Losh printf("[TTM] Attempted access of non-shareable object %p\n", 247592ffb21SWarner Losh base); 248592ffb21SWarner Losh ttm_base_object_unref(&base); 249592ffb21SWarner Losh return NULL; 250592ffb21SWarner Losh } 251592ffb21SWarner Losh 252592ffb21SWarner Losh return base; 253592ffb21SWarner Losh } 254592ffb21SWarner Losh 255592ffb21SWarner Losh MALLOC_DEFINE(M_TTM_OBJ_REF, "ttm_obj_ref", "TTM Ref Objects"); 256592ffb21SWarner Losh 257592ffb21SWarner Losh int ttm_ref_object_add(struct ttm_object_file *tfile, 258592ffb21SWarner Losh struct ttm_base_object *base, 259592ffb21SWarner Losh enum ttm_ref_type ref_type, bool *existed) 260592ffb21SWarner Losh { 261592ffb21SWarner Losh struct drm_open_hash *ht = &tfile->ref_hash[ref_type]; 262592ffb21SWarner Losh struct ttm_ref_object *ref; 263592ffb21SWarner Losh struct drm_hash_item *hash; 264592ffb21SWarner Losh struct ttm_mem_global *mem_glob = tfile->tdev->mem_glob; 265592ffb21SWarner Losh int ret = -EINVAL; 266592ffb21SWarner Losh 267592ffb21SWarner Losh if (existed != NULL) 268592ffb21SWarner Losh *existed = true; 269592ffb21SWarner Losh 270592ffb21SWarner Losh while (ret == -EINVAL) { 271592ffb21SWarner Losh rw_rlock(&tfile->lock); 272592ffb21SWarner Losh ret = drm_ht_find_item(ht, base->hash.key, &hash); 273592ffb21SWarner Losh 274592ffb21SWarner Losh if (ret == 0) { 275592ffb21SWarner Losh ref = drm_hash_entry(hash, struct ttm_ref_object, hash); 276592ffb21SWarner Losh refcount_acquire(&ref->kref); 277592ffb21SWarner Losh rw_runlock(&tfile->lock); 278592ffb21SWarner Losh break; 279592ffb21SWarner Losh } 280592ffb21SWarner Losh 281592ffb21SWarner Losh rw_runlock(&tfile->lock); 282592ffb21SWarner Losh ret = ttm_mem_global_alloc(mem_glob, sizeof(*ref), 283592ffb21SWarner Losh false, false); 284592ffb21SWarner Losh if (unlikely(ret != 0)) 285592ffb21SWarner Losh return ret; 286592ffb21SWarner Losh ref = malloc(sizeof(*ref), M_TTM_OBJ_REF, M_WAITOK); 287592ffb21SWarner Losh if (unlikely(ref == NULL)) { 288592ffb21SWarner Losh ttm_mem_global_free(mem_glob, sizeof(*ref)); 289592ffb21SWarner Losh return -ENOMEM; 290592ffb21SWarner Losh } 291592ffb21SWarner Losh 292592ffb21SWarner Losh ref->hash.key = base->hash.key; 293592ffb21SWarner Losh ref->obj = base; 294592ffb21SWarner Losh ref->tfile = tfile; 295592ffb21SWarner Losh ref->ref_type = ref_type; 296592ffb21SWarner Losh refcount_init(&ref->kref, 1); 297592ffb21SWarner Losh 298592ffb21SWarner Losh rw_wlock(&tfile->lock); 299592ffb21SWarner Losh ret = drm_ht_insert_item(ht, &ref->hash); 300592ffb21SWarner Losh 301592ffb21SWarner Losh if (ret == 0) { 302592ffb21SWarner Losh list_add_tail(&ref->head, &tfile->ref_list); 303592ffb21SWarner Losh refcount_acquire(&base->refcount); 304592ffb21SWarner Losh rw_wunlock(&tfile->lock); 305592ffb21SWarner Losh if (existed != NULL) 306592ffb21SWarner Losh *existed = false; 307592ffb21SWarner Losh break; 308592ffb21SWarner Losh } 309592ffb21SWarner Losh 310592ffb21SWarner Losh rw_wunlock(&tfile->lock); 311592ffb21SWarner Losh MPASS(ret == -EINVAL); 312592ffb21SWarner Losh 313592ffb21SWarner Losh ttm_mem_global_free(mem_glob, sizeof(*ref)); 314592ffb21SWarner Losh free(ref, M_TTM_OBJ_REF); 315592ffb21SWarner Losh } 316592ffb21SWarner Losh 317592ffb21SWarner Losh return ret; 318592ffb21SWarner Losh } 319592ffb21SWarner Losh 320592ffb21SWarner Losh static void ttm_ref_object_release(struct ttm_ref_object *ref) 321592ffb21SWarner Losh { 322592ffb21SWarner Losh struct ttm_base_object *base = ref->obj; 323592ffb21SWarner Losh struct ttm_object_file *tfile = ref->tfile; 324592ffb21SWarner Losh struct drm_open_hash *ht; 325592ffb21SWarner Losh struct ttm_mem_global *mem_glob = tfile->tdev->mem_glob; 326592ffb21SWarner Losh 327592ffb21SWarner Losh ht = &tfile->ref_hash[ref->ref_type]; 328592ffb21SWarner Losh (void)drm_ht_remove_item(ht, &ref->hash); 329592ffb21SWarner Losh list_del(&ref->head); 330592ffb21SWarner Losh rw_wunlock(&tfile->lock); 331592ffb21SWarner Losh 332592ffb21SWarner Losh if (ref->ref_type != TTM_REF_USAGE && base->ref_obj_release) 333592ffb21SWarner Losh base->ref_obj_release(base, ref->ref_type); 334592ffb21SWarner Losh 335592ffb21SWarner Losh ttm_base_object_unref(&ref->obj); 336592ffb21SWarner Losh ttm_mem_global_free(mem_glob, sizeof(*ref)); 337592ffb21SWarner Losh free(ref, M_TTM_OBJ_REF); 338592ffb21SWarner Losh rw_wlock(&tfile->lock); 339592ffb21SWarner Losh } 340592ffb21SWarner Losh 341592ffb21SWarner Losh int ttm_ref_object_base_unref(struct ttm_object_file *tfile, 342592ffb21SWarner Losh unsigned long key, enum ttm_ref_type ref_type) 343592ffb21SWarner Losh { 344592ffb21SWarner Losh struct drm_open_hash *ht = &tfile->ref_hash[ref_type]; 345592ffb21SWarner Losh struct ttm_ref_object *ref; 346592ffb21SWarner Losh struct drm_hash_item *hash; 347592ffb21SWarner Losh int ret; 348592ffb21SWarner Losh 349592ffb21SWarner Losh rw_wlock(&tfile->lock); 350592ffb21SWarner Losh ret = drm_ht_find_item(ht, key, &hash); 351592ffb21SWarner Losh if (unlikely(ret != 0)) { 352592ffb21SWarner Losh rw_wunlock(&tfile->lock); 353592ffb21SWarner Losh return -EINVAL; 354592ffb21SWarner Losh } 355592ffb21SWarner Losh ref = drm_hash_entry(hash, struct ttm_ref_object, hash); 356592ffb21SWarner Losh if (refcount_release(&ref->kref)) 357592ffb21SWarner Losh ttm_ref_object_release(ref); 358592ffb21SWarner Losh rw_wunlock(&tfile->lock); 359592ffb21SWarner Losh return 0; 360592ffb21SWarner Losh } 361592ffb21SWarner Losh 362592ffb21SWarner Losh void ttm_object_file_release(struct ttm_object_file **p_tfile) 363592ffb21SWarner Losh { 364592ffb21SWarner Losh struct ttm_ref_object *ref; 365592ffb21SWarner Losh struct list_head *list; 366592ffb21SWarner Losh unsigned int i; 367592ffb21SWarner Losh struct ttm_object_file *tfile = *p_tfile; 368592ffb21SWarner Losh 369592ffb21SWarner Losh *p_tfile = NULL; 370592ffb21SWarner Losh rw_wlock(&tfile->lock); 371592ffb21SWarner Losh 372592ffb21SWarner Losh /* 373592ffb21SWarner Losh * Since we release the lock within the loop, we have to 374592ffb21SWarner Losh * restart it from the beginning each time. 375592ffb21SWarner Losh */ 376592ffb21SWarner Losh 377592ffb21SWarner Losh while (!list_empty(&tfile->ref_list)) { 378592ffb21SWarner Losh list = tfile->ref_list.next; 379592ffb21SWarner Losh ref = list_entry(list, struct ttm_ref_object, head); 380592ffb21SWarner Losh ttm_ref_object_release(ref); 381592ffb21SWarner Losh } 382592ffb21SWarner Losh 383592ffb21SWarner Losh for (i = 0; i < TTM_REF_NUM; ++i) 384592ffb21SWarner Losh drm_ht_remove(&tfile->ref_hash[i]); 385592ffb21SWarner Losh 386592ffb21SWarner Losh rw_wunlock(&tfile->lock); 387592ffb21SWarner Losh ttm_object_file_unref(&tfile); 388592ffb21SWarner Losh } 389592ffb21SWarner Losh 390592ffb21SWarner Losh struct ttm_object_file *ttm_object_file_init(struct ttm_object_device *tdev, 391592ffb21SWarner Losh unsigned int hash_order) 392592ffb21SWarner Losh { 393592ffb21SWarner Losh struct ttm_object_file *tfile; 394592ffb21SWarner Losh unsigned int i; 395592ffb21SWarner Losh unsigned int j = 0; 396592ffb21SWarner Losh int ret; 397592ffb21SWarner Losh 398592ffb21SWarner Losh tfile = malloc(sizeof(*tfile), M_TTM_OBJ_FILE, M_WAITOK); 399592ffb21SWarner Losh rw_init(&tfile->lock, "ttmfo"); 400592ffb21SWarner Losh tfile->tdev = tdev; 401592ffb21SWarner Losh refcount_init(&tfile->refcount, 1); 402592ffb21SWarner Losh INIT_LIST_HEAD(&tfile->ref_list); 403592ffb21SWarner Losh 404592ffb21SWarner Losh for (i = 0; i < TTM_REF_NUM; ++i) { 405592ffb21SWarner Losh ret = drm_ht_create(&tfile->ref_hash[i], hash_order); 406592ffb21SWarner Losh if (ret) { 407592ffb21SWarner Losh j = i; 408592ffb21SWarner Losh goto out_err; 409592ffb21SWarner Losh } 410592ffb21SWarner Losh } 411592ffb21SWarner Losh 412592ffb21SWarner Losh return tfile; 413592ffb21SWarner Losh out_err: 414592ffb21SWarner Losh for (i = 0; i < j; ++i) 415592ffb21SWarner Losh drm_ht_remove(&tfile->ref_hash[i]); 416592ffb21SWarner Losh 417592ffb21SWarner Losh free(tfile, M_TTM_OBJ_FILE); 418592ffb21SWarner Losh 419592ffb21SWarner Losh return NULL; 420592ffb21SWarner Losh } 421592ffb21SWarner Losh 422592ffb21SWarner Losh MALLOC_DEFINE(M_TTM_OBJ_DEV, "ttm_obj_dev", "TTM Device Objects"); 423592ffb21SWarner Losh 424592ffb21SWarner Losh struct ttm_object_device *ttm_object_device_init(struct ttm_mem_global 425592ffb21SWarner Losh *mem_glob, 426592ffb21SWarner Losh unsigned int hash_order) 427592ffb21SWarner Losh { 428592ffb21SWarner Losh struct ttm_object_device *tdev; 429592ffb21SWarner Losh int ret; 430592ffb21SWarner Losh 431592ffb21SWarner Losh tdev = malloc(sizeof(*tdev), M_TTM_OBJ_DEV, M_WAITOK); 432592ffb21SWarner Losh tdev->mem_glob = mem_glob; 433592ffb21SWarner Losh rw_init(&tdev->object_lock, "ttmdo"); 434592ffb21SWarner Losh atomic_set(&tdev->object_count, 0); 435592ffb21SWarner Losh ret = drm_ht_create(&tdev->object_hash, hash_order); 436592ffb21SWarner Losh 437592ffb21SWarner Losh if (ret == 0) 438592ffb21SWarner Losh return tdev; 439592ffb21SWarner Losh 440592ffb21SWarner Losh free(tdev, M_TTM_OBJ_DEV); 441592ffb21SWarner Losh return NULL; 442592ffb21SWarner Losh } 443592ffb21SWarner Losh 444592ffb21SWarner Losh void ttm_object_device_release(struct ttm_object_device **p_tdev) 445592ffb21SWarner Losh { 446592ffb21SWarner Losh struct ttm_object_device *tdev = *p_tdev; 447592ffb21SWarner Losh 448592ffb21SWarner Losh *p_tdev = NULL; 449592ffb21SWarner Losh 450592ffb21SWarner Losh rw_wlock(&tdev->object_lock); 451592ffb21SWarner Losh drm_ht_remove(&tdev->object_hash); 452592ffb21SWarner Losh rw_wunlock(&tdev->object_lock); 453592ffb21SWarner Losh 454592ffb21SWarner Losh free(tdev, M_TTM_OBJ_DEV); 455592ffb21SWarner Losh } 456