diff options
author | Thomas Hellstrom <thellstrom@vmware.com> | 2013-11-13 04:48:31 -0500 |
---|---|---|
committer | Thomas Hellstrom <thellstrom@vmware.com> | 2013-11-18 03:46:41 -0500 |
commit | 65981f7681abdf92b25942222b629b9c512d0705 (patch) | |
tree | a9f90e3de5ccca2d7469e295c1b210935743bf62 | |
parent | ac49251b6bf428b8f4fb1ed8859219f0a72b5db4 (diff) |
drm/ttm: Add a minimal prime implementation for ttm base objects
Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com>
Reviewed-by: Jakob Bornecrantz <jakob@vmware.com>
-rw-r--r-- | drivers/gpu/drm/ttm/ttm_object.c | 254 | ||||
-rw-r--r-- | include/drm/ttm/ttm_object.h | 61 |
2 files changed, 307 insertions, 8 deletions
diff --git a/drivers/gpu/drm/ttm/ttm_object.c b/drivers/gpu/drm/ttm/ttm_object.c index a868176c258a..6fe7b92a82d1 100644 --- a/drivers/gpu/drm/ttm/ttm_object.c +++ b/drivers/gpu/drm/ttm/ttm_object.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /************************************************************************** | 1 | /************************************************************************** |
2 | * | 2 | * |
3 | * Copyright (c) 2009 VMware, Inc., Palo Alto, CA., USA | 3 | * Copyright (c) 2009-2013 VMware, Inc., Palo Alto, CA., USA |
4 | * All Rights Reserved. | 4 | * All Rights Reserved. |
5 | * | 5 | * |
6 | * Permission is hereby granted, free of charge, to any person obtaining a | 6 | * Permission is hereby granted, free of charge, to any person obtaining a |
@@ -26,6 +26,12 @@ | |||
26 | **************************************************************************/ | 26 | **************************************************************************/ |
27 | /* | 27 | /* |
28 | * Authors: Thomas Hellstrom <thellstrom-at-vmware-dot-com> | 28 | * Authors: Thomas Hellstrom <thellstrom-at-vmware-dot-com> |
29 | * | ||
30 | * While no substantial code is shared, the prime code is inspired by | ||
31 | * drm_prime.c, with | ||
32 | * Authors: | ||
33 | * Dave Airlie <airlied@redhat.com> | ||
34 | * Rob Clark <rob.clark@linaro.org> | ||
29 | */ | 35 | */ |
30 | /** @file ttm_ref_object.c | 36 | /** @file ttm_ref_object.c |
31 | * | 37 | * |
@@ -34,6 +40,7 @@ | |||
34 | * and release on file close. | 40 | * and release on file close. |
35 | */ | 41 | */ |
36 | 42 | ||
43 | |||
37 | /** | 44 | /** |
38 | * struct ttm_object_file | 45 | * struct ttm_object_file |
39 | * | 46 | * |
@@ -84,6 +91,9 @@ struct ttm_object_device { | |||
84 | struct drm_open_hash object_hash; | 91 | struct drm_open_hash object_hash; |
85 | atomic_t object_count; | 92 | atomic_t object_count; |
86 | struct ttm_mem_global *mem_glob; | 93 | struct ttm_mem_global *mem_glob; |
94 | struct dma_buf_ops ops; | ||
95 | void (*dmabuf_release)(struct dma_buf *dma_buf); | ||
96 | size_t dma_buf_size; | ||
87 | }; | 97 | }; |
88 | 98 | ||
89 | /** | 99 | /** |
@@ -116,6 +126,8 @@ struct ttm_ref_object { | |||
116 | struct ttm_object_file *tfile; | 126 | struct ttm_object_file *tfile; |
117 | }; | 127 | }; |
118 | 128 | ||
129 | static void ttm_prime_dmabuf_release(struct dma_buf *dma_buf); | ||
130 | |||
119 | static inline struct ttm_object_file * | 131 | static inline struct ttm_object_file * |
120 | ttm_object_file_ref(struct ttm_object_file *tfile) | 132 | ttm_object_file_ref(struct ttm_object_file *tfile) |
121 | { | 133 | { |
@@ -416,9 +428,10 @@ out_err: | |||
416 | } | 428 | } |
417 | EXPORT_SYMBOL(ttm_object_file_init); | 429 | EXPORT_SYMBOL(ttm_object_file_init); |
418 | 430 | ||
419 | struct ttm_object_device *ttm_object_device_init(struct ttm_mem_global | 431 | struct ttm_object_device * |
420 | *mem_glob, | 432 | ttm_object_device_init(struct ttm_mem_global *mem_glob, |
421 | unsigned int hash_order) | 433 | unsigned int hash_order, |
434 | const struct dma_buf_ops *ops) | ||
422 | { | 435 | { |
423 | struct ttm_object_device *tdev = kmalloc(sizeof(*tdev), GFP_KERNEL); | 436 | struct ttm_object_device *tdev = kmalloc(sizeof(*tdev), GFP_KERNEL); |
424 | int ret; | 437 | int ret; |
@@ -430,10 +443,17 @@ struct ttm_object_device *ttm_object_device_init(struct ttm_mem_global | |||
430 | spin_lock_init(&tdev->object_lock); | 443 | spin_lock_init(&tdev->object_lock); |
431 | atomic_set(&tdev->object_count, 0); | 444 | atomic_set(&tdev->object_count, 0); |
432 | ret = drm_ht_create(&tdev->object_hash, hash_order); | 445 | ret = drm_ht_create(&tdev->object_hash, hash_order); |
446 | if (ret != 0) | ||
447 | goto out_no_object_hash; | ||
433 | 448 | ||
434 | if (likely(ret == 0)) | 449 | tdev->ops = *ops; |
435 | return tdev; | 450 | tdev->dmabuf_release = tdev->ops.release; |
451 | tdev->ops.release = ttm_prime_dmabuf_release; | ||
452 | tdev->dma_buf_size = ttm_round_pot(sizeof(struct dma_buf)) + | ||
453 | ttm_round_pot(sizeof(struct file)); | ||
454 | return tdev; | ||
436 | 455 | ||
456 | out_no_object_hash: | ||
437 | kfree(tdev); | 457 | kfree(tdev); |
438 | return NULL; | 458 | return NULL; |
439 | } | 459 | } |
@@ -452,3 +472,225 @@ void ttm_object_device_release(struct ttm_object_device **p_tdev) | |||
452 | kfree(tdev); | 472 | kfree(tdev); |
453 | } | 473 | } |
454 | EXPORT_SYMBOL(ttm_object_device_release); | 474 | EXPORT_SYMBOL(ttm_object_device_release); |
475 | |||
476 | /** | ||
477 | * get_dma_buf_unless_doomed - get a dma_buf reference if possible. | ||
478 | * | ||
479 | * @dma_buf: Non-refcounted pointer to a struct dma-buf. | ||
480 | * | ||
481 | * Obtain a file reference from a lookup structure that doesn't refcount | ||
482 | * the file, but synchronizes with its release method to make sure it has | ||
483 | * not been freed yet. See for example kref_get_unless_zero documentation. | ||
484 | * Returns true if refcounting succeeds, false otherwise. | ||
485 | * | ||
486 | * Nobody really wants this as a public API yet, so let it mature here | ||
487 | * for some time... | ||
488 | */ | ||
489 | static bool __must_check get_dma_buf_unless_doomed(struct dma_buf *dmabuf) | ||
490 | { | ||
491 | return atomic_long_inc_not_zero(&dmabuf->file->f_count) != 0L; | ||
492 | } | ||
493 | |||
494 | /** | ||
495 | * ttm_prime_refcount_release - refcount release method for a prime object. | ||
496 | * | ||
497 | * @p_base: Pointer to ttm_base_object pointer. | ||
498 | * | ||
499 | * This is a wrapper that calls the refcount_release founction of the | ||
500 | * underlying object. At the same time it cleans up the prime object. | ||
501 | * This function is called when all references to the base object we | ||
502 | * derive from are gone. | ||
503 | */ | ||
504 | static void ttm_prime_refcount_release(struct ttm_base_object **p_base) | ||
505 | { | ||
506 | struct ttm_base_object *base = *p_base; | ||
507 | struct ttm_prime_object *prime; | ||
508 | |||
509 | *p_base = NULL; | ||
510 | prime = container_of(base, struct ttm_prime_object, base); | ||
511 | BUG_ON(prime->dma_buf != NULL); | ||
512 | mutex_destroy(&prime->mutex); | ||
513 | if (prime->refcount_release) | ||
514 | prime->refcount_release(&base); | ||
515 | } | ||
516 | |||
517 | /** | ||
518 | * ttm_prime_dmabuf_release - Release method for the dma-bufs we export | ||
519 | * | ||
520 | * @dma_buf: | ||
521 | * | ||
522 | * This function first calls the dma_buf release method the driver | ||
523 | * provides. Then it cleans up our dma_buf pointer used for lookup, | ||
524 | * and finally releases the reference the dma_buf has on our base | ||
525 | * object. | ||
526 | */ | ||
527 | static void ttm_prime_dmabuf_release(struct dma_buf *dma_buf) | ||
528 | { | ||
529 | struct ttm_prime_object *prime = | ||
530 | (struct ttm_prime_object *) dma_buf->priv; | ||
531 | struct ttm_base_object *base = &prime->base; | ||
532 | struct ttm_object_device *tdev = base->tfile->tdev; | ||
533 | |||
534 | if (tdev->dmabuf_release) | ||
535 | tdev->dmabuf_release(dma_buf); | ||
536 | mutex_lock(&prime->mutex); | ||
537 | if (prime->dma_buf == dma_buf) | ||
538 | prime->dma_buf = NULL; | ||
539 | mutex_unlock(&prime->mutex); | ||
540 | ttm_mem_global_free(tdev->mem_glob, tdev->dma_buf_size); | ||
541 | ttm_base_object_unref(&base); | ||
542 | } | ||
543 | |||
544 | /** | ||
545 | * ttm_prime_fd_to_handle - Get a base object handle from a prime fd | ||
546 | * | ||
547 | * @tfile: A struct ttm_object_file identifying the caller. | ||
548 | * @fd: The prime / dmabuf fd. | ||
549 | * @handle: The returned handle. | ||
550 | * | ||
551 | * This function returns a handle to an object that previously exported | ||
552 | * a dma-buf. Note that we don't handle imports yet, because we simply | ||
553 | * have no consumers of that implementation. | ||
554 | */ | ||
555 | int ttm_prime_fd_to_handle(struct ttm_object_file *tfile, | ||
556 | int fd, u32 *handle) | ||
557 | { | ||
558 | struct ttm_object_device *tdev = tfile->tdev; | ||
559 | struct dma_buf *dma_buf; | ||
560 | struct ttm_prime_object *prime; | ||
561 | struct ttm_base_object *base; | ||
562 | int ret; | ||
563 | |||
564 | dma_buf = dma_buf_get(fd); | ||
565 | if (IS_ERR(dma_buf)) | ||
566 | return PTR_ERR(dma_buf); | ||
567 | |||
568 | if (dma_buf->ops != &tdev->ops) | ||
569 | return -ENOSYS; | ||
570 | |||
571 | prime = (struct ttm_prime_object *) dma_buf->priv; | ||
572 | base = &prime->base; | ||
573 | *handle = base->hash.key; | ||
574 | ret = ttm_ref_object_add(tfile, base, TTM_REF_USAGE, NULL); | ||
575 | |||
576 | dma_buf_put(dma_buf); | ||
577 | |||
578 | return ret; | ||
579 | } | ||
580 | EXPORT_SYMBOL_GPL(ttm_prime_fd_to_handle); | ||
581 | |||
582 | /** | ||
583 | * ttm_prime_handle_to_fd - Return a dma_buf fd from a ttm prime object | ||
584 | * | ||
585 | * @tfile: Struct ttm_object_file identifying the caller. | ||
586 | * @handle: Handle to the object we're exporting from. | ||
587 | * @flags: flags for dma-buf creation. We just pass them on. | ||
588 | * @prime_fd: The returned file descriptor. | ||
589 | * | ||
590 | */ | ||
591 | int ttm_prime_handle_to_fd(struct ttm_object_file *tfile, | ||
592 | uint32_t handle, uint32_t flags, | ||
593 | int *prime_fd) | ||
594 | { | ||
595 | struct ttm_object_device *tdev = tfile->tdev; | ||
596 | struct ttm_base_object *base; | ||
597 | struct dma_buf *dma_buf; | ||
598 | struct ttm_prime_object *prime; | ||
599 | int ret; | ||
600 | |||
601 | base = ttm_base_object_lookup(tfile, handle); | ||
602 | if (unlikely(base == NULL || | ||
603 | base->object_type != ttm_prime_type)) { | ||
604 | ret = -ENOENT; | ||
605 | goto out_unref; | ||
606 | } | ||
607 | |||
608 | prime = container_of(base, struct ttm_prime_object, base); | ||
609 | if (unlikely(!base->shareable)) { | ||
610 | ret = -EPERM; | ||
611 | goto out_unref; | ||
612 | } | ||
613 | |||
614 | ret = mutex_lock_interruptible(&prime->mutex); | ||
615 | if (unlikely(ret != 0)) { | ||
616 | ret = -ERESTARTSYS; | ||
617 | goto out_unref; | ||
618 | } | ||
619 | |||
620 | dma_buf = prime->dma_buf; | ||
621 | if (!dma_buf || !get_dma_buf_unless_doomed(dma_buf)) { | ||
622 | |||
623 | /* | ||
624 | * Need to create a new dma_buf, with memory accounting. | ||
625 | */ | ||
626 | ret = ttm_mem_global_alloc(tdev->mem_glob, tdev->dma_buf_size, | ||
627 | false, true); | ||
628 | if (unlikely(ret != 0)) { | ||
629 | mutex_unlock(&prime->mutex); | ||
630 | goto out_unref; | ||
631 | } | ||
632 | |||
633 | dma_buf = dma_buf_export(prime, &tdev->ops, | ||
634 | prime->size, flags); | ||
635 | if (IS_ERR(dma_buf)) { | ||
636 | ret = PTR_ERR(dma_buf); | ||
637 | ttm_mem_global_free(tdev->mem_glob, | ||
638 | tdev->dma_buf_size); | ||
639 | mutex_unlock(&prime->mutex); | ||
640 | goto out_unref; | ||
641 | } | ||
642 | |||
643 | /* | ||
644 | * dma_buf has taken the base object reference | ||
645 | */ | ||
646 | base = NULL; | ||
647 | prime->dma_buf = dma_buf; | ||
648 | } | ||
649 | mutex_unlock(&prime->mutex); | ||
650 | |||
651 | ret = dma_buf_fd(dma_buf, flags); | ||
652 | if (ret >= 0) { | ||
653 | *prime_fd = ret; | ||
654 | ret = 0; | ||
655 | } else | ||
656 | dma_buf_put(dma_buf); | ||
657 | |||
658 | out_unref: | ||
659 | if (base) | ||
660 | ttm_base_object_unref(&base); | ||
661 | return ret; | ||
662 | } | ||
663 | EXPORT_SYMBOL_GPL(ttm_prime_handle_to_fd); | ||
664 | |||
665 | /** | ||
666 | * ttm_prime_object_init - Initialize a ttm_prime_object | ||
667 | * | ||
668 | * @tfile: struct ttm_object_file identifying the caller | ||
669 | * @size: The size of the dma_bufs we export. | ||
670 | * @prime: The object to be initialized. | ||
671 | * @shareable: See ttm_base_object_init | ||
672 | * @type: See ttm_base_object_init | ||
673 | * @refcount_release: See ttm_base_object_init | ||
674 | * @ref_obj_release: See ttm_base_object_init | ||
675 | * | ||
676 | * Initializes an object which is compatible with the drm_prime model | ||
677 | * for data sharing between processes and devices. | ||
678 | */ | ||
679 | int ttm_prime_object_init(struct ttm_object_file *tfile, size_t size, | ||
680 | struct ttm_prime_object *prime, bool shareable, | ||
681 | enum ttm_object_type type, | ||
682 | void (*refcount_release) (struct ttm_base_object **), | ||
683 | void (*ref_obj_release) (struct ttm_base_object *, | ||
684 | enum ttm_ref_type ref_type)) | ||
685 | { | ||
686 | mutex_init(&prime->mutex); | ||
687 | prime->size = PAGE_ALIGN(size); | ||
688 | prime->real_type = type; | ||
689 | prime->dma_buf = NULL; | ||
690 | prime->refcount_release = refcount_release; | ||
691 | return ttm_base_object_init(tfile, &prime->base, shareable, | ||
692 | ttm_prime_type, | ||
693 | ttm_prime_refcount_release, | ||
694 | ref_obj_release); | ||
695 | } | ||
696 | EXPORT_SYMBOL(ttm_prime_object_init); | ||
diff --git a/include/drm/ttm/ttm_object.h b/include/drm/ttm/ttm_object.h index fc0cf0649901..58b029894eb3 100644 --- a/include/drm/ttm/ttm_object.h +++ b/include/drm/ttm/ttm_object.h | |||
@@ -41,6 +41,7 @@ | |||
41 | #include <drm/drm_hashtab.h> | 41 | #include <drm/drm_hashtab.h> |
42 | #include <linux/kref.h> | 42 | #include <linux/kref.h> |
43 | #include <linux/rcupdate.h> | 43 | #include <linux/rcupdate.h> |
44 | #include <linux/dma-buf.h> | ||
44 | #include <ttm/ttm_memory.h> | 45 | #include <ttm/ttm_memory.h> |
45 | 46 | ||
46 | /** | 47 | /** |
@@ -77,6 +78,7 @@ enum ttm_object_type { | |||
77 | ttm_fence_type, | 78 | ttm_fence_type, |
78 | ttm_buffer_type, | 79 | ttm_buffer_type, |
79 | ttm_lock_type, | 80 | ttm_lock_type, |
81 | ttm_prime_type, | ||
80 | ttm_driver_type0 = 256, | 82 | ttm_driver_type0 = 256, |
81 | ttm_driver_type1, | 83 | ttm_driver_type1, |
82 | ttm_driver_type2, | 84 | ttm_driver_type2, |
@@ -132,6 +134,30 @@ struct ttm_base_object { | |||
132 | enum ttm_ref_type ref_type); | 134 | enum ttm_ref_type ref_type); |
133 | }; | 135 | }; |
134 | 136 | ||
137 | |||
138 | /** | ||
139 | * struct ttm_prime_object - Modified base object that is prime-aware | ||
140 | * | ||
141 | * @base: struct ttm_base_object that we derive from | ||
142 | * @mutex: Mutex protecting the @dma_buf member. | ||
143 | * @size: Size of the dma_buf associated with this object | ||
144 | * @real_type: Type of the underlying object. Needed since we're setting | ||
145 | * the value of @base::object_type to ttm_prime_type | ||
146 | * @dma_buf: Non ref-coutned pointer to a struct dma_buf created from this | ||
147 | * object. | ||
148 | * @refcount_release: The underlying object's release method. Needed since | ||
149 | * we set @base::refcount_release to our own release method. | ||
150 | */ | ||
151 | |||
152 | struct ttm_prime_object { | ||
153 | struct ttm_base_object base; | ||
154 | struct mutex mutex; | ||
155 | size_t size; | ||
156 | enum ttm_object_type real_type; | ||
157 | struct dma_buf *dma_buf; | ||
158 | void (*refcount_release) (struct ttm_base_object **); | ||
159 | }; | ||
160 | |||
135 | /** | 161 | /** |
136 | * ttm_base_object_init | 162 | * ttm_base_object_init |
137 | * | 163 | * |
@@ -248,14 +274,18 @@ extern void ttm_object_file_release(struct ttm_object_file **p_tfile); | |||
248 | /** | 274 | /** |
249 | * ttm_object device init - initialize a struct ttm_object_device | 275 | * ttm_object device init - initialize a struct ttm_object_device |
250 | * | 276 | * |
277 | * @mem_glob: struct ttm_mem_global for memory accounting. | ||
251 | * @hash_order: Order of hash table used to hash the base objects. | 278 | * @hash_order: Order of hash table used to hash the base objects. |
279 | * @ops: DMA buf ops for prime objects of this device. | ||
252 | * | 280 | * |
253 | * This function is typically called on device initialization to prepare | 281 | * This function is typically called on device initialization to prepare |
254 | * data structures needed for ttm base and ref objects. | 282 | * data structures needed for ttm base and ref objects. |
255 | */ | 283 | */ |
256 | 284 | ||
257 | extern struct ttm_object_device *ttm_object_device_init | 285 | extern struct ttm_object_device * |
258 | (struct ttm_mem_global *mem_glob, unsigned int hash_order); | 286 | ttm_object_device_init(struct ttm_mem_global *mem_glob, |
287 | unsigned int hash_order, | ||
288 | const struct dma_buf_ops *ops); | ||
259 | 289 | ||
260 | /** | 290 | /** |
261 | * ttm_object_device_release - release data held by a ttm_object_device | 291 | * ttm_object_device_release - release data held by a ttm_object_device |
@@ -272,4 +302,31 @@ extern void ttm_object_device_release(struct ttm_object_device **p_tdev); | |||
272 | 302 | ||
273 | #define ttm_base_object_kfree(__object, __base)\ | 303 | #define ttm_base_object_kfree(__object, __base)\ |
274 | kfree_rcu(__object, __base.rhead) | 304 | kfree_rcu(__object, __base.rhead) |
305 | |||
306 | extern int ttm_prime_object_init(struct ttm_object_file *tfile, | ||
307 | size_t size, | ||
308 | struct ttm_prime_object *prime, | ||
309 | bool shareable, | ||
310 | enum ttm_object_type type, | ||
311 | void (*refcount_release) | ||
312 | (struct ttm_base_object **), | ||
313 | void (*ref_obj_release) | ||
314 | (struct ttm_base_object *, | ||
315 | enum ttm_ref_type ref_type)); | ||
316 | |||
317 | static inline enum ttm_object_type | ||
318 | ttm_base_object_type(struct ttm_base_object *base) | ||
319 | { | ||
320 | return (base->object_type == ttm_prime_type) ? | ||
321 | container_of(base, struct ttm_prime_object, base)->real_type : | ||
322 | base->object_type; | ||
323 | } | ||
324 | extern int ttm_prime_fd_to_handle(struct ttm_object_file *tfile, | ||
325 | int fd, u32 *handle); | ||
326 | extern int ttm_prime_handle_to_fd(struct ttm_object_file *tfile, | ||
327 | uint32_t handle, uint32_t flags, | ||
328 | int *prime_fd); | ||
329 | |||
330 | #define ttm_prime_object_kfree(__obj, __prime) \ | ||
331 | kfree_rcu(__obj, __prime.base.rhead) | ||
275 | #endif | 332 | #endif |