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 /**
40*592ffb21SWarner Losh * struct ttm_object_file
41*592ffb21SWarner Losh *
42*592ffb21SWarner Losh * @tdev: Pointer to the ttm_object_device.
43*592ffb21SWarner Losh *
44*592ffb21SWarner Losh * @lock: Lock that protects the ref_list list and the
45*592ffb21SWarner Losh * ref_hash hash tables.
46*592ffb21SWarner Losh *
47*592ffb21SWarner Losh * @ref_list: List of ttm_ref_objects to be destroyed at
48*592ffb21SWarner Losh * file release.
49*592ffb21SWarner Losh *
50*592ffb21SWarner Losh * @ref_hash: Hash tables of ref objects, one per ttm_ref_type,
51*592ffb21SWarner Losh * for fast lookup of ref objects given a base object.
52*592ffb21SWarner Losh */
53*592ffb21SWarner Losh
54*592ffb21SWarner Losh #define pr_fmt(fmt) "[TTM] " fmt
55*592ffb21SWarner Losh
56*592ffb21SWarner Losh #include <dev/drm2/drmP.h>
57*592ffb21SWarner Losh #include <dev/drm2/drm.h>
58*592ffb21SWarner Losh #include <sys/rwlock.h>
59*592ffb21SWarner Losh #include <dev/drm2/ttm/ttm_object.h>
60*592ffb21SWarner Losh #include <dev/drm2/ttm/ttm_module.h>
61*592ffb21SWarner Losh
62*592ffb21SWarner Losh struct ttm_object_file {
63*592ffb21SWarner Losh struct ttm_object_device *tdev;
64*592ffb21SWarner Losh struct rwlock lock;
65*592ffb21SWarner Losh struct list_head ref_list;
66*592ffb21SWarner Losh struct drm_open_hash ref_hash[TTM_REF_NUM];
67*592ffb21SWarner Losh u_int refcount;
68*592ffb21SWarner Losh };
69*592ffb21SWarner Losh
70*592ffb21SWarner Losh /**
71*592ffb21SWarner Losh * struct ttm_object_device
72*592ffb21SWarner Losh *
73*592ffb21SWarner Losh * @object_lock: lock that protects the object_hash hash table.
74*592ffb21SWarner Losh *
75*592ffb21SWarner Losh * @object_hash: hash table for fast lookup of object global names.
76*592ffb21SWarner Losh *
77*592ffb21SWarner Losh * @object_count: Per device object count.
78*592ffb21SWarner Losh *
79*592ffb21SWarner Losh * This is the per-device data structure needed for ttm object management.
80*592ffb21SWarner Losh */
81*592ffb21SWarner Losh
82*592ffb21SWarner Losh struct ttm_object_device {
83*592ffb21SWarner Losh struct rwlock object_lock;
84*592ffb21SWarner Losh struct drm_open_hash object_hash;
85*592ffb21SWarner Losh atomic_t object_count;
86*592ffb21SWarner Losh struct ttm_mem_global *mem_glob;
87*592ffb21SWarner Losh };
88*592ffb21SWarner Losh
89*592ffb21SWarner Losh /**
90*592ffb21SWarner Losh * struct ttm_ref_object
91*592ffb21SWarner Losh *
92*592ffb21SWarner Losh * @hash: Hash entry for the per-file object reference hash.
93*592ffb21SWarner Losh *
94*592ffb21SWarner Losh * @head: List entry for the per-file list of ref-objects.
95*592ffb21SWarner Losh *
96*592ffb21SWarner Losh * @kref: Ref count.
97*592ffb21SWarner Losh *
98*592ffb21SWarner Losh * @obj: Base object this ref object is referencing.
99*592ffb21SWarner Losh *
100*592ffb21SWarner Losh * @ref_type: Type of ref object.
101*592ffb21SWarner Losh *
102*592ffb21SWarner Losh * This is similar to an idr object, but it also has a hash table entry
103*592ffb21SWarner Losh * that allows lookup with a pointer to the referenced object as a key. In
104*592ffb21SWarner Losh * that way, one can easily detect whether a base object is referenced by
105*592ffb21SWarner Losh * a particular ttm_object_file. It also carries a ref count to avoid creating
106*592ffb21SWarner Losh * multiple ref objects if a ttm_object_file references the same base
107*592ffb21SWarner Losh * object more than once.
108*592ffb21SWarner Losh */
109*592ffb21SWarner Losh
110*592ffb21SWarner Losh struct ttm_ref_object {
111*592ffb21SWarner Losh struct drm_hash_item hash;
112*592ffb21SWarner Losh struct list_head head;
113*592ffb21SWarner Losh u_int kref;
114*592ffb21SWarner Losh enum ttm_ref_type ref_type;
115*592ffb21SWarner Losh struct ttm_base_object *obj;
116*592ffb21SWarner Losh struct ttm_object_file *tfile;
117*592ffb21SWarner Losh };
118*592ffb21SWarner Losh
119*592ffb21SWarner Losh MALLOC_DEFINE(M_TTM_OBJ_FILE, "ttm_obj_file", "TTM File Objects");
120*592ffb21SWarner Losh
121*592ffb21SWarner Losh static inline struct ttm_object_file *
ttm_object_file_ref(struct ttm_object_file * tfile)122*592ffb21SWarner Losh ttm_object_file_ref(struct ttm_object_file *tfile)
123*592ffb21SWarner Losh {
124*592ffb21SWarner Losh refcount_acquire(&tfile->refcount);
125*592ffb21SWarner Losh return tfile;
126*592ffb21SWarner Losh }
127*592ffb21SWarner Losh
ttm_object_file_destroy(struct ttm_object_file * tfile)128*592ffb21SWarner Losh static void ttm_object_file_destroy(struct ttm_object_file *tfile)
129*592ffb21SWarner Losh {
130*592ffb21SWarner Losh
131*592ffb21SWarner Losh free(tfile, M_TTM_OBJ_FILE);
132*592ffb21SWarner Losh }
133*592ffb21SWarner Losh
134*592ffb21SWarner Losh
ttm_object_file_unref(struct ttm_object_file ** p_tfile)135*592ffb21SWarner Losh static inline void ttm_object_file_unref(struct ttm_object_file **p_tfile)
136*592ffb21SWarner Losh {
137*592ffb21SWarner Losh struct ttm_object_file *tfile = *p_tfile;
138*592ffb21SWarner Losh
139*592ffb21SWarner Losh *p_tfile = NULL;
140*592ffb21SWarner Losh if (refcount_release(&tfile->refcount))
141*592ffb21SWarner Losh ttm_object_file_destroy(tfile);
142*592ffb21SWarner Losh }
143*592ffb21SWarner Losh
144*592ffb21SWarner Losh
ttm_base_object_init(struct ttm_object_file * tfile,struct ttm_base_object * base,bool shareable,enum ttm_object_type object_type,void (* rcount_release)(struct ttm_base_object **),void (* ref_obj_release)(struct ttm_base_object *,enum ttm_ref_type ref_type))145*592ffb21SWarner Losh int ttm_base_object_init(struct ttm_object_file *tfile,
146*592ffb21SWarner Losh struct ttm_base_object *base,
147*592ffb21SWarner Losh bool shareable,
148*592ffb21SWarner Losh enum ttm_object_type object_type,
149*592ffb21SWarner Losh void (*rcount_release) (struct ttm_base_object **),
150*592ffb21SWarner Losh void (*ref_obj_release) (struct ttm_base_object *,
151*592ffb21SWarner Losh enum ttm_ref_type ref_type))
152*592ffb21SWarner Losh {
153*592ffb21SWarner Losh struct ttm_object_device *tdev = tfile->tdev;
154*592ffb21SWarner Losh int ret;
155*592ffb21SWarner Losh
156*592ffb21SWarner Losh base->shareable = shareable;
157*592ffb21SWarner Losh base->tfile = ttm_object_file_ref(tfile);
158*592ffb21SWarner Losh base->refcount_release = rcount_release;
159*592ffb21SWarner Losh base->ref_obj_release = ref_obj_release;
160*592ffb21SWarner Losh base->object_type = object_type;
161*592ffb21SWarner Losh refcount_init(&base->refcount, 1);
162*592ffb21SWarner Losh rw_init(&tdev->object_lock, "ttmbao");
163*592ffb21SWarner Losh rw_wlock(&tdev->object_lock);
164*592ffb21SWarner Losh ret = drm_ht_just_insert_please(&tdev->object_hash,
165*592ffb21SWarner Losh &base->hash,
166*592ffb21SWarner Losh (unsigned long)base, 31, 0, 0);
167*592ffb21SWarner Losh rw_wunlock(&tdev->object_lock);
168*592ffb21SWarner Losh if (unlikely(ret != 0))
169*592ffb21SWarner Losh goto out_err0;
170*592ffb21SWarner Losh
171*592ffb21SWarner Losh ret = ttm_ref_object_add(tfile, base, TTM_REF_USAGE, NULL);
172*592ffb21SWarner Losh if (unlikely(ret != 0))
173*592ffb21SWarner Losh goto out_err1;
174*592ffb21SWarner Losh
175*592ffb21SWarner Losh ttm_base_object_unref(&base);
176*592ffb21SWarner Losh
177*592ffb21SWarner Losh return 0;
178*592ffb21SWarner Losh out_err1:
179*592ffb21SWarner Losh rw_wlock(&tdev->object_lock);
180*592ffb21SWarner Losh (void)drm_ht_remove_item(&tdev->object_hash, &base->hash);
181*592ffb21SWarner Losh rw_wunlock(&tdev->object_lock);
182*592ffb21SWarner Losh out_err0:
183*592ffb21SWarner Losh return ret;
184*592ffb21SWarner Losh }
185*592ffb21SWarner Losh
ttm_release_base(struct ttm_base_object * base)186*592ffb21SWarner Losh static void ttm_release_base(struct ttm_base_object *base)
187*592ffb21SWarner Losh {
188*592ffb21SWarner Losh struct ttm_object_device *tdev = base->tfile->tdev;
189*592ffb21SWarner Losh
190*592ffb21SWarner Losh (void)drm_ht_remove_item(&tdev->object_hash, &base->hash);
191*592ffb21SWarner Losh rw_wunlock(&tdev->object_lock);
192*592ffb21SWarner Losh /*
193*592ffb21SWarner Losh * Note: We don't use synchronize_rcu() here because it's far
194*592ffb21SWarner Losh * too slow. It's up to the user to free the object using
195*592ffb21SWarner Losh * call_rcu() or ttm_base_object_kfree().
196*592ffb21SWarner Losh */
197*592ffb21SWarner Losh
198*592ffb21SWarner Losh if (base->refcount_release) {
199*592ffb21SWarner Losh ttm_object_file_unref(&base->tfile);
200*592ffb21SWarner Losh base->refcount_release(&base);
201*592ffb21SWarner Losh }
202*592ffb21SWarner Losh rw_wlock(&tdev->object_lock);
203*592ffb21SWarner Losh }
204*592ffb21SWarner Losh
ttm_base_object_unref(struct ttm_base_object ** p_base)205*592ffb21SWarner Losh void ttm_base_object_unref(struct ttm_base_object **p_base)
206*592ffb21SWarner Losh {
207*592ffb21SWarner Losh struct ttm_base_object *base = *p_base;
208*592ffb21SWarner Losh struct ttm_object_device *tdev = base->tfile->tdev;
209*592ffb21SWarner Losh
210*592ffb21SWarner Losh *p_base = NULL;
211*592ffb21SWarner Losh
212*592ffb21SWarner Losh /*
213*592ffb21SWarner Losh * Need to take the lock here to avoid racing with
214*592ffb21SWarner Losh * users trying to look up the object.
215*592ffb21SWarner Losh */
216*592ffb21SWarner Losh
217*592ffb21SWarner Losh rw_wlock(&tdev->object_lock);
218*592ffb21SWarner Losh if (refcount_release(&base->refcount))
219*592ffb21SWarner Losh ttm_release_base(base);
220*592ffb21SWarner Losh rw_wunlock(&tdev->object_lock);
221*592ffb21SWarner Losh }
222*592ffb21SWarner Losh
ttm_base_object_lookup(struct ttm_object_file * tfile,uint32_t key)223*592ffb21SWarner Losh struct ttm_base_object *ttm_base_object_lookup(struct ttm_object_file *tfile,
224*592ffb21SWarner Losh uint32_t key)
225*592ffb21SWarner Losh {
226*592ffb21SWarner Losh struct ttm_object_device *tdev = tfile->tdev;
227*592ffb21SWarner Losh struct ttm_base_object *base;
228*592ffb21SWarner Losh struct drm_hash_item *hash;
229*592ffb21SWarner Losh int ret;
230*592ffb21SWarner Losh
231*592ffb21SWarner Losh rw_rlock(&tdev->object_lock);
232*592ffb21SWarner Losh ret = drm_ht_find_item(&tdev->object_hash, key, &hash);
233*592ffb21SWarner Losh
234*592ffb21SWarner Losh if (ret == 0) {
235*592ffb21SWarner Losh base = drm_hash_entry(hash, struct ttm_base_object, hash);
236*592ffb21SWarner Losh refcount_acquire(&base->refcount);
237*592ffb21SWarner Losh }
238*592ffb21SWarner Losh rw_runlock(&tdev->object_lock);
239*592ffb21SWarner Losh
240*592ffb21SWarner Losh if (unlikely(ret != 0))
241*592ffb21SWarner Losh return NULL;
242*592ffb21SWarner Losh
243*592ffb21SWarner Losh if (tfile != base->tfile && !base->shareable) {
244*592ffb21SWarner Losh printf("[TTM] Attempted access of non-shareable object %p\n",
245*592ffb21SWarner Losh base);
246*592ffb21SWarner Losh ttm_base_object_unref(&base);
247*592ffb21SWarner Losh return NULL;
248*592ffb21SWarner Losh }
249*592ffb21SWarner Losh
250*592ffb21SWarner Losh return base;
251*592ffb21SWarner Losh }
252*592ffb21SWarner Losh
253*592ffb21SWarner Losh MALLOC_DEFINE(M_TTM_OBJ_REF, "ttm_obj_ref", "TTM Ref Objects");
254*592ffb21SWarner Losh
ttm_ref_object_add(struct ttm_object_file * tfile,struct ttm_base_object * base,enum ttm_ref_type ref_type,bool * existed)255*592ffb21SWarner Losh int ttm_ref_object_add(struct ttm_object_file *tfile,
256*592ffb21SWarner Losh struct ttm_base_object *base,
257*592ffb21SWarner Losh enum ttm_ref_type ref_type, bool *existed)
258*592ffb21SWarner Losh {
259*592ffb21SWarner Losh struct drm_open_hash *ht = &tfile->ref_hash[ref_type];
260*592ffb21SWarner Losh struct ttm_ref_object *ref;
261*592ffb21SWarner Losh struct drm_hash_item *hash;
262*592ffb21SWarner Losh struct ttm_mem_global *mem_glob = tfile->tdev->mem_glob;
263*592ffb21SWarner Losh int ret = -EINVAL;
264*592ffb21SWarner Losh
265*592ffb21SWarner Losh if (existed != NULL)
266*592ffb21SWarner Losh *existed = true;
267*592ffb21SWarner Losh
268*592ffb21SWarner Losh while (ret == -EINVAL) {
269*592ffb21SWarner Losh rw_rlock(&tfile->lock);
270*592ffb21SWarner Losh ret = drm_ht_find_item(ht, base->hash.key, &hash);
271*592ffb21SWarner Losh
272*592ffb21SWarner Losh if (ret == 0) {
273*592ffb21SWarner Losh ref = drm_hash_entry(hash, struct ttm_ref_object, hash);
274*592ffb21SWarner Losh refcount_acquire(&ref->kref);
275*592ffb21SWarner Losh rw_runlock(&tfile->lock);
276*592ffb21SWarner Losh break;
277*592ffb21SWarner Losh }
278*592ffb21SWarner Losh
279*592ffb21SWarner Losh rw_runlock(&tfile->lock);
280*592ffb21SWarner Losh ret = ttm_mem_global_alloc(mem_glob, sizeof(*ref),
281*592ffb21SWarner Losh false, false);
282*592ffb21SWarner Losh if (unlikely(ret != 0))
283*592ffb21SWarner Losh return ret;
284*592ffb21SWarner Losh ref = malloc(sizeof(*ref), M_TTM_OBJ_REF, M_WAITOK);
285*592ffb21SWarner Losh ref->hash.key = base->hash.key;
286*592ffb21SWarner Losh ref->obj = base;
287*592ffb21SWarner Losh ref->tfile = tfile;
288*592ffb21SWarner Losh ref->ref_type = ref_type;
289*592ffb21SWarner Losh refcount_init(&ref->kref, 1);
290*592ffb21SWarner Losh
291*592ffb21SWarner Losh rw_wlock(&tfile->lock);
292*592ffb21SWarner Losh ret = drm_ht_insert_item(ht, &ref->hash);
293*592ffb21SWarner Losh
294*592ffb21SWarner Losh if (ret == 0) {
295*592ffb21SWarner Losh list_add_tail(&ref->head, &tfile->ref_list);
296*592ffb21SWarner Losh refcount_acquire(&base->refcount);
297*592ffb21SWarner Losh rw_wunlock(&tfile->lock);
298*592ffb21SWarner Losh if (existed != NULL)
299*592ffb21SWarner Losh *existed = false;
300*592ffb21SWarner Losh break;
301*592ffb21SWarner Losh }
302*592ffb21SWarner Losh
303*592ffb21SWarner Losh rw_wunlock(&tfile->lock);
304*592ffb21SWarner Losh MPASS(ret == -EINVAL);
305*592ffb21SWarner Losh
306*592ffb21SWarner Losh ttm_mem_global_free(mem_glob, sizeof(*ref));
307*592ffb21SWarner Losh free(ref, M_TTM_OBJ_REF);
308*592ffb21SWarner Losh }
309*592ffb21SWarner Losh
310*592ffb21SWarner Losh return ret;
311*592ffb21SWarner Losh }
312*592ffb21SWarner Losh
ttm_ref_object_release(struct ttm_ref_object * ref)313*592ffb21SWarner Losh static void ttm_ref_object_release(struct ttm_ref_object *ref)
314*592ffb21SWarner Losh {
315*592ffb21SWarner Losh struct ttm_base_object *base = ref->obj;
316*592ffb21SWarner Losh struct ttm_object_file *tfile = ref->tfile;
317*592ffb21SWarner Losh struct drm_open_hash *ht;
318*592ffb21SWarner Losh struct ttm_mem_global *mem_glob = tfile->tdev->mem_glob;
319*592ffb21SWarner Losh
320*592ffb21SWarner Losh ht = &tfile->ref_hash[ref->ref_type];
321*592ffb21SWarner Losh (void)drm_ht_remove_item(ht, &ref->hash);
322*592ffb21SWarner Losh list_del(&ref->head);
323*592ffb21SWarner Losh rw_wunlock(&tfile->lock);
324*592ffb21SWarner Losh
325*592ffb21SWarner Losh if (ref->ref_type != TTM_REF_USAGE && base->ref_obj_release)
326*592ffb21SWarner Losh base->ref_obj_release(base, ref->ref_type);
327*592ffb21SWarner Losh
328*592ffb21SWarner Losh ttm_base_object_unref(&ref->obj);
329*592ffb21SWarner Losh ttm_mem_global_free(mem_glob, sizeof(*ref));
330*592ffb21SWarner Losh free(ref, M_TTM_OBJ_REF);
331*592ffb21SWarner Losh rw_wlock(&tfile->lock);
332*592ffb21SWarner Losh }
333*592ffb21SWarner Losh
ttm_ref_object_base_unref(struct ttm_object_file * tfile,unsigned long key,enum ttm_ref_type ref_type)334*592ffb21SWarner Losh int ttm_ref_object_base_unref(struct ttm_object_file *tfile,
335*592ffb21SWarner Losh unsigned long key, enum ttm_ref_type ref_type)
336*592ffb21SWarner Losh {
337*592ffb21SWarner Losh struct drm_open_hash *ht = &tfile->ref_hash[ref_type];
338*592ffb21SWarner Losh struct ttm_ref_object *ref;
339*592ffb21SWarner Losh struct drm_hash_item *hash;
340*592ffb21SWarner Losh int ret;
341*592ffb21SWarner Losh
342*592ffb21SWarner Losh rw_wlock(&tfile->lock);
343*592ffb21SWarner Losh ret = drm_ht_find_item(ht, key, &hash);
344*592ffb21SWarner Losh if (unlikely(ret != 0)) {
345*592ffb21SWarner Losh rw_wunlock(&tfile->lock);
346*592ffb21SWarner Losh return -EINVAL;
347*592ffb21SWarner Losh }
348*592ffb21SWarner Losh ref = drm_hash_entry(hash, struct ttm_ref_object, hash);
349*592ffb21SWarner Losh if (refcount_release(&ref->kref))
350*592ffb21SWarner Losh ttm_ref_object_release(ref);
351*592ffb21SWarner Losh rw_wunlock(&tfile->lock);
352*592ffb21SWarner Losh return 0;
353*592ffb21SWarner Losh }
354*592ffb21SWarner Losh
ttm_object_file_release(struct ttm_object_file ** p_tfile)355*592ffb21SWarner Losh void ttm_object_file_release(struct ttm_object_file **p_tfile)
356*592ffb21SWarner Losh {
357*592ffb21SWarner Losh struct ttm_ref_object *ref;
358*592ffb21SWarner Losh struct list_head *list;
359*592ffb21SWarner Losh unsigned int i;
360*592ffb21SWarner Losh struct ttm_object_file *tfile = *p_tfile;
361*592ffb21SWarner Losh
362*592ffb21SWarner Losh *p_tfile = NULL;
363*592ffb21SWarner Losh rw_wlock(&tfile->lock);
364*592ffb21SWarner Losh
365*592ffb21SWarner Losh /*
366*592ffb21SWarner Losh * Since we release the lock within the loop, we have to
367*592ffb21SWarner Losh * restart it from the beginning each time.
368*592ffb21SWarner Losh */
369*592ffb21SWarner Losh
370*592ffb21SWarner Losh while (!list_empty(&tfile->ref_list)) {
371*592ffb21SWarner Losh list = tfile->ref_list.next;
372*592ffb21SWarner Losh ref = list_entry(list, struct ttm_ref_object, head);
373*592ffb21SWarner Losh ttm_ref_object_release(ref);
374*592ffb21SWarner Losh }
375*592ffb21SWarner Losh
376*592ffb21SWarner Losh for (i = 0; i < TTM_REF_NUM; ++i)
377*592ffb21SWarner Losh drm_ht_remove(&tfile->ref_hash[i]);
378*592ffb21SWarner Losh
379*592ffb21SWarner Losh rw_wunlock(&tfile->lock);
380*592ffb21SWarner Losh ttm_object_file_unref(&tfile);
381*592ffb21SWarner Losh }
382*592ffb21SWarner Losh
ttm_object_file_init(struct ttm_object_device * tdev,unsigned int hash_order)383*592ffb21SWarner Losh struct ttm_object_file *ttm_object_file_init(struct ttm_object_device *tdev,
384*592ffb21SWarner Losh unsigned int hash_order)
385*592ffb21SWarner Losh {
386*592ffb21SWarner Losh struct ttm_object_file *tfile;
387*592ffb21SWarner Losh unsigned int i;
388*592ffb21SWarner Losh unsigned int j = 0;
389*592ffb21SWarner Losh int ret;
390*592ffb21SWarner Losh
391*592ffb21SWarner Losh tfile = malloc(sizeof(*tfile), M_TTM_OBJ_FILE, M_WAITOK);
392*592ffb21SWarner Losh rw_init(&tfile->lock, "ttmfo");
393*592ffb21SWarner Losh tfile->tdev = tdev;
394*592ffb21SWarner Losh refcount_init(&tfile->refcount, 1);
395*592ffb21SWarner Losh INIT_LIST_HEAD(&tfile->ref_list);
396*592ffb21SWarner Losh
397*592ffb21SWarner Losh for (i = 0; i < TTM_REF_NUM; ++i) {
398*592ffb21SWarner Losh ret = drm_ht_create(&tfile->ref_hash[i], hash_order);
399*592ffb21SWarner Losh if (ret) {
400*592ffb21SWarner Losh j = i;
401*592ffb21SWarner Losh goto out_err;
402*592ffb21SWarner Losh }
403*592ffb21SWarner Losh }
404*592ffb21SWarner Losh
405*592ffb21SWarner Losh return tfile;
406*592ffb21SWarner Losh out_err:
407*592ffb21SWarner Losh for (i = 0; i < j; ++i)
408*592ffb21SWarner Losh drm_ht_remove(&tfile->ref_hash[i]);
409*592ffb21SWarner Losh
410*592ffb21SWarner Losh free(tfile, M_TTM_OBJ_FILE);
411*592ffb21SWarner Losh
412*592ffb21SWarner Losh return NULL;
413*592ffb21SWarner Losh }
414*592ffb21SWarner Losh
415*592ffb21SWarner Losh MALLOC_DEFINE(M_TTM_OBJ_DEV, "ttm_obj_dev", "TTM Device Objects");
416*592ffb21SWarner Losh
ttm_object_device_init(struct ttm_mem_global * mem_glob,unsigned int hash_order)417*592ffb21SWarner Losh struct ttm_object_device *ttm_object_device_init(struct ttm_mem_global
418*592ffb21SWarner Losh *mem_glob,
419*592ffb21SWarner Losh unsigned int hash_order)
420*592ffb21SWarner Losh {
421*592ffb21SWarner Losh struct ttm_object_device *tdev;
422*592ffb21SWarner Losh int ret;
423*592ffb21SWarner Losh
424*592ffb21SWarner Losh tdev = malloc(sizeof(*tdev), M_TTM_OBJ_DEV, M_WAITOK);
425*592ffb21SWarner Losh tdev->mem_glob = mem_glob;
426*592ffb21SWarner Losh rw_init(&tdev->object_lock, "ttmdo");
427*592ffb21SWarner Losh atomic_set(&tdev->object_count, 0);
428*592ffb21SWarner Losh ret = drm_ht_create(&tdev->object_hash, hash_order);
429*592ffb21SWarner Losh
430*592ffb21SWarner Losh if (ret == 0)
431*592ffb21SWarner Losh return tdev;
432*592ffb21SWarner Losh
433*592ffb21SWarner Losh free(tdev, M_TTM_OBJ_DEV);
434*592ffb21SWarner Losh return NULL;
435*592ffb21SWarner Losh }
436*592ffb21SWarner Losh
ttm_object_device_release(struct ttm_object_device ** p_tdev)437*592ffb21SWarner Losh void ttm_object_device_release(struct ttm_object_device **p_tdev)
438*592ffb21SWarner Losh {
439*592ffb21SWarner Losh struct ttm_object_device *tdev = *p_tdev;
440*592ffb21SWarner Losh
441*592ffb21SWarner Losh *p_tdev = NULL;
442*592ffb21SWarner Losh
443*592ffb21SWarner Losh rw_wlock(&tdev->object_lock);
444*592ffb21SWarner Losh drm_ht_remove(&tdev->object_hash);
445*592ffb21SWarner Losh rw_wunlock(&tdev->object_lock);
446*592ffb21SWarner Losh
447*592ffb21SWarner Losh free(tdev, M_TTM_OBJ_DEV);
448*592ffb21SWarner Losh }
449