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