xref: /freebsd/sys/dev/drm2/ttm/ttm_object.c (revision 685dc743)
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 /**
40592ffb21SWarner Losh  * struct ttm_object_file
41592ffb21SWarner Losh  *
42592ffb21SWarner Losh  * @tdev: Pointer to the ttm_object_device.
43592ffb21SWarner Losh  *
44592ffb21SWarner Losh  * @lock: Lock that protects the ref_list list and the
45592ffb21SWarner Losh  * ref_hash hash tables.
46592ffb21SWarner Losh  *
47592ffb21SWarner Losh  * @ref_list: List of ttm_ref_objects to be destroyed at
48592ffb21SWarner Losh  * file release.
49592ffb21SWarner Losh  *
50592ffb21SWarner Losh  * @ref_hash: Hash tables of ref objects, one per ttm_ref_type,
51592ffb21SWarner Losh  * for fast lookup of ref objects given a base object.
52592ffb21SWarner Losh  */
53592ffb21SWarner Losh 
54592ffb21SWarner Losh #define pr_fmt(fmt) "[TTM] " fmt
55592ffb21SWarner Losh 
56592ffb21SWarner Losh #include <dev/drm2/drmP.h>
57592ffb21SWarner Losh #include <dev/drm2/drm.h>
58592ffb21SWarner Losh #include <sys/rwlock.h>
59592ffb21SWarner Losh #include <dev/drm2/ttm/ttm_object.h>
60592ffb21SWarner Losh #include <dev/drm2/ttm/ttm_module.h>
61592ffb21SWarner Losh 
62592ffb21SWarner Losh struct ttm_object_file {
63592ffb21SWarner Losh 	struct ttm_object_device *tdev;
64592ffb21SWarner Losh 	struct rwlock lock;
65592ffb21SWarner Losh 	struct list_head ref_list;
66592ffb21SWarner Losh 	struct drm_open_hash ref_hash[TTM_REF_NUM];
67592ffb21SWarner Losh 	u_int refcount;
68592ffb21SWarner Losh };
69592ffb21SWarner Losh 
70592ffb21SWarner Losh /**
71592ffb21SWarner Losh  * struct ttm_object_device
72592ffb21SWarner Losh  *
73592ffb21SWarner Losh  * @object_lock: lock that protects the object_hash hash table.
74592ffb21SWarner Losh  *
75592ffb21SWarner Losh  * @object_hash: hash table for fast lookup of object global names.
76592ffb21SWarner Losh  *
77592ffb21SWarner Losh  * @object_count: Per device object count.
78592ffb21SWarner Losh  *
79592ffb21SWarner Losh  * This is the per-device data structure needed for ttm object management.
80592ffb21SWarner Losh  */
81592ffb21SWarner Losh 
82592ffb21SWarner Losh struct ttm_object_device {
83592ffb21SWarner Losh 	struct rwlock object_lock;
84592ffb21SWarner Losh 	struct drm_open_hash object_hash;
85592ffb21SWarner Losh 	atomic_t object_count;
86592ffb21SWarner Losh 	struct ttm_mem_global *mem_glob;
87592ffb21SWarner Losh };
88592ffb21SWarner Losh 
89592ffb21SWarner Losh /**
90592ffb21SWarner Losh  * struct ttm_ref_object
91592ffb21SWarner Losh  *
92592ffb21SWarner Losh  * @hash: Hash entry for the per-file object reference hash.
93592ffb21SWarner Losh  *
94592ffb21SWarner Losh  * @head: List entry for the per-file list of ref-objects.
95592ffb21SWarner Losh  *
96592ffb21SWarner Losh  * @kref: Ref count.
97592ffb21SWarner Losh  *
98592ffb21SWarner Losh  * @obj: Base object this ref object is referencing.
99592ffb21SWarner Losh  *
100592ffb21SWarner Losh  * @ref_type: Type of ref object.
101592ffb21SWarner Losh  *
102592ffb21SWarner Losh  * This is similar to an idr object, but it also has a hash table entry
103592ffb21SWarner Losh  * that allows lookup with a pointer to the referenced object as a key. In
104592ffb21SWarner Losh  * that way, one can easily detect whether a base object is referenced by
105592ffb21SWarner Losh  * a particular ttm_object_file. It also carries a ref count to avoid creating
106592ffb21SWarner Losh  * multiple ref objects if a ttm_object_file references the same base
107592ffb21SWarner Losh  * object more than once.
108592ffb21SWarner Losh  */
109592ffb21SWarner Losh 
110592ffb21SWarner Losh struct ttm_ref_object {
111592ffb21SWarner Losh 	struct drm_hash_item hash;
112592ffb21SWarner Losh 	struct list_head head;
113592ffb21SWarner Losh 	u_int kref;
114592ffb21SWarner Losh 	enum ttm_ref_type ref_type;
115592ffb21SWarner Losh 	struct ttm_base_object *obj;
116592ffb21SWarner Losh 	struct ttm_object_file *tfile;
117592ffb21SWarner Losh };
118592ffb21SWarner Losh 
119592ffb21SWarner Losh MALLOC_DEFINE(M_TTM_OBJ_FILE, "ttm_obj_file", "TTM File Objects");
120592ffb21SWarner Losh 
121592ffb21SWarner Losh static inline struct ttm_object_file *
ttm_object_file_ref(struct ttm_object_file * tfile)122592ffb21SWarner Losh ttm_object_file_ref(struct ttm_object_file *tfile)
123592ffb21SWarner Losh {
124592ffb21SWarner Losh 	refcount_acquire(&tfile->refcount);
125592ffb21SWarner Losh 	return tfile;
126592ffb21SWarner Losh }
127592ffb21SWarner Losh 
ttm_object_file_destroy(struct ttm_object_file * tfile)128592ffb21SWarner Losh static void ttm_object_file_destroy(struct ttm_object_file *tfile)
129592ffb21SWarner Losh {
130592ffb21SWarner Losh 
131592ffb21SWarner Losh 	free(tfile, M_TTM_OBJ_FILE);
132592ffb21SWarner Losh }
133592ffb21SWarner Losh 
134592ffb21SWarner Losh 
ttm_object_file_unref(struct ttm_object_file ** p_tfile)135592ffb21SWarner Losh static inline void ttm_object_file_unref(struct ttm_object_file **p_tfile)
136592ffb21SWarner Losh {
137592ffb21SWarner Losh 	struct ttm_object_file *tfile = *p_tfile;
138592ffb21SWarner Losh 
139592ffb21SWarner Losh 	*p_tfile = NULL;
140592ffb21SWarner Losh 	if (refcount_release(&tfile->refcount))
141592ffb21SWarner Losh 		ttm_object_file_destroy(tfile);
142592ffb21SWarner Losh }
143592ffb21SWarner Losh 
144592ffb21SWarner 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))145592ffb21SWarner Losh int ttm_base_object_init(struct ttm_object_file *tfile,
146592ffb21SWarner Losh 			 struct ttm_base_object *base,
147592ffb21SWarner Losh 			 bool shareable,
148592ffb21SWarner Losh 			 enum ttm_object_type object_type,
149592ffb21SWarner Losh 			 void (*rcount_release) (struct ttm_base_object **),
150592ffb21SWarner Losh 			 void (*ref_obj_release) (struct ttm_base_object *,
151592ffb21SWarner Losh 						  enum ttm_ref_type ref_type))
152592ffb21SWarner Losh {
153592ffb21SWarner Losh 	struct ttm_object_device *tdev = tfile->tdev;
154592ffb21SWarner Losh 	int ret;
155592ffb21SWarner Losh 
156592ffb21SWarner Losh 	base->shareable = shareable;
157592ffb21SWarner Losh 	base->tfile = ttm_object_file_ref(tfile);
158592ffb21SWarner Losh 	base->refcount_release = rcount_release;
159592ffb21SWarner Losh 	base->ref_obj_release = ref_obj_release;
160592ffb21SWarner Losh 	base->object_type = object_type;
161592ffb21SWarner Losh 	refcount_init(&base->refcount, 1);
162592ffb21SWarner Losh 	rw_init(&tdev->object_lock, "ttmbao");
163592ffb21SWarner Losh 	rw_wlock(&tdev->object_lock);
164592ffb21SWarner Losh 	ret = drm_ht_just_insert_please(&tdev->object_hash,
165592ffb21SWarner Losh 					    &base->hash,
166592ffb21SWarner Losh 					    (unsigned long)base, 31, 0, 0);
167592ffb21SWarner Losh 	rw_wunlock(&tdev->object_lock);
168592ffb21SWarner Losh 	if (unlikely(ret != 0))
169592ffb21SWarner Losh 		goto out_err0;
170592ffb21SWarner Losh 
171592ffb21SWarner Losh 	ret = ttm_ref_object_add(tfile, base, TTM_REF_USAGE, NULL);
172592ffb21SWarner Losh 	if (unlikely(ret != 0))
173592ffb21SWarner Losh 		goto out_err1;
174592ffb21SWarner Losh 
175592ffb21SWarner Losh 	ttm_base_object_unref(&base);
176592ffb21SWarner Losh 
177592ffb21SWarner Losh 	return 0;
178592ffb21SWarner Losh out_err1:
179592ffb21SWarner Losh 	rw_wlock(&tdev->object_lock);
180592ffb21SWarner Losh 	(void)drm_ht_remove_item(&tdev->object_hash, &base->hash);
181592ffb21SWarner Losh 	rw_wunlock(&tdev->object_lock);
182592ffb21SWarner Losh out_err0:
183592ffb21SWarner Losh 	return ret;
184592ffb21SWarner Losh }
185592ffb21SWarner Losh 
ttm_release_base(struct ttm_base_object * base)186592ffb21SWarner Losh static void ttm_release_base(struct ttm_base_object *base)
187592ffb21SWarner Losh {
188592ffb21SWarner Losh 	struct ttm_object_device *tdev = base->tfile->tdev;
189592ffb21SWarner Losh 
190592ffb21SWarner Losh 	(void)drm_ht_remove_item(&tdev->object_hash, &base->hash);
191592ffb21SWarner Losh 	rw_wunlock(&tdev->object_lock);
192592ffb21SWarner Losh 	/*
193592ffb21SWarner Losh 	 * Note: We don't use synchronize_rcu() here because it's far
194592ffb21SWarner Losh 	 * too slow. It's up to the user to free the object using
195592ffb21SWarner Losh 	 * call_rcu() or ttm_base_object_kfree().
196592ffb21SWarner Losh 	 */
197592ffb21SWarner Losh 
198592ffb21SWarner Losh 	if (base->refcount_release) {
199592ffb21SWarner Losh 		ttm_object_file_unref(&base->tfile);
200592ffb21SWarner Losh 		base->refcount_release(&base);
201592ffb21SWarner Losh 	}
202592ffb21SWarner Losh 	rw_wlock(&tdev->object_lock);
203592ffb21SWarner Losh }
204592ffb21SWarner Losh 
ttm_base_object_unref(struct ttm_base_object ** p_base)205592ffb21SWarner Losh void ttm_base_object_unref(struct ttm_base_object **p_base)
206592ffb21SWarner Losh {
207592ffb21SWarner Losh 	struct ttm_base_object *base = *p_base;
208592ffb21SWarner Losh 	struct ttm_object_device *tdev = base->tfile->tdev;
209592ffb21SWarner Losh 
210592ffb21SWarner Losh 	*p_base = NULL;
211592ffb21SWarner Losh 
212592ffb21SWarner Losh 	/*
213592ffb21SWarner Losh 	 * Need to take the lock here to avoid racing with
214592ffb21SWarner Losh 	 * users trying to look up the object.
215592ffb21SWarner Losh 	 */
216592ffb21SWarner Losh 
217592ffb21SWarner Losh 	rw_wlock(&tdev->object_lock);
218592ffb21SWarner Losh 	if (refcount_release(&base->refcount))
219592ffb21SWarner Losh 		ttm_release_base(base);
220592ffb21SWarner Losh 	rw_wunlock(&tdev->object_lock);
221592ffb21SWarner Losh }
222592ffb21SWarner Losh 
ttm_base_object_lookup(struct ttm_object_file * tfile,uint32_t key)223592ffb21SWarner Losh struct ttm_base_object *ttm_base_object_lookup(struct ttm_object_file *tfile,
224592ffb21SWarner Losh 					       uint32_t key)
225592ffb21SWarner Losh {
226592ffb21SWarner Losh 	struct ttm_object_device *tdev = tfile->tdev;
227592ffb21SWarner Losh 	struct ttm_base_object *base;
228592ffb21SWarner Losh 	struct drm_hash_item *hash;
229592ffb21SWarner Losh 	int ret;
230592ffb21SWarner Losh 
231592ffb21SWarner Losh 	rw_rlock(&tdev->object_lock);
232592ffb21SWarner Losh 	ret = drm_ht_find_item(&tdev->object_hash, key, &hash);
233592ffb21SWarner Losh 
234592ffb21SWarner Losh 	if (ret == 0) {
235592ffb21SWarner Losh 		base = drm_hash_entry(hash, struct ttm_base_object, hash);
236592ffb21SWarner Losh 		refcount_acquire(&base->refcount);
237592ffb21SWarner Losh 	}
238592ffb21SWarner Losh 	rw_runlock(&tdev->object_lock);
239592ffb21SWarner Losh 
240592ffb21SWarner Losh 	if (unlikely(ret != 0))
241592ffb21SWarner Losh 		return NULL;
242592ffb21SWarner Losh 
243592ffb21SWarner Losh 	if (tfile != base->tfile && !base->shareable) {
244592ffb21SWarner Losh 		printf("[TTM] Attempted access of non-shareable object %p\n",
245592ffb21SWarner Losh 		    base);
246592ffb21SWarner Losh 		ttm_base_object_unref(&base);
247592ffb21SWarner Losh 		return NULL;
248592ffb21SWarner Losh 	}
249592ffb21SWarner Losh 
250592ffb21SWarner Losh 	return base;
251592ffb21SWarner Losh }
252592ffb21SWarner Losh 
253592ffb21SWarner Losh MALLOC_DEFINE(M_TTM_OBJ_REF, "ttm_obj_ref", "TTM Ref Objects");
254592ffb21SWarner Losh 
ttm_ref_object_add(struct ttm_object_file * tfile,struct ttm_base_object * base,enum ttm_ref_type ref_type,bool * existed)255592ffb21SWarner Losh int ttm_ref_object_add(struct ttm_object_file *tfile,
256592ffb21SWarner Losh 		       struct ttm_base_object *base,
257592ffb21SWarner Losh 		       enum ttm_ref_type ref_type, bool *existed)
258592ffb21SWarner Losh {
259592ffb21SWarner Losh 	struct drm_open_hash *ht = &tfile->ref_hash[ref_type];
260592ffb21SWarner Losh 	struct ttm_ref_object *ref;
261592ffb21SWarner Losh 	struct drm_hash_item *hash;
262592ffb21SWarner Losh 	struct ttm_mem_global *mem_glob = tfile->tdev->mem_glob;
263592ffb21SWarner Losh 	int ret = -EINVAL;
264592ffb21SWarner Losh 
265592ffb21SWarner Losh 	if (existed != NULL)
266592ffb21SWarner Losh 		*existed = true;
267592ffb21SWarner Losh 
268592ffb21SWarner Losh 	while (ret == -EINVAL) {
269592ffb21SWarner Losh 		rw_rlock(&tfile->lock);
270592ffb21SWarner Losh 		ret = drm_ht_find_item(ht, base->hash.key, &hash);
271592ffb21SWarner Losh 
272592ffb21SWarner Losh 		if (ret == 0) {
273592ffb21SWarner Losh 			ref = drm_hash_entry(hash, struct ttm_ref_object, hash);
274592ffb21SWarner Losh 			refcount_acquire(&ref->kref);
275592ffb21SWarner Losh 			rw_runlock(&tfile->lock);
276592ffb21SWarner Losh 			break;
277592ffb21SWarner Losh 		}
278592ffb21SWarner Losh 
279592ffb21SWarner Losh 		rw_runlock(&tfile->lock);
280592ffb21SWarner Losh 		ret = ttm_mem_global_alloc(mem_glob, sizeof(*ref),
281592ffb21SWarner Losh 					   false, false);
282592ffb21SWarner Losh 		if (unlikely(ret != 0))
283592ffb21SWarner Losh 			return ret;
284592ffb21SWarner Losh 		ref = malloc(sizeof(*ref), M_TTM_OBJ_REF, M_WAITOK);
285592ffb21SWarner Losh 		if (unlikely(ref == NULL)) {
286592ffb21SWarner Losh 			ttm_mem_global_free(mem_glob, sizeof(*ref));
287592ffb21SWarner Losh 			return -ENOMEM;
288592ffb21SWarner Losh 		}
289592ffb21SWarner Losh 
290592ffb21SWarner Losh 		ref->hash.key = base->hash.key;
291592ffb21SWarner Losh 		ref->obj = base;
292592ffb21SWarner Losh 		ref->tfile = tfile;
293592ffb21SWarner Losh 		ref->ref_type = ref_type;
294592ffb21SWarner Losh 		refcount_init(&ref->kref, 1);
295592ffb21SWarner Losh 
296592ffb21SWarner Losh 		rw_wlock(&tfile->lock);
297592ffb21SWarner Losh 		ret = drm_ht_insert_item(ht, &ref->hash);
298592ffb21SWarner Losh 
299592ffb21SWarner Losh 		if (ret == 0) {
300592ffb21SWarner Losh 			list_add_tail(&ref->head, &tfile->ref_list);
301592ffb21SWarner Losh 			refcount_acquire(&base->refcount);
302592ffb21SWarner Losh 			rw_wunlock(&tfile->lock);
303592ffb21SWarner Losh 			if (existed != NULL)
304592ffb21SWarner Losh 				*existed = false;
305592ffb21SWarner Losh 			break;
306592ffb21SWarner Losh 		}
307592ffb21SWarner Losh 
308592ffb21SWarner Losh 		rw_wunlock(&tfile->lock);
309592ffb21SWarner Losh 		MPASS(ret == -EINVAL);
310592ffb21SWarner Losh 
311592ffb21SWarner Losh 		ttm_mem_global_free(mem_glob, sizeof(*ref));
312592ffb21SWarner Losh 		free(ref, M_TTM_OBJ_REF);
313592ffb21SWarner Losh 	}
314592ffb21SWarner Losh 
315592ffb21SWarner Losh 	return ret;
316592ffb21SWarner Losh }
317592ffb21SWarner Losh 
ttm_ref_object_release(struct ttm_ref_object * ref)318592ffb21SWarner Losh static void ttm_ref_object_release(struct ttm_ref_object *ref)
319592ffb21SWarner Losh {
320592ffb21SWarner Losh 	struct ttm_base_object *base = ref->obj;
321592ffb21SWarner Losh 	struct ttm_object_file *tfile = ref->tfile;
322592ffb21SWarner Losh 	struct drm_open_hash *ht;
323592ffb21SWarner Losh 	struct ttm_mem_global *mem_glob = tfile->tdev->mem_glob;
324592ffb21SWarner Losh 
325592ffb21SWarner Losh 	ht = &tfile->ref_hash[ref->ref_type];
326592ffb21SWarner Losh 	(void)drm_ht_remove_item(ht, &ref->hash);
327592ffb21SWarner Losh 	list_del(&ref->head);
328592ffb21SWarner Losh 	rw_wunlock(&tfile->lock);
329592ffb21SWarner Losh 
330592ffb21SWarner Losh 	if (ref->ref_type != TTM_REF_USAGE && base->ref_obj_release)
331592ffb21SWarner Losh 		base->ref_obj_release(base, ref->ref_type);
332592ffb21SWarner Losh 
333592ffb21SWarner Losh 	ttm_base_object_unref(&ref->obj);
334592ffb21SWarner Losh 	ttm_mem_global_free(mem_glob, sizeof(*ref));
335592ffb21SWarner Losh 	free(ref, M_TTM_OBJ_REF);
336592ffb21SWarner Losh 	rw_wlock(&tfile->lock);
337592ffb21SWarner Losh }
338592ffb21SWarner Losh 
ttm_ref_object_base_unref(struct ttm_object_file * tfile,unsigned long key,enum ttm_ref_type ref_type)339592ffb21SWarner Losh int ttm_ref_object_base_unref(struct ttm_object_file *tfile,
340592ffb21SWarner Losh 			      unsigned long key, enum ttm_ref_type ref_type)
341592ffb21SWarner Losh {
342592ffb21SWarner Losh 	struct drm_open_hash *ht = &tfile->ref_hash[ref_type];
343592ffb21SWarner Losh 	struct ttm_ref_object *ref;
344592ffb21SWarner Losh 	struct drm_hash_item *hash;
345592ffb21SWarner Losh 	int ret;
346592ffb21SWarner Losh 
347592ffb21SWarner Losh 	rw_wlock(&tfile->lock);
348592ffb21SWarner Losh 	ret = drm_ht_find_item(ht, key, &hash);
349592ffb21SWarner Losh 	if (unlikely(ret != 0)) {
350592ffb21SWarner Losh 		rw_wunlock(&tfile->lock);
351592ffb21SWarner Losh 		return -EINVAL;
352592ffb21SWarner Losh 	}
353592ffb21SWarner Losh 	ref = drm_hash_entry(hash, struct ttm_ref_object, hash);
354592ffb21SWarner Losh 	if (refcount_release(&ref->kref))
355592ffb21SWarner Losh 		ttm_ref_object_release(ref);
356592ffb21SWarner Losh 	rw_wunlock(&tfile->lock);
357592ffb21SWarner Losh 	return 0;
358592ffb21SWarner Losh }
359592ffb21SWarner Losh 
ttm_object_file_release(struct ttm_object_file ** p_tfile)360592ffb21SWarner Losh void ttm_object_file_release(struct ttm_object_file **p_tfile)
361592ffb21SWarner Losh {
362592ffb21SWarner Losh 	struct ttm_ref_object *ref;
363592ffb21SWarner Losh 	struct list_head *list;
364592ffb21SWarner Losh 	unsigned int i;
365592ffb21SWarner Losh 	struct ttm_object_file *tfile = *p_tfile;
366592ffb21SWarner Losh 
367592ffb21SWarner Losh 	*p_tfile = NULL;
368592ffb21SWarner Losh 	rw_wlock(&tfile->lock);
369592ffb21SWarner Losh 
370592ffb21SWarner Losh 	/*
371592ffb21SWarner Losh 	 * Since we release the lock within the loop, we have to
372592ffb21SWarner Losh 	 * restart it from the beginning each time.
373592ffb21SWarner Losh 	 */
374592ffb21SWarner Losh 
375592ffb21SWarner Losh 	while (!list_empty(&tfile->ref_list)) {
376592ffb21SWarner Losh 		list = tfile->ref_list.next;
377592ffb21SWarner Losh 		ref = list_entry(list, struct ttm_ref_object, head);
378592ffb21SWarner Losh 		ttm_ref_object_release(ref);
379592ffb21SWarner Losh 	}
380592ffb21SWarner Losh 
381592ffb21SWarner Losh 	for (i = 0; i < TTM_REF_NUM; ++i)
382592ffb21SWarner Losh 		drm_ht_remove(&tfile->ref_hash[i]);
383592ffb21SWarner Losh 
384592ffb21SWarner Losh 	rw_wunlock(&tfile->lock);
385592ffb21SWarner Losh 	ttm_object_file_unref(&tfile);
386592ffb21SWarner Losh }
387592ffb21SWarner Losh 
ttm_object_file_init(struct ttm_object_device * tdev,unsigned int hash_order)388592ffb21SWarner Losh struct ttm_object_file *ttm_object_file_init(struct ttm_object_device *tdev,
389592ffb21SWarner Losh 					     unsigned int hash_order)
390592ffb21SWarner Losh {
391592ffb21SWarner Losh 	struct ttm_object_file *tfile;
392592ffb21SWarner Losh 	unsigned int i;
393592ffb21SWarner Losh 	unsigned int j = 0;
394592ffb21SWarner Losh 	int ret;
395592ffb21SWarner Losh 
396592ffb21SWarner Losh 	tfile = malloc(sizeof(*tfile), M_TTM_OBJ_FILE, M_WAITOK);
397592ffb21SWarner Losh 	rw_init(&tfile->lock, "ttmfo");
398592ffb21SWarner Losh 	tfile->tdev = tdev;
399592ffb21SWarner Losh 	refcount_init(&tfile->refcount, 1);
400592ffb21SWarner Losh 	INIT_LIST_HEAD(&tfile->ref_list);
401592ffb21SWarner Losh 
402592ffb21SWarner Losh 	for (i = 0; i < TTM_REF_NUM; ++i) {
403592ffb21SWarner Losh 		ret = drm_ht_create(&tfile->ref_hash[i], hash_order);
404592ffb21SWarner Losh 		if (ret) {
405592ffb21SWarner Losh 			j = i;
406592ffb21SWarner Losh 			goto out_err;
407592ffb21SWarner Losh 		}
408592ffb21SWarner Losh 	}
409592ffb21SWarner Losh 
410592ffb21SWarner Losh 	return tfile;
411592ffb21SWarner Losh out_err:
412592ffb21SWarner Losh 	for (i = 0; i < j; ++i)
413592ffb21SWarner Losh 		drm_ht_remove(&tfile->ref_hash[i]);
414592ffb21SWarner Losh 
415592ffb21SWarner Losh 	free(tfile, M_TTM_OBJ_FILE);
416592ffb21SWarner Losh 
417592ffb21SWarner Losh 	return NULL;
418592ffb21SWarner Losh }
419592ffb21SWarner Losh 
420592ffb21SWarner Losh MALLOC_DEFINE(M_TTM_OBJ_DEV, "ttm_obj_dev", "TTM Device Objects");
421592ffb21SWarner Losh 
ttm_object_device_init(struct ttm_mem_global * mem_glob,unsigned int hash_order)422592ffb21SWarner Losh struct ttm_object_device *ttm_object_device_init(struct ttm_mem_global
423592ffb21SWarner Losh 						 *mem_glob,
424592ffb21SWarner Losh 						 unsigned int hash_order)
425592ffb21SWarner Losh {
426592ffb21SWarner Losh 	struct ttm_object_device *tdev;
427592ffb21SWarner Losh 	int ret;
428592ffb21SWarner Losh 
429592ffb21SWarner Losh 	tdev = malloc(sizeof(*tdev), M_TTM_OBJ_DEV, M_WAITOK);
430592ffb21SWarner Losh 	tdev->mem_glob = mem_glob;
431592ffb21SWarner Losh 	rw_init(&tdev->object_lock, "ttmdo");
432592ffb21SWarner Losh 	atomic_set(&tdev->object_count, 0);
433592ffb21SWarner Losh 	ret = drm_ht_create(&tdev->object_hash, hash_order);
434592ffb21SWarner Losh 
435592ffb21SWarner Losh 	if (ret == 0)
436592ffb21SWarner Losh 		return tdev;
437592ffb21SWarner Losh 
438592ffb21SWarner Losh 	free(tdev, M_TTM_OBJ_DEV);
439592ffb21SWarner Losh 	return NULL;
440592ffb21SWarner Losh }
441592ffb21SWarner Losh 
ttm_object_device_release(struct ttm_object_device ** p_tdev)442592ffb21SWarner Losh void ttm_object_device_release(struct ttm_object_device **p_tdev)
443592ffb21SWarner Losh {
444592ffb21SWarner Losh 	struct ttm_object_device *tdev = *p_tdev;
445592ffb21SWarner Losh 
446592ffb21SWarner Losh 	*p_tdev = NULL;
447592ffb21SWarner Losh 
448592ffb21SWarner Losh 	rw_wlock(&tdev->object_lock);
449592ffb21SWarner Losh 	drm_ht_remove(&tdev->object_hash);
450592ffb21SWarner Losh 	rw_wunlock(&tdev->object_lock);
451592ffb21SWarner Losh 
452592ffb21SWarner Losh 	free(tdev, M_TTM_OBJ_DEV);
453592ffb21SWarner Losh }
454