1 /*	$NetBSD: ttm_object.c,v 1.3 2022/02/17 01:21:02 riastradh Exp $	*/
2 
3 /* SPDX-License-Identifier: GPL-2.0 OR MIT */
4 /**************************************************************************
5  *
6  * Copyright (c) 2009-2013 VMware, Inc., Palo Alto, CA., USA
7  * All Rights Reserved.
8  *
9  * Permission is hereby granted, free of charge, to any person obtaining a
10  * copy of this software and associated documentation files (the
11  * "Software"), to deal in the Software without restriction, including
12  * without limitation the rights to use, copy, modify, merge, publish,
13  * distribute, sub license, and/or sell copies of the Software, and to
14  * permit persons to whom the Software is furnished to do so, subject to
15  * the following conditions:
16  *
17  * The above copyright notice and this permission notice (including the
18  * next paragraph) shall be included in all copies or substantial portions
19  * of the Software.
20  *
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
24  * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
25  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
26  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
27  * USE OR OTHER DEALINGS IN THE SOFTWARE.
28  *
29  **************************************************************************/
30 /*
31  * Authors: Thomas Hellstrom <thellstrom-at-vmware-dot-com>
32  *
33  * While no substantial code is shared, the prime code is inspired by
34  * drm_prime.c, with
35  * Authors:
36  *      Dave Airlie <airlied@redhat.com>
37  *      Rob Clark <rob.clark@linaro.org>
38  */
39 /** @file ttm_ref_object.c
40  *
41  * Base- and reference object implementation for the various
42  * ttm objects. Implements reference counting, minimal security checks
43  * and release on file close.
44  */
45 
46 
47 /**
48  * struct ttm_object_file
49  *
50  * @tdev: Pointer to the ttm_object_device.
51  *
52  * @lock: Lock that protects the ref_list list and the
53  * ref_hash hash tables.
54  *
55  * @ref_list: List of ttm_ref_objects to be destroyed at
56  * file release.
57  *
58  * @ref_hash: Hash tables of ref objects, one per ttm_ref_type,
59  * for fast lookup of ref objects given a base object.
60  */
61 
62 #include <sys/cdefs.h>
63 __KERNEL_RCSID(0, "$NetBSD: ttm_object.c,v 1.3 2022/02/17 01:21:02 riastradh Exp $");
64 
65 #define pr_fmt(fmt) "[TTM] " fmt
66 
67 #include <drm/ttm/ttm_module.h>
68 #include <linux/list.h>
69 #include <linux/spinlock.h>
70 #include <linux/slab.h>
71 #include <linux/atomic.h>
72 #include "ttm_object.h"
73 
74 #include <linux/nbsd-namespace.h>
75 
76 struct ttm_object_file {
77 	struct ttm_object_device *tdev;
78 	spinlock_t lock;
79 	struct list_head ref_list;
80 	struct drm_open_hash ref_hash[TTM_REF_NUM];
81 	struct kref refcount;
82 };
83 
84 /**
85  * struct ttm_object_device
86  *
87  * @object_lock: lock that protects the object_hash hash table.
88  *
89  * @object_hash: hash table for fast lookup of object global names.
90  *
91  * @object_count: Per device object count.
92  *
93  * This is the per-device data structure needed for ttm object management.
94  */
95 
96 struct ttm_object_device {
97 	spinlock_t object_lock;
98 	struct drm_open_hash object_hash;
99 	atomic_t object_count;
100 	struct ttm_mem_global *mem_glob;
101 	struct dma_buf_ops ops;
102 	void (*dmabuf_release)(struct dma_buf *dma_buf);
103 	size_t dma_buf_size;
104 	struct idr idr;
105 };
106 
107 /**
108  * struct ttm_ref_object
109  *
110  * @hash: Hash entry for the per-file object reference hash.
111  *
112  * @head: List entry for the per-file list of ref-objects.
113  *
114  * @kref: Ref count.
115  *
116  * @obj: Base object this ref object is referencing.
117  *
118  * @ref_type: Type of ref object.
119  *
120  * This is similar to an idr object, but it also has a hash table entry
121  * that allows lookup with a pointer to the referenced object as a key. In
122  * that way, one can easily detect whether a base object is referenced by
123  * a particular ttm_object_file. It also carries a ref count to avoid creating
124  * multiple ref objects if a ttm_object_file references the same base
125  * object more than once.
126  */
127 
128 struct ttm_ref_object {
129 	struct rcu_head rcu_head;
130 	struct drm_hash_item hash;
131 	struct list_head head;
132 	struct kref kref;
133 	enum ttm_ref_type ref_type;
134 	struct ttm_base_object *obj;
135 	struct ttm_object_file *tfile;
136 };
137 
138 static void ttm_prime_dmabuf_release(struct dma_buf *dma_buf);
139 
140 static inline struct ttm_object_file *
ttm_object_file_ref(struct ttm_object_file * tfile)141 ttm_object_file_ref(struct ttm_object_file *tfile)
142 {
143 	kref_get(&tfile->refcount);
144 	return tfile;
145 }
146 
ttm_object_file_destroy(struct kref * kref)147 static void ttm_object_file_destroy(struct kref *kref)
148 {
149 	struct ttm_object_file *tfile =
150 		container_of(kref, struct ttm_object_file, refcount);
151 
152 	kfree(tfile);
153 }
154 
155 
ttm_object_file_unref(struct ttm_object_file ** p_tfile)156 static inline void ttm_object_file_unref(struct ttm_object_file **p_tfile)
157 {
158 	struct ttm_object_file *tfile = *p_tfile;
159 
160 	*p_tfile = NULL;
161 	kref_put(&tfile->refcount, ttm_object_file_destroy);
162 }
163 
164 
ttm_base_object_init(struct ttm_object_file * tfile,struct ttm_base_object * base,bool shareable,enum ttm_object_type object_type,void (* refcount_release)(struct ttm_base_object **),void (* ref_obj_release)(struct ttm_base_object *,enum ttm_ref_type ref_type))165 int ttm_base_object_init(struct ttm_object_file *tfile,
166 			 struct ttm_base_object *base,
167 			 bool shareable,
168 			 enum ttm_object_type object_type,
169 			 void (*refcount_release) (struct ttm_base_object **),
170 			 void (*ref_obj_release) (struct ttm_base_object *,
171 						  enum ttm_ref_type ref_type))
172 {
173 	struct ttm_object_device *tdev = tfile->tdev;
174 	int ret;
175 
176 	base->shareable = shareable;
177 	base->tfile = ttm_object_file_ref(tfile);
178 	base->refcount_release = refcount_release;
179 	base->ref_obj_release = ref_obj_release;
180 	base->object_type = object_type;
181 	kref_init(&base->refcount);
182 	idr_preload(GFP_KERNEL);
183 	spin_lock(&tdev->object_lock);
184 	ret = idr_alloc(&tdev->idr, base, 1, 0, GFP_NOWAIT);
185 	spin_unlock(&tdev->object_lock);
186 	idr_preload_end();
187 	if (ret < 0)
188 		return ret;
189 
190 	base->handle = ret;
191 	ret = ttm_ref_object_add(tfile, base, TTM_REF_USAGE, NULL, false);
192 	if (unlikely(ret != 0))
193 		goto out_err1;
194 
195 	ttm_base_object_unref(&base);
196 
197 	return 0;
198 out_err1:
199 	spin_lock(&tdev->object_lock);
200 	idr_remove(&tdev->idr, base->handle);
201 	spin_unlock(&tdev->object_lock);
202 	return ret;
203 }
204 
ttm_release_base(struct kref * kref)205 static void ttm_release_base(struct kref *kref)
206 {
207 	struct ttm_base_object *base =
208 	    container_of(kref, struct ttm_base_object, refcount);
209 	struct ttm_object_device *tdev = base->tfile->tdev;
210 
211 	spin_lock(&tdev->object_lock);
212 	idr_remove(&tdev->idr, base->handle);
213 	spin_unlock(&tdev->object_lock);
214 
215 	/*
216 	 * Note: We don't use synchronize_rcu() here because it's far
217 	 * too slow. It's up to the user to free the object using
218 	 * call_rcu() or ttm_base_object_kfree().
219 	 */
220 
221 	ttm_object_file_unref(&base->tfile);
222 	if (base->refcount_release)
223 		base->refcount_release(&base);
224 }
225 
ttm_base_object_unref(struct ttm_base_object ** p_base)226 void ttm_base_object_unref(struct ttm_base_object **p_base)
227 {
228 	struct ttm_base_object *base = *p_base;
229 
230 	*p_base = NULL;
231 
232 	kref_put(&base->refcount, ttm_release_base);
233 }
234 
235 /**
236  * ttm_base_object_noref_lookup - look up a base object without reference
237  * @tfile: The struct ttm_object_file the object is registered with.
238  * @key: The object handle.
239  *
240  * This function looks up a ttm base object and returns a pointer to it
241  * without refcounting the pointer. The returned pointer is only valid
242  * until ttm_base_object_noref_release() is called, and the object
243  * pointed to by the returned pointer may be doomed. Any persistent usage
244  * of the object requires a refcount to be taken using kref_get_unless_zero().
245  * Iff this function returns successfully it needs to be paired with
246  * ttm_base_object_noref_release() and no sleeping- or scheduling functions
247  * may be called inbetween these function callse.
248  *
249  * Return: A pointer to the object if successful or NULL otherwise.
250  */
251 struct ttm_base_object *
ttm_base_object_noref_lookup(struct ttm_object_file * tfile,uint32_t key)252 ttm_base_object_noref_lookup(struct ttm_object_file *tfile, uint32_t key)
253 {
254 	struct drm_hash_item *hash;
255 	struct drm_open_hash *ht = &tfile->ref_hash[TTM_REF_USAGE];
256 	int ret;
257 
258 	rcu_read_lock();
259 	ret = drm_ht_find_item_rcu(ht, key, &hash);
260 	if (ret) {
261 		rcu_read_unlock();
262 		return NULL;
263 	}
264 
265 	__release(RCU);
266 	return drm_hash_entry(hash, struct ttm_ref_object, hash)->obj;
267 }
268 EXPORT_SYMBOL(ttm_base_object_noref_lookup);
269 
ttm_base_object_lookup(struct ttm_object_file * tfile,uint32_t key)270 struct ttm_base_object *ttm_base_object_lookup(struct ttm_object_file *tfile,
271 					       uint32_t key)
272 {
273 	struct ttm_base_object *base = NULL;
274 	struct drm_hash_item *hash;
275 	struct drm_open_hash *ht = &tfile->ref_hash[TTM_REF_USAGE];
276 	int ret;
277 
278 	rcu_read_lock();
279 	ret = drm_ht_find_item_rcu(ht, key, &hash);
280 
281 	if (likely(ret == 0)) {
282 		base = drm_hash_entry(hash, struct ttm_ref_object, hash)->obj;
283 		if (!kref_get_unless_zero(&base->refcount))
284 			base = NULL;
285 	}
286 	rcu_read_unlock();
287 
288 	return base;
289 }
290 
291 struct ttm_base_object *
ttm_base_object_lookup_for_ref(struct ttm_object_device * tdev,uint32_t key)292 ttm_base_object_lookup_for_ref(struct ttm_object_device *tdev, uint32_t key)
293 {
294 	struct ttm_base_object *base;
295 
296 	rcu_read_lock();
297 	base = idr_find(&tdev->idr, key);
298 
299 	if (base && !kref_get_unless_zero(&base->refcount))
300 		base = NULL;
301 	rcu_read_unlock();
302 
303 	return base;
304 }
305 
306 /**
307  * ttm_ref_object_exists - Check whether a caller has a valid ref object
308  * (has opened) a base object.
309  *
310  * @tfile: Pointer to a struct ttm_object_file identifying the caller.
311  * @base: Pointer to a struct base object.
312  *
313  * Checks wether the caller identified by @tfile has put a valid USAGE
314  * reference object on the base object identified by @base.
315  */
ttm_ref_object_exists(struct ttm_object_file * tfile,struct ttm_base_object * base)316 bool ttm_ref_object_exists(struct ttm_object_file *tfile,
317 			   struct ttm_base_object *base)
318 {
319 	struct drm_open_hash *ht = &tfile->ref_hash[TTM_REF_USAGE];
320 	struct drm_hash_item *hash;
321 	struct ttm_ref_object *ref;
322 
323 	rcu_read_lock();
324 	if (unlikely(drm_ht_find_item_rcu(ht, base->handle, &hash) != 0))
325 		goto out_false;
326 
327 	/*
328 	 * Verify that the ref object is really pointing to our base object.
329 	 * Our base object could actually be dead, and the ref object pointing
330 	 * to another base object with the same handle.
331 	 */
332 	ref = drm_hash_entry(hash, struct ttm_ref_object, hash);
333 	if (unlikely(base != ref->obj))
334 		goto out_false;
335 
336 	/*
337 	 * Verify that the ref->obj pointer was actually valid!
338 	 */
339 	rmb();
340 	if (unlikely(kref_read(&ref->kref) == 0))
341 		goto out_false;
342 
343 	rcu_read_unlock();
344 	return true;
345 
346  out_false:
347 	rcu_read_unlock();
348 	return false;
349 }
350 
ttm_ref_object_add(struct ttm_object_file * tfile,struct ttm_base_object * base,enum ttm_ref_type ref_type,bool * existed,bool require_existed)351 int ttm_ref_object_add(struct ttm_object_file *tfile,
352 		       struct ttm_base_object *base,
353 		       enum ttm_ref_type ref_type, bool *existed,
354 		       bool require_existed)
355 {
356 	struct drm_open_hash *ht = &tfile->ref_hash[ref_type];
357 	struct ttm_ref_object *ref;
358 	struct drm_hash_item *hash;
359 	struct ttm_mem_global *mem_glob = tfile->tdev->mem_glob;
360 	struct ttm_operation_ctx ctx = {
361 		.interruptible = false,
362 		.no_wait_gpu = false
363 	};
364 	int ret = -EINVAL;
365 
366 	if (base->tfile != tfile && !base->shareable)
367 		return -EPERM;
368 
369 	if (existed != NULL)
370 		*existed = true;
371 
372 	while (ret == -EINVAL) {
373 		rcu_read_lock();
374 		ret = drm_ht_find_item_rcu(ht, base->handle, &hash);
375 
376 		if (ret == 0) {
377 			ref = drm_hash_entry(hash, struct ttm_ref_object, hash);
378 			if (kref_get_unless_zero(&ref->kref)) {
379 				rcu_read_unlock();
380 				break;
381 			}
382 		}
383 
384 		rcu_read_unlock();
385 		if (require_existed)
386 			return -EPERM;
387 
388 		ret = ttm_mem_global_alloc(mem_glob, sizeof(*ref),
389 					   &ctx);
390 		if (unlikely(ret != 0))
391 			return ret;
392 		ref = kmalloc(sizeof(*ref), GFP_KERNEL);
393 		if (unlikely(ref == NULL)) {
394 			ttm_mem_global_free(mem_glob, sizeof(*ref));
395 			return -ENOMEM;
396 		}
397 
398 		ref->hash.key = base->handle;
399 		ref->obj = base;
400 		ref->tfile = tfile;
401 		ref->ref_type = ref_type;
402 		kref_init(&ref->kref);
403 
404 		spin_lock(&tfile->lock);
405 		ret = drm_ht_insert_item_rcu(ht, &ref->hash);
406 
407 		if (likely(ret == 0)) {
408 			list_add_tail(&ref->head, &tfile->ref_list);
409 			kref_get(&base->refcount);
410 			spin_unlock(&tfile->lock);
411 			if (existed != NULL)
412 				*existed = false;
413 			break;
414 		}
415 
416 		spin_unlock(&tfile->lock);
417 		BUG_ON(ret != -EINVAL);
418 
419 		ttm_mem_global_free(mem_glob, sizeof(*ref));
420 		kfree(ref);
421 	}
422 
423 	return ret;
424 }
425 
426 static void __releases(tfile->lock) __acquires(tfile->lock)
ttm_ref_object_release(struct kref * kref)427 ttm_ref_object_release(struct kref *kref)
428 {
429 	struct ttm_ref_object *ref =
430 	    container_of(kref, struct ttm_ref_object, kref);
431 	struct ttm_base_object *base = ref->obj;
432 	struct ttm_object_file *tfile = ref->tfile;
433 	struct drm_open_hash *ht;
434 	struct ttm_mem_global *mem_glob = tfile->tdev->mem_glob;
435 
436 	ht = &tfile->ref_hash[ref->ref_type];
437 	(void)drm_ht_remove_item_rcu(ht, &ref->hash);
438 	list_del(&ref->head);
439 	spin_unlock(&tfile->lock);
440 
441 	if (ref->ref_type != TTM_REF_USAGE && base->ref_obj_release)
442 		base->ref_obj_release(base, ref->ref_type);
443 
444 	ttm_base_object_unref(&ref->obj);
445 	ttm_mem_global_free(mem_glob, sizeof(*ref));
446 	kfree_rcu(ref, rcu_head);
447 	spin_lock(&tfile->lock);
448 }
449 
ttm_ref_object_base_unref(struct ttm_object_file * tfile,unsigned long key,enum ttm_ref_type ref_type)450 int ttm_ref_object_base_unref(struct ttm_object_file *tfile,
451 			      unsigned long key, enum ttm_ref_type ref_type)
452 {
453 	struct drm_open_hash *ht = &tfile->ref_hash[ref_type];
454 	struct ttm_ref_object *ref;
455 	struct drm_hash_item *hash;
456 	int ret;
457 
458 	spin_lock(&tfile->lock);
459 	ret = drm_ht_find_item(ht, key, &hash);
460 	if (unlikely(ret != 0)) {
461 		spin_unlock(&tfile->lock);
462 		return -EINVAL;
463 	}
464 	ref = drm_hash_entry(hash, struct ttm_ref_object, hash);
465 	kref_put(&ref->kref, ttm_ref_object_release);
466 	spin_unlock(&tfile->lock);
467 	return 0;
468 }
469 
ttm_object_file_release(struct ttm_object_file ** p_tfile)470 void ttm_object_file_release(struct ttm_object_file **p_tfile)
471 {
472 	struct ttm_ref_object *ref;
473 	struct list_head *list;
474 	unsigned int i;
475 	struct ttm_object_file *tfile = *p_tfile;
476 
477 	*p_tfile = NULL;
478 	spin_lock(&tfile->lock);
479 
480 	/*
481 	 * Since we release the lock within the loop, we have to
482 	 * restart it from the beginning each time.
483 	 */
484 
485 	while (!list_empty(&tfile->ref_list)) {
486 		list = tfile->ref_list.next;
487 		ref = list_entry(list, struct ttm_ref_object, head);
488 		ttm_ref_object_release(&ref->kref);
489 	}
490 
491 	spin_unlock(&tfile->lock);
492 	for (i = 0; i < TTM_REF_NUM; ++i)
493 		drm_ht_remove(&tfile->ref_hash[i]);
494 
495 	ttm_object_file_unref(&tfile);
496 }
497 
ttm_object_file_init(struct ttm_object_device * tdev,unsigned int hash_order)498 struct ttm_object_file *ttm_object_file_init(struct ttm_object_device *tdev,
499 					     unsigned int hash_order)
500 {
501 	struct ttm_object_file *tfile = kmalloc(sizeof(*tfile), GFP_KERNEL);
502 	unsigned int i;
503 	unsigned int j = 0;
504 	int ret;
505 
506 	if (unlikely(tfile == NULL))
507 		return NULL;
508 
509 	spin_lock_init(&tfile->lock);
510 	tfile->tdev = tdev;
511 	kref_init(&tfile->refcount);
512 	INIT_LIST_HEAD(&tfile->ref_list);
513 
514 	for (i = 0; i < TTM_REF_NUM; ++i) {
515 		ret = drm_ht_create(&tfile->ref_hash[i], hash_order);
516 		if (ret) {
517 			j = i;
518 			goto out_err;
519 		}
520 	}
521 
522 	return tfile;
523 out_err:
524 	for (i = 0; i < j; ++i)
525 		drm_ht_remove(&tfile->ref_hash[i]);
526 
527 	kfree(tfile);
528 
529 	return NULL;
530 }
531 
532 struct ttm_object_device *
ttm_object_device_init(struct ttm_mem_global * mem_glob,unsigned int hash_order,const struct dma_buf_ops * ops)533 ttm_object_device_init(struct ttm_mem_global *mem_glob,
534 		       unsigned int hash_order,
535 		       const struct dma_buf_ops *ops)
536 {
537 	struct ttm_object_device *tdev = kmalloc(sizeof(*tdev), GFP_KERNEL);
538 	int ret;
539 
540 	if (unlikely(tdev == NULL))
541 		return NULL;
542 
543 	tdev->mem_glob = mem_glob;
544 	spin_lock_init(&tdev->object_lock);
545 	atomic_set(&tdev->object_count, 0);
546 	ret = drm_ht_create(&tdev->object_hash, hash_order);
547 	if (ret != 0)
548 		goto out_no_object_hash;
549 
550 	idr_init(&tdev->idr);
551 	tdev->ops = *ops;
552 	tdev->dmabuf_release = tdev->ops.release;
553 	tdev->ops.release = ttm_prime_dmabuf_release;
554 	tdev->dma_buf_size = ttm_round_pot(sizeof(struct dma_buf)) +
555 		ttm_round_pot(sizeof(struct file));
556 	return tdev;
557 
558 out_no_object_hash:
559 	kfree(tdev);
560 	return NULL;
561 }
562 
ttm_object_device_release(struct ttm_object_device ** p_tdev)563 void ttm_object_device_release(struct ttm_object_device **p_tdev)
564 {
565 	struct ttm_object_device *tdev = *p_tdev;
566 
567 	*p_tdev = NULL;
568 
569 	WARN_ON_ONCE(!idr_is_empty(&tdev->idr));
570 	idr_destroy(&tdev->idr);
571 	drm_ht_remove(&tdev->object_hash);
572 
573 	kfree(tdev);
574 }
575 
576 /**
577  * get_dma_buf_unless_doomed - get a dma_buf reference if possible.
578  *
579  * @dma_buf: Non-refcounted pointer to a struct dma-buf.
580  *
581  * Obtain a file reference from a lookup structure that doesn't refcount
582  * the file, but synchronizes with its release method to make sure it has
583  * not been freed yet. See for example kref_get_unless_zero documentation.
584  * Returns true if refcounting succeeds, false otherwise.
585  *
586  * Nobody really wants this as a public API yet, so let it mature here
587  * for some time...
588  */
get_dma_buf_unless_doomed(struct dma_buf * dmabuf)589 static bool __must_check get_dma_buf_unless_doomed(struct dma_buf *dmabuf)
590 {
591 #ifdef __NetBSD__
592 	/* XXX move this to linux_dma_buf.c */
593 	unsigned cnt;
594 
595 	do {
596 		cnt = atomic_load_relaxed(&dmabuf->db_refcnt);
597 		if (cnt == 0)
598 			return false;
599 	} while (atomic_cas_uint(&dmabuf->db_refcnt, cnt, cnt + 1) != cnt);
600 	return true;
601 #else
602 	return atomic_long_inc_not_zero(&dmabuf->file->f_count) != 0L;
603 #endif
604 }
605 
606 /**
607  * ttm_prime_refcount_release - refcount release method for a prime object.
608  *
609  * @p_base: Pointer to ttm_base_object pointer.
610  *
611  * This is a wrapper that calls the refcount_release founction of the
612  * underlying object. At the same time it cleans up the prime object.
613  * This function is called when all references to the base object we
614  * derive from are gone.
615  */
ttm_prime_refcount_release(struct ttm_base_object ** p_base)616 static void ttm_prime_refcount_release(struct ttm_base_object **p_base)
617 {
618 	struct ttm_base_object *base = *p_base;
619 	struct ttm_prime_object *prime;
620 
621 	*p_base = NULL;
622 	prime = container_of(base, struct ttm_prime_object, base);
623 	BUG_ON(prime->dma_buf != NULL);
624 	mutex_destroy(&prime->mutex);
625 	if (prime->refcount_release)
626 		prime->refcount_release(&base);
627 }
628 
629 /**
630  * ttm_prime_dmabuf_release - Release method for the dma-bufs we export
631  *
632  * @dma_buf:
633  *
634  * This function first calls the dma_buf release method the driver
635  * provides. Then it cleans up our dma_buf pointer used for lookup,
636  * and finally releases the reference the dma_buf has on our base
637  * object.
638  */
ttm_prime_dmabuf_release(struct dma_buf * dma_buf)639 static void ttm_prime_dmabuf_release(struct dma_buf *dma_buf)
640 {
641 	struct ttm_prime_object *prime =
642 		(struct ttm_prime_object *) dma_buf->priv;
643 	struct ttm_base_object *base = &prime->base;
644 	struct ttm_object_device *tdev = base->tfile->tdev;
645 
646 	if (tdev->dmabuf_release)
647 		tdev->dmabuf_release(dma_buf);
648 	mutex_lock(&prime->mutex);
649 	if (prime->dma_buf == dma_buf)
650 		prime->dma_buf = NULL;
651 	mutex_unlock(&prime->mutex);
652 	ttm_mem_global_free(tdev->mem_glob, tdev->dma_buf_size);
653 	ttm_base_object_unref(&base);
654 }
655 
656 /**
657  * ttm_prime_fd_to_handle - Get a base object handle from a prime fd
658  *
659  * @tfile: A struct ttm_object_file identifying the caller.
660  * @fd: The prime / dmabuf fd.
661  * @handle: The returned handle.
662  *
663  * This function returns a handle to an object that previously exported
664  * a dma-buf. Note that we don't handle imports yet, because we simply
665  * have no consumers of that implementation.
666  */
ttm_prime_fd_to_handle(struct ttm_object_file * tfile,int fd,u32 * handle)667 int ttm_prime_fd_to_handle(struct ttm_object_file *tfile,
668 			   int fd, u32 *handle)
669 {
670 	struct ttm_object_device *tdev = tfile->tdev;
671 	struct dma_buf *dma_buf;
672 	struct ttm_prime_object *prime;
673 	struct ttm_base_object *base;
674 	int ret;
675 
676 	dma_buf = dma_buf_get(fd);
677 	if (IS_ERR(dma_buf))
678 		return PTR_ERR(dma_buf);
679 
680 	if (dma_buf->ops != &tdev->ops)
681 		return -ENOSYS;
682 
683 	prime = (struct ttm_prime_object *) dma_buf->priv;
684 	base = &prime->base;
685 	*handle = base->handle;
686 	ret = ttm_ref_object_add(tfile, base, TTM_REF_USAGE, NULL, false);
687 
688 	dma_buf_put(dma_buf);
689 
690 	return ret;
691 }
692 
693 /**
694  * ttm_prime_handle_to_fd - Return a dma_buf fd from a ttm prime object
695  *
696  * @tfile: Struct ttm_object_file identifying the caller.
697  * @handle: Handle to the object we're exporting from.
698  * @flags: flags for dma-buf creation. We just pass them on.
699  * @prime_fd: The returned file descriptor.
700  *
701  */
ttm_prime_handle_to_fd(struct ttm_object_file * tfile,uint32_t handle,uint32_t flags,int * prime_fd)702 int ttm_prime_handle_to_fd(struct ttm_object_file *tfile,
703 			   uint32_t handle, uint32_t flags,
704 			   int *prime_fd)
705 {
706 	struct ttm_object_device *tdev = tfile->tdev;
707 	struct ttm_base_object *base;
708 	struct dma_buf *dma_buf;
709 	struct ttm_prime_object *prime;
710 	int ret;
711 
712 	base = ttm_base_object_lookup(tfile, handle);
713 	if (unlikely(base == NULL ||
714 		     base->object_type != ttm_prime_type)) {
715 		ret = -ENOENT;
716 		goto out_unref;
717 	}
718 
719 	prime = container_of(base, struct ttm_prime_object, base);
720 	if (unlikely(!base->shareable)) {
721 		ret = -EPERM;
722 		goto out_unref;
723 	}
724 
725 	ret = mutex_lock_interruptible(&prime->mutex);
726 	if (unlikely(ret != 0)) {
727 		ret = -ERESTARTSYS;
728 		goto out_unref;
729 	}
730 
731 	dma_buf = prime->dma_buf;
732 	if (!dma_buf || !get_dma_buf_unless_doomed(dma_buf)) {
733 		DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
734 		struct ttm_operation_ctx ctx = {
735 			.interruptible = true,
736 			.no_wait_gpu = false
737 		};
738 		exp_info.ops = &tdev->ops;
739 		exp_info.size = prime->size;
740 		exp_info.flags = flags;
741 		exp_info.priv = prime;
742 
743 		/*
744 		 * Need to create a new dma_buf, with memory accounting.
745 		 */
746 		ret = ttm_mem_global_alloc(tdev->mem_glob, tdev->dma_buf_size,
747 					   &ctx);
748 		if (unlikely(ret != 0)) {
749 			mutex_unlock(&prime->mutex);
750 			goto out_unref;
751 		}
752 
753 		dma_buf = dma_buf_export(&exp_info);
754 		if (IS_ERR(dma_buf)) {
755 			ret = PTR_ERR(dma_buf);
756 			ttm_mem_global_free(tdev->mem_glob,
757 					    tdev->dma_buf_size);
758 			mutex_unlock(&prime->mutex);
759 			goto out_unref;
760 		}
761 
762 		/*
763 		 * dma_buf has taken the base object reference
764 		 */
765 		base = NULL;
766 		prime->dma_buf = dma_buf;
767 	}
768 	mutex_unlock(&prime->mutex);
769 
770 	ret = dma_buf_fd(dma_buf, flags);
771 	if (ret >= 0) {
772 		*prime_fd = ret;
773 		ret = 0;
774 	} else
775 		dma_buf_put(dma_buf);
776 
777 out_unref:
778 	if (base)
779 		ttm_base_object_unref(&base);
780 	return ret;
781 }
782 
783 /**
784  * ttm_prime_object_init - Initialize a ttm_prime_object
785  *
786  * @tfile: struct ttm_object_file identifying the caller
787  * @size: The size of the dma_bufs we export.
788  * @prime: The object to be initialized.
789  * @shareable: See ttm_base_object_init
790  * @type: See ttm_base_object_init
791  * @refcount_release: See ttm_base_object_init
792  * @ref_obj_release: See ttm_base_object_init
793  *
794  * Initializes an object which is compatible with the drm_prime model
795  * for data sharing between processes and devices.
796  */
ttm_prime_object_init(struct ttm_object_file * tfile,size_t size,struct ttm_prime_object * prime,bool shareable,enum ttm_object_type type,void (* refcount_release)(struct ttm_base_object **),void (* ref_obj_release)(struct ttm_base_object *,enum ttm_ref_type ref_type))797 int ttm_prime_object_init(struct ttm_object_file *tfile, size_t size,
798 			  struct ttm_prime_object *prime, bool shareable,
799 			  enum ttm_object_type type,
800 			  void (*refcount_release) (struct ttm_base_object **),
801 			  void (*ref_obj_release) (struct ttm_base_object *,
802 						   enum ttm_ref_type ref_type))
803 {
804 	mutex_init(&prime->mutex);
805 	prime->size = PAGE_ALIGN(size);
806 	prime->real_type = type;
807 	prime->dma_buf = NULL;
808 	prime->refcount_release = refcount_release;
809 	return ttm_base_object_init(tfile, &prime->base, shareable,
810 				    ttm_prime_type,
811 				    ttm_prime_refcount_release,
812 				    ref_obj_release);
813 }
814