xref: /freebsd/sys/dev/drm2/ttm/ttm_object.c (revision 592ffb217505586a6c69e91549a3c14132875f16)
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