1*592ffb21SWarner Losh /************************************************************************** 2*592ffb21SWarner Losh * 3*592ffb21SWarner Losh * Copyright (c) 2009 VMware, Inc., Palo Alto, CA., USA 4*592ffb21SWarner Losh * All Rights Reserved. 5*592ffb21SWarner Losh * 6*592ffb21SWarner Losh * Permission is hereby granted, free of charge, to any person obtaining a 7*592ffb21SWarner Losh * copy of this software and associated documentation files (the 8*592ffb21SWarner Losh * "Software"), to deal in the Software without restriction, including 9*592ffb21SWarner Losh * without limitation the rights to use, copy, modify, merge, publish, 10*592ffb21SWarner Losh * distribute, sub license, and/or sell copies of the Software, and to 11*592ffb21SWarner Losh * permit persons to whom the Software is furnished to do so, subject to 12*592ffb21SWarner Losh * the following conditions: 13*592ffb21SWarner Losh * 14*592ffb21SWarner Losh * The above copyright notice and this permission notice (including the 15*592ffb21SWarner Losh * next paragraph) shall be included in all copies or substantial portions 16*592ffb21SWarner Losh * of the Software. 17*592ffb21SWarner Losh * 18*592ffb21SWarner Losh * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19*592ffb21SWarner Losh * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20*592ffb21SWarner Losh * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 21*592ffb21SWarner Losh * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 22*592ffb21SWarner Losh * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 23*592ffb21SWarner Losh * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 24*592ffb21SWarner Losh * USE OR OTHER DEALINGS IN THE SOFTWARE. 25*592ffb21SWarner Losh * 26*592ffb21SWarner Losh **************************************************************************/ 27*592ffb21SWarner Losh /* 28*592ffb21SWarner Losh * Authors: Thomas Hellstrom <thellstrom-at-vmware-dot-com> 29*592ffb21SWarner Losh */ 30*592ffb21SWarner Losh /** @file ttm_ref_object.c 31*592ffb21SWarner Losh * 32*592ffb21SWarner Losh * Base- and reference object implementation for the various 33*592ffb21SWarner Losh * ttm objects. Implements reference counting, minimal security checks 34*592ffb21SWarner Losh * and release on file close. 35*592ffb21SWarner Losh */ 36*592ffb21SWarner Losh 37*592ffb21SWarner Losh 38*592ffb21SWarner Losh #include <sys/cdefs.h> 39*592ffb21SWarner Losh __FBSDID("$FreeBSD$"); 40*592ffb21SWarner Losh 41*592ffb21SWarner Losh /** 42*592ffb21SWarner Losh * struct ttm_object_file 43*592ffb21SWarner Losh * 44*592ffb21SWarner Losh * @tdev: Pointer to the ttm_object_device. 45*592ffb21SWarner Losh * 46*592ffb21SWarner Losh * @lock: Lock that protects the ref_list list and the 47*592ffb21SWarner Losh * ref_hash hash tables. 48*592ffb21SWarner Losh * 49*592ffb21SWarner Losh * @ref_list: List of ttm_ref_objects to be destroyed at 50*592ffb21SWarner Losh * file release. 51*592ffb21SWarner Losh * 52*592ffb21SWarner Losh * @ref_hash: Hash tables of ref objects, one per ttm_ref_type, 53*592ffb21SWarner Losh * for fast lookup of ref objects given a base object. 54*592ffb21SWarner Losh */ 55*592ffb21SWarner Losh 56*592ffb21SWarner Losh #define pr_fmt(fmt) "[TTM] " fmt 57*592ffb21SWarner Losh 58*592ffb21SWarner Losh #include <dev/drm2/drmP.h> 59*592ffb21SWarner Losh #include <dev/drm2/drm.h> 60*592ffb21SWarner Losh #include <sys/rwlock.h> 61*592ffb21SWarner Losh #include <dev/drm2/ttm/ttm_object.h> 62*592ffb21SWarner Losh #include <dev/drm2/ttm/ttm_module.h> 63*592ffb21SWarner Losh 64*592ffb21SWarner Losh struct ttm_object_file { 65*592ffb21SWarner Losh struct ttm_object_device *tdev; 66*592ffb21SWarner Losh struct rwlock lock; 67*592ffb21SWarner Losh struct list_head ref_list; 68*592ffb21SWarner Losh struct drm_open_hash ref_hash[TTM_REF_NUM]; 69*592ffb21SWarner Losh u_int refcount; 70*592ffb21SWarner Losh }; 71*592ffb21SWarner Losh 72*592ffb21SWarner Losh /** 73*592ffb21SWarner Losh * struct ttm_object_device 74*592ffb21SWarner Losh * 75*592ffb21SWarner Losh * @object_lock: lock that protects the object_hash hash table. 76*592ffb21SWarner Losh * 77*592ffb21SWarner Losh * @object_hash: hash table for fast lookup of object global names. 78*592ffb21SWarner Losh * 79*592ffb21SWarner Losh * @object_count: Per device object count. 80*592ffb21SWarner Losh * 81*592ffb21SWarner Losh * This is the per-device data structure needed for ttm object management. 82*592ffb21SWarner Losh */ 83*592ffb21SWarner Losh 84*592ffb21SWarner Losh struct ttm_object_device { 85*592ffb21SWarner Losh struct rwlock object_lock; 86*592ffb21SWarner Losh struct drm_open_hash object_hash; 87*592ffb21SWarner Losh atomic_t object_count; 88*592ffb21SWarner Losh struct ttm_mem_global *mem_glob; 89*592ffb21SWarner Losh }; 90*592ffb21SWarner Losh 91*592ffb21SWarner Losh /** 92*592ffb21SWarner Losh * struct ttm_ref_object 93*592ffb21SWarner Losh * 94*592ffb21SWarner Losh * @hash: Hash entry for the per-file object reference hash. 95*592ffb21SWarner Losh * 96*592ffb21SWarner Losh * @head: List entry for the per-file list of ref-objects. 97*592ffb21SWarner Losh * 98*592ffb21SWarner Losh * @kref: Ref count. 99*592ffb21SWarner Losh * 100*592ffb21SWarner Losh * @obj: Base object this ref object is referencing. 101*592ffb21SWarner Losh * 102*592ffb21SWarner Losh * @ref_type: Type of ref object. 103*592ffb21SWarner Losh * 104*592ffb21SWarner Losh * This is similar to an idr object, but it also has a hash table entry 105*592ffb21SWarner Losh * that allows lookup with a pointer to the referenced object as a key. In 106*592ffb21SWarner Losh * that way, one can easily detect whether a base object is referenced by 107*592ffb21SWarner Losh * a particular ttm_object_file. It also carries a ref count to avoid creating 108*592ffb21SWarner Losh * multiple ref objects if a ttm_object_file references the same base 109*592ffb21SWarner Losh * object more than once. 110*592ffb21SWarner Losh */ 111*592ffb21SWarner Losh 112*592ffb21SWarner Losh struct ttm_ref_object { 113*592ffb21SWarner Losh struct drm_hash_item hash; 114*592ffb21SWarner Losh struct list_head head; 115*592ffb21SWarner Losh u_int kref; 116*592ffb21SWarner Losh enum ttm_ref_type ref_type; 117*592ffb21SWarner Losh struct ttm_base_object *obj; 118*592ffb21SWarner Losh struct ttm_object_file *tfile; 119*592ffb21SWarner Losh }; 120*592ffb21SWarner Losh 121*592ffb21SWarner Losh MALLOC_DEFINE(M_TTM_OBJ_FILE, "ttm_obj_file", "TTM File Objects"); 122*592ffb21SWarner Losh 123*592ffb21SWarner Losh static inline struct ttm_object_file * 124*592ffb21SWarner Losh ttm_object_file_ref(struct ttm_object_file *tfile) 125*592ffb21SWarner Losh { 126*592ffb21SWarner Losh refcount_acquire(&tfile->refcount); 127*592ffb21SWarner Losh return tfile; 128*592ffb21SWarner Losh } 129*592ffb21SWarner Losh 130*592ffb21SWarner Losh static void ttm_object_file_destroy(struct ttm_object_file *tfile) 131*592ffb21SWarner Losh { 132*592ffb21SWarner Losh 133*592ffb21SWarner Losh free(tfile, M_TTM_OBJ_FILE); 134*592ffb21SWarner Losh } 135*592ffb21SWarner Losh 136*592ffb21SWarner Losh 137*592ffb21SWarner Losh static inline void ttm_object_file_unref(struct ttm_object_file **p_tfile) 138*592ffb21SWarner Losh { 139*592ffb21SWarner Losh struct ttm_object_file *tfile = *p_tfile; 140*592ffb21SWarner Losh 141*592ffb21SWarner Losh *p_tfile = NULL; 142*592ffb21SWarner Losh if (refcount_release(&tfile->refcount)) 143*592ffb21SWarner Losh ttm_object_file_destroy(tfile); 144*592ffb21SWarner Losh } 145*592ffb21SWarner Losh 146*592ffb21SWarner Losh 147*592ffb21SWarner Losh int ttm_base_object_init(struct ttm_object_file *tfile, 148*592ffb21SWarner Losh struct ttm_base_object *base, 149*592ffb21SWarner Losh bool shareable, 150*592ffb21SWarner Losh enum ttm_object_type object_type, 151*592ffb21SWarner Losh void (*rcount_release) (struct ttm_base_object **), 152*592ffb21SWarner Losh void (*ref_obj_release) (struct ttm_base_object *, 153*592ffb21SWarner Losh enum ttm_ref_type ref_type)) 154*592ffb21SWarner Losh { 155*592ffb21SWarner Losh struct ttm_object_device *tdev = tfile->tdev; 156*592ffb21SWarner Losh int ret; 157*592ffb21SWarner Losh 158*592ffb21SWarner Losh base->shareable = shareable; 159*592ffb21SWarner Losh base->tfile = ttm_object_file_ref(tfile); 160*592ffb21SWarner Losh base->refcount_release = rcount_release; 161*592ffb21SWarner Losh base->ref_obj_release = ref_obj_release; 162*592ffb21SWarner Losh base->object_type = object_type; 163*592ffb21SWarner Losh refcount_init(&base->refcount, 1); 164*592ffb21SWarner Losh rw_init(&tdev->object_lock, "ttmbao"); 165*592ffb21SWarner Losh rw_wlock(&tdev->object_lock); 166*592ffb21SWarner Losh ret = drm_ht_just_insert_please(&tdev->object_hash, 167*592ffb21SWarner Losh &base->hash, 168*592ffb21SWarner Losh (unsigned long)base, 31, 0, 0); 169*592ffb21SWarner Losh rw_wunlock(&tdev->object_lock); 170*592ffb21SWarner Losh if (unlikely(ret != 0)) 171*592ffb21SWarner Losh goto out_err0; 172*592ffb21SWarner Losh 173*592ffb21SWarner Losh ret = ttm_ref_object_add(tfile, base, TTM_REF_USAGE, NULL); 174*592ffb21SWarner Losh if (unlikely(ret != 0)) 175*592ffb21SWarner Losh goto out_err1; 176*592ffb21SWarner Losh 177*592ffb21SWarner Losh ttm_base_object_unref(&base); 178*592ffb21SWarner Losh 179*592ffb21SWarner Losh return 0; 180*592ffb21SWarner Losh out_err1: 181*592ffb21SWarner Losh rw_wlock(&tdev->object_lock); 182*592ffb21SWarner Losh (void)drm_ht_remove_item(&tdev->object_hash, &base->hash); 183*592ffb21SWarner Losh rw_wunlock(&tdev->object_lock); 184*592ffb21SWarner Losh out_err0: 185*592ffb21SWarner Losh return ret; 186*592ffb21SWarner Losh } 187*592ffb21SWarner Losh 188*592ffb21SWarner Losh static void ttm_release_base(struct ttm_base_object *base) 189*592ffb21SWarner Losh { 190*592ffb21SWarner Losh struct ttm_object_device *tdev = base->tfile->tdev; 191*592ffb21SWarner Losh 192*592ffb21SWarner Losh (void)drm_ht_remove_item(&tdev->object_hash, &base->hash); 193*592ffb21SWarner Losh rw_wunlock(&tdev->object_lock); 194*592ffb21SWarner Losh /* 195*592ffb21SWarner Losh * Note: We don't use synchronize_rcu() here because it's far 196*592ffb21SWarner Losh * too slow. It's up to the user to free the object using 197*592ffb21SWarner Losh * call_rcu() or ttm_base_object_kfree(). 198*592ffb21SWarner Losh */ 199*592ffb21SWarner Losh 200*592ffb21SWarner Losh if (base->refcount_release) { 201*592ffb21SWarner Losh ttm_object_file_unref(&base->tfile); 202*592ffb21SWarner Losh base->refcount_release(&base); 203*592ffb21SWarner Losh } 204*592ffb21SWarner Losh rw_wlock(&tdev->object_lock); 205*592ffb21SWarner Losh } 206*592ffb21SWarner Losh 207*592ffb21SWarner Losh void ttm_base_object_unref(struct ttm_base_object **p_base) 208*592ffb21SWarner Losh { 209*592ffb21SWarner Losh struct ttm_base_object *base = *p_base; 210*592ffb21SWarner Losh struct ttm_object_device *tdev = base->tfile->tdev; 211*592ffb21SWarner Losh 212*592ffb21SWarner Losh *p_base = NULL; 213*592ffb21SWarner Losh 214*592ffb21SWarner Losh /* 215*592ffb21SWarner Losh * Need to take the lock here to avoid racing with 216*592ffb21SWarner Losh * users trying to look up the object. 217*592ffb21SWarner Losh */ 218*592ffb21SWarner Losh 219*592ffb21SWarner Losh rw_wlock(&tdev->object_lock); 220*592ffb21SWarner Losh if (refcount_release(&base->refcount)) 221*592ffb21SWarner Losh ttm_release_base(base); 222*592ffb21SWarner Losh rw_wunlock(&tdev->object_lock); 223*592ffb21SWarner Losh } 224*592ffb21SWarner Losh 225*592ffb21SWarner Losh struct ttm_base_object *ttm_base_object_lookup(struct ttm_object_file *tfile, 226*592ffb21SWarner Losh uint32_t key) 227*592ffb21SWarner Losh { 228*592ffb21SWarner Losh struct ttm_object_device *tdev = tfile->tdev; 229*592ffb21SWarner Losh struct ttm_base_object *base; 230*592ffb21SWarner Losh struct drm_hash_item *hash; 231*592ffb21SWarner Losh int ret; 232*592ffb21SWarner Losh 233*592ffb21SWarner Losh rw_rlock(&tdev->object_lock); 234*592ffb21SWarner Losh ret = drm_ht_find_item(&tdev->object_hash, key, &hash); 235*592ffb21SWarner Losh 236*592ffb21SWarner Losh if (ret == 0) { 237*592ffb21SWarner Losh base = drm_hash_entry(hash, struct ttm_base_object, hash); 238*592ffb21SWarner Losh refcount_acquire(&base->refcount); 239*592ffb21SWarner Losh } 240*592ffb21SWarner Losh rw_runlock(&tdev->object_lock); 241*592ffb21SWarner Losh 242*592ffb21SWarner Losh if (unlikely(ret != 0)) 243*592ffb21SWarner Losh return NULL; 244*592ffb21SWarner Losh 245*592ffb21SWarner Losh if (tfile != base->tfile && !base->shareable) { 246*592ffb21SWarner Losh printf("[TTM] Attempted access of non-shareable object %p\n", 247*592ffb21SWarner Losh base); 248*592ffb21SWarner Losh ttm_base_object_unref(&base); 249*592ffb21SWarner Losh return NULL; 250*592ffb21SWarner Losh } 251*592ffb21SWarner Losh 252*592ffb21SWarner Losh return base; 253*592ffb21SWarner Losh } 254*592ffb21SWarner Losh 255*592ffb21SWarner Losh MALLOC_DEFINE(M_TTM_OBJ_REF, "ttm_obj_ref", "TTM Ref Objects"); 256*592ffb21SWarner Losh 257*592ffb21SWarner Losh int ttm_ref_object_add(struct ttm_object_file *tfile, 258*592ffb21SWarner Losh struct ttm_base_object *base, 259*592ffb21SWarner Losh enum ttm_ref_type ref_type, bool *existed) 260*592ffb21SWarner Losh { 261*592ffb21SWarner Losh struct drm_open_hash *ht = &tfile->ref_hash[ref_type]; 262*592ffb21SWarner Losh struct ttm_ref_object *ref; 263*592ffb21SWarner Losh struct drm_hash_item *hash; 264*592ffb21SWarner Losh struct ttm_mem_global *mem_glob = tfile->tdev->mem_glob; 265*592ffb21SWarner Losh int ret = -EINVAL; 266*592ffb21SWarner Losh 267*592ffb21SWarner Losh if (existed != NULL) 268*592ffb21SWarner Losh *existed = true; 269*592ffb21SWarner Losh 270*592ffb21SWarner Losh while (ret == -EINVAL) { 271*592ffb21SWarner Losh rw_rlock(&tfile->lock); 272*592ffb21SWarner Losh ret = drm_ht_find_item(ht, base->hash.key, &hash); 273*592ffb21SWarner Losh 274*592ffb21SWarner Losh if (ret == 0) { 275*592ffb21SWarner Losh ref = drm_hash_entry(hash, struct ttm_ref_object, hash); 276*592ffb21SWarner Losh refcount_acquire(&ref->kref); 277*592ffb21SWarner Losh rw_runlock(&tfile->lock); 278*592ffb21SWarner Losh break; 279*592ffb21SWarner Losh } 280*592ffb21SWarner Losh 281*592ffb21SWarner Losh rw_runlock(&tfile->lock); 282*592ffb21SWarner Losh ret = ttm_mem_global_alloc(mem_glob, sizeof(*ref), 283*592ffb21SWarner Losh false, false); 284*592ffb21SWarner Losh if (unlikely(ret != 0)) 285*592ffb21SWarner Losh return ret; 286*592ffb21SWarner Losh ref = malloc(sizeof(*ref), M_TTM_OBJ_REF, M_WAITOK); 287*592ffb21SWarner Losh if (unlikely(ref == NULL)) { 288*592ffb21SWarner Losh ttm_mem_global_free(mem_glob, sizeof(*ref)); 289*592ffb21SWarner Losh return -ENOMEM; 290*592ffb21SWarner Losh } 291*592ffb21SWarner Losh 292*592ffb21SWarner Losh ref->hash.key = base->hash.key; 293*592ffb21SWarner Losh ref->obj = base; 294*592ffb21SWarner Losh ref->tfile = tfile; 295*592ffb21SWarner Losh ref->ref_type = ref_type; 296*592ffb21SWarner Losh refcount_init(&ref->kref, 1); 297*592ffb21SWarner Losh 298*592ffb21SWarner Losh rw_wlock(&tfile->lock); 299*592ffb21SWarner Losh ret = drm_ht_insert_item(ht, &ref->hash); 300*592ffb21SWarner Losh 301*592ffb21SWarner Losh if (ret == 0) { 302*592ffb21SWarner Losh list_add_tail(&ref->head, &tfile->ref_list); 303*592ffb21SWarner Losh refcount_acquire(&base->refcount); 304*592ffb21SWarner Losh rw_wunlock(&tfile->lock); 305*592ffb21SWarner Losh if (existed != NULL) 306*592ffb21SWarner Losh *existed = false; 307*592ffb21SWarner Losh break; 308*592ffb21SWarner Losh } 309*592ffb21SWarner Losh 310*592ffb21SWarner Losh rw_wunlock(&tfile->lock); 311*592ffb21SWarner Losh MPASS(ret == -EINVAL); 312*592ffb21SWarner Losh 313*592ffb21SWarner Losh ttm_mem_global_free(mem_glob, sizeof(*ref)); 314*592ffb21SWarner Losh free(ref, M_TTM_OBJ_REF); 315*592ffb21SWarner Losh } 316*592ffb21SWarner Losh 317*592ffb21SWarner Losh return ret; 318*592ffb21SWarner Losh } 319*592ffb21SWarner Losh 320*592ffb21SWarner Losh static void ttm_ref_object_release(struct ttm_ref_object *ref) 321*592ffb21SWarner Losh { 322*592ffb21SWarner Losh struct ttm_base_object *base = ref->obj; 323*592ffb21SWarner Losh struct ttm_object_file *tfile = ref->tfile; 324*592ffb21SWarner Losh struct drm_open_hash *ht; 325*592ffb21SWarner Losh struct ttm_mem_global *mem_glob = tfile->tdev->mem_glob; 326*592ffb21SWarner Losh 327*592ffb21SWarner Losh ht = &tfile->ref_hash[ref->ref_type]; 328*592ffb21SWarner Losh (void)drm_ht_remove_item(ht, &ref->hash); 329*592ffb21SWarner Losh list_del(&ref->head); 330*592ffb21SWarner Losh rw_wunlock(&tfile->lock); 331*592ffb21SWarner Losh 332*592ffb21SWarner Losh if (ref->ref_type != TTM_REF_USAGE && base->ref_obj_release) 333*592ffb21SWarner Losh base->ref_obj_release(base, ref->ref_type); 334*592ffb21SWarner Losh 335*592ffb21SWarner Losh ttm_base_object_unref(&ref->obj); 336*592ffb21SWarner Losh ttm_mem_global_free(mem_glob, sizeof(*ref)); 337*592ffb21SWarner Losh free(ref, M_TTM_OBJ_REF); 338*592ffb21SWarner Losh rw_wlock(&tfile->lock); 339*592ffb21SWarner Losh } 340*592ffb21SWarner Losh 341*592ffb21SWarner Losh int ttm_ref_object_base_unref(struct ttm_object_file *tfile, 342*592ffb21SWarner Losh unsigned long key, enum ttm_ref_type ref_type) 343*592ffb21SWarner Losh { 344*592ffb21SWarner Losh struct drm_open_hash *ht = &tfile->ref_hash[ref_type]; 345*592ffb21SWarner Losh struct ttm_ref_object *ref; 346*592ffb21SWarner Losh struct drm_hash_item *hash; 347*592ffb21SWarner Losh int ret; 348*592ffb21SWarner Losh 349*592ffb21SWarner Losh rw_wlock(&tfile->lock); 350*592ffb21SWarner Losh ret = drm_ht_find_item(ht, key, &hash); 351*592ffb21SWarner Losh if (unlikely(ret != 0)) { 352*592ffb21SWarner Losh rw_wunlock(&tfile->lock); 353*592ffb21SWarner Losh return -EINVAL; 354*592ffb21SWarner Losh } 355*592ffb21SWarner Losh ref = drm_hash_entry(hash, struct ttm_ref_object, hash); 356*592ffb21SWarner Losh if (refcount_release(&ref->kref)) 357*592ffb21SWarner Losh ttm_ref_object_release(ref); 358*592ffb21SWarner Losh rw_wunlock(&tfile->lock); 359*592ffb21SWarner Losh return 0; 360*592ffb21SWarner Losh } 361*592ffb21SWarner Losh 362*592ffb21SWarner Losh void ttm_object_file_release(struct ttm_object_file **p_tfile) 363*592ffb21SWarner Losh { 364*592ffb21SWarner Losh struct ttm_ref_object *ref; 365*592ffb21SWarner Losh struct list_head *list; 366*592ffb21SWarner Losh unsigned int i; 367*592ffb21SWarner Losh struct ttm_object_file *tfile = *p_tfile; 368*592ffb21SWarner Losh 369*592ffb21SWarner Losh *p_tfile = NULL; 370*592ffb21SWarner Losh rw_wlock(&tfile->lock); 371*592ffb21SWarner Losh 372*592ffb21SWarner Losh /* 373*592ffb21SWarner Losh * Since we release the lock within the loop, we have to 374*592ffb21SWarner Losh * restart it from the beginning each time. 375*592ffb21SWarner Losh */ 376*592ffb21SWarner Losh 377*592ffb21SWarner Losh while (!list_empty(&tfile->ref_list)) { 378*592ffb21SWarner Losh list = tfile->ref_list.next; 379*592ffb21SWarner Losh ref = list_entry(list, struct ttm_ref_object, head); 380*592ffb21SWarner Losh ttm_ref_object_release(ref); 381*592ffb21SWarner Losh } 382*592ffb21SWarner Losh 383*592ffb21SWarner Losh for (i = 0; i < TTM_REF_NUM; ++i) 384*592ffb21SWarner Losh drm_ht_remove(&tfile->ref_hash[i]); 385*592ffb21SWarner Losh 386*592ffb21SWarner Losh rw_wunlock(&tfile->lock); 387*592ffb21SWarner Losh ttm_object_file_unref(&tfile); 388*592ffb21SWarner Losh } 389*592ffb21SWarner Losh 390*592ffb21SWarner Losh struct ttm_object_file *ttm_object_file_init(struct ttm_object_device *tdev, 391*592ffb21SWarner Losh unsigned int hash_order) 392*592ffb21SWarner Losh { 393*592ffb21SWarner Losh struct ttm_object_file *tfile; 394*592ffb21SWarner Losh unsigned int i; 395*592ffb21SWarner Losh unsigned int j = 0; 396*592ffb21SWarner Losh int ret; 397*592ffb21SWarner Losh 398*592ffb21SWarner Losh tfile = malloc(sizeof(*tfile), M_TTM_OBJ_FILE, M_WAITOK); 399*592ffb21SWarner Losh rw_init(&tfile->lock, "ttmfo"); 400*592ffb21SWarner Losh tfile->tdev = tdev; 401*592ffb21SWarner Losh refcount_init(&tfile->refcount, 1); 402*592ffb21SWarner Losh INIT_LIST_HEAD(&tfile->ref_list); 403*592ffb21SWarner Losh 404*592ffb21SWarner Losh for (i = 0; i < TTM_REF_NUM; ++i) { 405*592ffb21SWarner Losh ret = drm_ht_create(&tfile->ref_hash[i], hash_order); 406*592ffb21SWarner Losh if (ret) { 407*592ffb21SWarner Losh j = i; 408*592ffb21SWarner Losh goto out_err; 409*592ffb21SWarner Losh } 410*592ffb21SWarner Losh } 411*592ffb21SWarner Losh 412*592ffb21SWarner Losh return tfile; 413*592ffb21SWarner Losh out_err: 414*592ffb21SWarner Losh for (i = 0; i < j; ++i) 415*592ffb21SWarner Losh drm_ht_remove(&tfile->ref_hash[i]); 416*592ffb21SWarner Losh 417*592ffb21SWarner Losh free(tfile, M_TTM_OBJ_FILE); 418*592ffb21SWarner Losh 419*592ffb21SWarner Losh return NULL; 420*592ffb21SWarner Losh } 421*592ffb21SWarner Losh 422*592ffb21SWarner Losh MALLOC_DEFINE(M_TTM_OBJ_DEV, "ttm_obj_dev", "TTM Device Objects"); 423*592ffb21SWarner Losh 424*592ffb21SWarner Losh struct ttm_object_device *ttm_object_device_init(struct ttm_mem_global 425*592ffb21SWarner Losh *mem_glob, 426*592ffb21SWarner Losh unsigned int hash_order) 427*592ffb21SWarner Losh { 428*592ffb21SWarner Losh struct ttm_object_device *tdev; 429*592ffb21SWarner Losh int ret; 430*592ffb21SWarner Losh 431*592ffb21SWarner Losh tdev = malloc(sizeof(*tdev), M_TTM_OBJ_DEV, M_WAITOK); 432*592ffb21SWarner Losh tdev->mem_glob = mem_glob; 433*592ffb21SWarner Losh rw_init(&tdev->object_lock, "ttmdo"); 434*592ffb21SWarner Losh atomic_set(&tdev->object_count, 0); 435*592ffb21SWarner Losh ret = drm_ht_create(&tdev->object_hash, hash_order); 436*592ffb21SWarner Losh 437*592ffb21SWarner Losh if (ret == 0) 438*592ffb21SWarner Losh return tdev; 439*592ffb21SWarner Losh 440*592ffb21SWarner Losh free(tdev, M_TTM_OBJ_DEV); 441*592ffb21SWarner Losh return NULL; 442*592ffb21SWarner Losh } 443*592ffb21SWarner Losh 444*592ffb21SWarner Losh void ttm_object_device_release(struct ttm_object_device **p_tdev) 445*592ffb21SWarner Losh { 446*592ffb21SWarner Losh struct ttm_object_device *tdev = *p_tdev; 447*592ffb21SWarner Losh 448*592ffb21SWarner Losh *p_tdev = NULL; 449*592ffb21SWarner Losh 450*592ffb21SWarner Losh rw_wlock(&tdev->object_lock); 451*592ffb21SWarner Losh drm_ht_remove(&tdev->object_hash); 452*592ffb21SWarner Losh rw_wunlock(&tdev->object_lock); 453*592ffb21SWarner Losh 454*592ffb21SWarner Losh free(tdev, M_TTM_OBJ_DEV); 455*592ffb21SWarner Losh } 456