Rev 4569 | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 4569 | Rev 6296 | ||
---|---|---|---|
Line 56... | Line 56... | ||
56 | * for fast lookup of ref objects given a base object. |
56 | * for fast lookup of ref objects given a base object. |
57 | */ |
57 | */ |
Line 58... | Line 58... | ||
58 | 58 | ||
Line 59... | Line -... | ||
59 | #define pr_fmt(fmt) "[TTM] " fmt |
- | |
60 | - | ||
61 | #include |
59 | #define pr_fmt(fmt) "[TTM] " fmt |
62 | 60 | ||
63 | #include |
61 | #include |
64 | #include |
62 | #include |
65 | #include |
63 | #include |
66 | #include |
64 | #include |
67 | #include |
65 | #include |
68 | #include |
- | |
69 | //#include |
- | |
70 | - | ||
71 | static inline int __must_check kref_get_unless_zero(struct kref *kref) |
- | |
72 | { |
- | |
73 | return atomic_add_unless(&kref->refcount, 1, 0); |
- | |
74 | } |
- | |
75 | - | ||
Line 76... | Line 66... | ||
76 | #define pr_err(fmt, ...) \ |
66 | #include |
77 | printk(KERN_ERR pr_fmt(fmt), ##__VA_ARGS__) |
67 | #include |
78 | 68 | ||
79 | struct ttm_object_file { |
69 | struct ttm_object_file { |
Line 99... | Line 89... | ||
99 | struct ttm_object_device { |
89 | struct ttm_object_device { |
100 | spinlock_t object_lock; |
90 | spinlock_t object_lock; |
101 | struct drm_open_hash object_hash; |
91 | struct drm_open_hash object_hash; |
102 | atomic_t object_count; |
92 | atomic_t object_count; |
103 | 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; |
|
104 | }; |
97 | }; |
Line 105... | Line 98... | ||
105 | 98 | ||
106 | /** |
99 | /** |
107 | * struct ttm_ref_object |
100 | * struct ttm_ref_object |
Line 123... | Line 116... | ||
123 | * multiple ref objects if a ttm_object_file references the same base |
116 | * multiple ref objects if a ttm_object_file references the same base |
124 | * object more than once. |
117 | * object more than once. |
125 | */ |
118 | */ |
Line 126... | Line 119... | ||
126 | 119 | ||
- | 120 | struct ttm_ref_object { |
|
127 | struct ttm_ref_object { |
121 | struct rcu_head rcu_head; |
128 | struct drm_hash_item hash; |
122 | struct drm_hash_item hash; |
129 | struct list_head head; |
123 | struct list_head head; |
130 | struct kref kref; |
124 | struct kref kref; |
131 | enum ttm_ref_type ref_type; |
125 | enum ttm_ref_type ref_type; |
Line 238... | Line 232... | ||
238 | struct ttm_base_object *base = NULL; |
232 | struct ttm_base_object *base = NULL; |
239 | struct drm_hash_item *hash; |
233 | struct drm_hash_item *hash; |
240 | struct drm_open_hash *ht = &tfile->ref_hash[TTM_REF_USAGE]; |
234 | struct drm_open_hash *ht = &tfile->ref_hash[TTM_REF_USAGE]; |
241 | int ret; |
235 | int ret; |
Line 242... | Line 236... | ||
242 | 236 | ||
243 | // rcu_read_lock(); |
237 | rcu_read_lock(); |
Line 244... | Line 238... | ||
244 | ret = drm_ht_find_item_rcu(ht, key, &hash); |
238 | ret = drm_ht_find_item_rcu(ht, key, &hash); |
245 | 239 | ||
246 | if (likely(ret == 0)) { |
240 | if (likely(ret == 0)) { |
247 | base = drm_hash_entry(hash, struct ttm_ref_object, hash)->obj; |
241 | base = drm_hash_entry(hash, struct ttm_ref_object, hash)->obj; |
248 | if (!kref_get_unless_zero(&base->refcount)) |
242 | if (!kref_get_unless_zero(&base->refcount)) |
249 | base = NULL; |
243 | base = NULL; |
Line 250... | Line 244... | ||
250 | } |
244 | } |
251 | // rcu_read_unlock(); |
245 | rcu_read_unlock(); |
252 | 246 | ||
Line 260... | Line 254... | ||
260 | struct ttm_base_object *base = NULL; |
254 | struct ttm_base_object *base = NULL; |
261 | struct drm_hash_item *hash; |
255 | struct drm_hash_item *hash; |
262 | struct drm_open_hash *ht = &tdev->object_hash; |
256 | struct drm_open_hash *ht = &tdev->object_hash; |
263 | int ret; |
257 | int ret; |
Line -... | Line 258... | ||
- | 258 | ||
264 | 259 | rcu_read_lock(); |
|
Line 265... | Line 260... | ||
265 | ret = drm_ht_find_item_rcu(ht, key, &hash); |
260 | ret = drm_ht_find_item_rcu(ht, key, &hash); |
266 | 261 | ||
267 | if (likely(ret == 0)) { |
262 | if (likely(ret == 0)) { |
268 | base = drm_hash_entry(hash, struct ttm_base_object, hash); |
263 | base = drm_hash_entry(hash, struct ttm_base_object, hash); |
269 | if (!kref_get_unless_zero(&base->refcount)) |
264 | if (!kref_get_unless_zero(&base->refcount)) |
- | 265 | base = NULL; |
|
Line 270... | Line 266... | ||
270 | base = NULL; |
266 | } |
271 | } |
267 | rcu_read_unlock(); |
272 | 268 | ||
Line 286... | Line 282... | ||
286 | 282 | ||
287 | if (existed != NULL) |
283 | if (existed != NULL) |
Line 288... | Line 284... | ||
288 | *existed = true; |
284 | *existed = true; |
- | 285 | ||
289 | 286 | while (ret == -EINVAL) { |
|
Line 290... | Line 287... | ||
290 | while (ret == -EINVAL) { |
287 | rcu_read_lock(); |
291 | ret = drm_ht_find_item_rcu(ht, base->hash.key, &hash); |
288 | ret = drm_ht_find_item_rcu(ht, base->hash.key, &hash); |
292 | 289 | ||
- | 290 | if (ret == 0) { |
|
293 | if (ret == 0) { |
291 | ref = drm_hash_entry(hash, struct ttm_ref_object, hash); |
294 | ref = drm_hash_entry(hash, struct ttm_ref_object, hash); |
292 | if (kref_get_unless_zero(&ref->kref)) { |
295 | if (!kref_get_unless_zero(&ref->kref)) { |
293 | rcu_read_unlock(); |
Line -... | Line 294... | ||
- | 294 | break; |
|
296 | break; |
295 | } |
297 | } |
296 | } |
298 | } |
297 | |
299 | 298 | rcu_read_unlock(); |
|
300 | ret = ttm_mem_global_alloc(mem_glob, sizeof(*ref), |
299 | ret = ttm_mem_global_alloc(mem_glob, sizeof(*ref), |
Line 353... | Line 352... | ||
353 | if (ref->ref_type != TTM_REF_USAGE && base->ref_obj_release) |
352 | if (ref->ref_type != TTM_REF_USAGE && base->ref_obj_release) |
354 | base->ref_obj_release(base, ref->ref_type); |
353 | base->ref_obj_release(base, ref->ref_type); |
Line 355... | Line 354... | ||
355 | 354 | ||
356 | ttm_base_object_unref(&ref->obj); |
355 | ttm_base_object_unref(&ref->obj); |
357 | ttm_mem_global_free(mem_glob, sizeof(*ref)); |
356 | ttm_mem_global_free(mem_glob, sizeof(*ref)); |
358 | kfree(ref); |
357 | kfree_rcu(ref, rcu_head); |
359 | spin_lock(&tfile->lock); |
358 | spin_lock(&tfile->lock); |
Line 360... | Line 359... | ||
360 | } |
359 | } |
361 | 360 | ||
Line 460... | Line 459... | ||
460 | atomic_set(&tdev->object_count, 0); |
459 | atomic_set(&tdev->object_count, 0); |
461 | ret = drm_ht_create(&tdev->object_hash, hash_order); |
460 | ret = drm_ht_create(&tdev->object_hash, hash_order); |
462 | if (ret != 0) |
461 | if (ret != 0) |
463 | goto out_no_object_hash; |
462 | goto out_no_object_hash; |
Line 464... | Line 463... | ||
464 | 463 | ||
465 | // tdev->ops = *ops; |
464 | tdev->ops = *ops; |
466 | // tdev->dmabuf_release = tdev->ops.release; |
465 | tdev->dmabuf_release = tdev->ops.release; |
467 | // tdev->ops.release = ttm_prime_dmabuf_release; |
466 | tdev->ops.release = ttm_prime_dmabuf_release; |
468 | // tdev->dma_buf_size = ttm_round_pot(sizeof(struct dma_buf)) + |
467 | tdev->dma_buf_size = ttm_round_pot(sizeof(struct dma_buf)) + |
469 | // ttm_round_pot(sizeof(struct file)); |
468 | ttm_round_pot(sizeof(struct file)); |
Line 470... | Line 469... | ||
470 | return tdev; |
469 | return tdev; |
471 | 470 | ||
472 | out_no_object_hash: |
471 | out_no_object_hash: |
Line 486... | Line 485... | ||
486 | spin_unlock(&tdev->object_lock); |
485 | spin_unlock(&tdev->object_lock); |
Line 487... | Line 486... | ||
487 | 486 | ||
488 | kfree(tdev); |
487 | kfree(tdev); |
489 | } |
488 | } |
- | 489 | EXPORT_SYMBOL(ttm_object_device_release); |
|
- | 490 | ||
- | 491 | /** |
|
- | 492 | * get_dma_buf_unless_doomed - get a dma_buf reference if possible. |
|
- | 493 | * |
|
- | 494 | * @dma_buf: Non-refcounted pointer to a struct dma-buf. |
|
- | 495 | * |
|
- | 496 | * Obtain a file reference from a lookup structure that doesn't refcount |
|
- | 497 | * the file, but synchronizes with its release method to make sure it has |
|
- | 498 | * not been freed yet. See for example kref_get_unless_zero documentation. |
|
- | 499 | * Returns true if refcounting succeeds, false otherwise. |
|
- | 500 | * |
|
- | 501 | * Nobody really wants this as a public API yet, so let it mature here |
|
- | 502 | * for some time... |
|
- | 503 | */ |
|
- | 504 | static bool __must_check get_dma_buf_unless_doomed(struct dma_buf *dmabuf) |
|
- | 505 | { |
|
- | 506 | return atomic_long_inc_not_zero(&dmabuf->file->f_count) != 0L; |
|
- | 507 | } |
|
- | 508 | ||
- | 509 | /** |
|
- | 510 | * ttm_prime_refcount_release - refcount release method for a prime object. |
|
- | 511 | * |
|
- | 512 | * @p_base: Pointer to ttm_base_object pointer. |
|
- | 513 | * |
|
- | 514 | * This is a wrapper that calls the refcount_release founction of the |
|
- | 515 | * underlying object. At the same time it cleans up the prime object. |
|
- | 516 | * This function is called when all references to the base object we |
|
- | 517 | * derive from are gone. |
|
- | 518 | */ |
|
- | 519 | static void ttm_prime_refcount_release(struct ttm_base_object **p_base) |
|
- | 520 | { |
|
- | 521 | struct ttm_base_object *base = *p_base; |
|
- | 522 | struct ttm_prime_object *prime; |
|
- | 523 | ||
- | 524 | *p_base = NULL; |
|
- | 525 | prime = container_of(base, struct ttm_prime_object, base); |
|
- | 526 | BUG_ON(prime->dma_buf != NULL); |
|
- | 527 | mutex_destroy(&prime->mutex); |
|
- | 528 | if (prime->refcount_release) |
|
- | 529 | prime->refcount_release(&base); |
|
- | 530 | } |
|
- | 531 | ||
- | 532 | /** |
|
- | 533 | * ttm_prime_dmabuf_release - Release method for the dma-bufs we export |
|
- | 534 | * |
|
- | 535 | * @dma_buf: |
|
- | 536 | * |
|
- | 537 | * This function first calls the dma_buf release method the driver |
|
- | 538 | * provides. Then it cleans up our dma_buf pointer used for lookup, |
|
- | 539 | * and finally releases the reference the dma_buf has on our base |
|
- | 540 | * object. |
|
- | 541 | */ |
|
- | 542 | static void ttm_prime_dmabuf_release(struct dma_buf *dma_buf) |
|
- | 543 | { |
|
- | 544 | struct ttm_prime_object *prime = |
|
- | 545 | (struct ttm_prime_object *) dma_buf->priv; |
|
- | 546 | struct ttm_base_object *base = &prime->base; |
|
- | 547 | struct ttm_object_device *tdev = base->tfile->tdev; |
|
- | 548 | ||
- | 549 | if (tdev->dmabuf_release) |
|
- | 550 | tdev->dmabuf_release(dma_buf); |
|
- | 551 | mutex_lock(&prime->mutex); |
|
- | 552 | if (prime->dma_buf == dma_buf) |
|
- | 553 | prime->dma_buf = NULL; |
|
- | 554 | mutex_unlock(&prime->mutex); |
|
- | 555 | ttm_mem_global_free(tdev->mem_glob, tdev->dma_buf_size); |
|
- | 556 | ttm_base_object_unref(&base); |
|
- | 557 | } |
|
- | 558 | ||
- | 559 | /** |
|
- | 560 | * ttm_prime_fd_to_handle - Get a base object handle from a prime fd |
|
- | 561 | * |
|
- | 562 | * @tfile: A struct ttm_object_file identifying the caller. |
|
- | 563 | * @fd: The prime / dmabuf fd. |
|
- | 564 | * @handle: The returned handle. |
|
- | 565 | * |
|
- | 566 | * This function returns a handle to an object that previously exported |
|
- | 567 | * a dma-buf. Note that we don't handle imports yet, because we simply |
|
- | 568 | * have no consumers of that implementation. |
|
- | 569 | */ |
|
- | 570 | int ttm_prime_fd_to_handle(struct ttm_object_file *tfile, |
|
- | 571 | int fd, u32 *handle) |
|
- | 572 | { |
|
- | 573 | struct ttm_object_device *tdev = tfile->tdev; |
|
- | 574 | struct dma_buf *dma_buf; |
|
- | 575 | struct ttm_prime_object *prime; |
|
- | 576 | struct ttm_base_object *base; |
|
- | 577 | int ret; |
|
- | 578 | ||
- | 579 | dma_buf = dma_buf_get(fd); |
|
- | 580 | if (IS_ERR(dma_buf)) |
|
- | 581 | return PTR_ERR(dma_buf); |
|
- | 582 | ||
- | 583 | if (dma_buf->ops != &tdev->ops) |
|
- | 584 | return -ENOSYS; |
|
- | 585 | ||
- | 586 | prime = (struct ttm_prime_object *) dma_buf->priv; |
|
- | 587 | base = &prime->base; |
|
- | 588 | *handle = base->hash.key; |
|
- | 589 | ret = ttm_ref_object_add(tfile, base, TTM_REF_USAGE, NULL); |
|
- | 590 | ||
- | 591 | dma_buf_put(dma_buf); |
|
- | 592 | ||
- | 593 | return ret; |
|
- | 594 | } |
|
- | 595 | EXPORT_SYMBOL_GPL(ttm_prime_fd_to_handle); |
|
- | 596 | ||
- | 597 | /** |
|
- | 598 | * ttm_prime_handle_to_fd - Return a dma_buf fd from a ttm prime object |
|
- | 599 | * |
|
- | 600 | * @tfile: Struct ttm_object_file identifying the caller. |
|
- | 601 | * @handle: Handle to the object we're exporting from. |
|
- | 602 | * @flags: flags for dma-buf creation. We just pass them on. |
|
- | 603 | * @prime_fd: The returned file descriptor. |
|
- | 604 | * |
|
- | 605 | */ |
|
- | 606 | int ttm_prime_handle_to_fd(struct ttm_object_file *tfile, |
|
- | 607 | uint32_t handle, uint32_t flags, |
|
- | 608 | int *prime_fd) |
|
- | 609 | { |
|
- | 610 | struct ttm_object_device *tdev = tfile->tdev; |
|
- | 611 | struct ttm_base_object *base; |
|
- | 612 | struct dma_buf *dma_buf; |
|
- | 613 | struct ttm_prime_object *prime; |
|
- | 614 | int ret; |
|
- | 615 | ||
- | 616 | base = ttm_base_object_lookup(tfile, handle); |
|
- | 617 | if (unlikely(base == NULL || |
|
- | 618 | base->object_type != ttm_prime_type)) { |
|
- | 619 | ret = -ENOENT; |
|
- | 620 | goto out_unref; |
|
- | 621 | } |
|
- | 622 | ||
- | 623 | prime = container_of(base, struct ttm_prime_object, base); |
|
- | 624 | if (unlikely(!base->shareable)) { |
|
- | 625 | ret = -EPERM; |
|
- | 626 | goto out_unref; |
|
- | 627 | } |
|
- | 628 | ||
- | 629 | ret = mutex_lock_interruptible(&prime->mutex); |
|
- | 630 | if (unlikely(ret != 0)) { |
|
- | 631 | ret = -ERESTARTSYS; |
|
- | 632 | goto out_unref; |
|
- | 633 | } |
|
- | 634 | ||
- | 635 | dma_buf = prime->dma_buf; |
|
- | 636 | if (!dma_buf || !get_dma_buf_unless_doomed(dma_buf)) { |
|
- | 637 | DEFINE_DMA_BUF_EXPORT_INFO(exp_info); |
|
- | 638 | ||
- | 639 | exp_info.ops = &tdev->ops; |
|
- | 640 | exp_info.size = prime->size; |
|
- | 641 | exp_info.flags = flags; |
|
- | 642 | exp_info.priv = prime; |
|
- | 643 | ||
- | 644 | /* |
|
- | 645 | * Need to create a new dma_buf, with memory accounting. |
|
- | 646 | */ |
|
- | 647 | ret = ttm_mem_global_alloc(tdev->mem_glob, tdev->dma_buf_size, |
|
- | 648 | false, true); |
|
- | 649 | if (unlikely(ret != 0)) { |
|
- | 650 | mutex_unlock(&prime->mutex); |
|
- | 651 | goto out_unref; |
|
- | 652 | } |
|
- | 653 | ||
- | 654 | dma_buf = dma_buf_export(&exp_info); |
|
- | 655 | if (IS_ERR(dma_buf)) { |
|
- | 656 | ret = PTR_ERR(dma_buf); |
|
- | 657 | ttm_mem_global_free(tdev->mem_glob, |
|
- | 658 | tdev->dma_buf_size); |
|
- | 659 | mutex_unlock(&prime->mutex); |
|
- | 660 | goto out_unref; |
|
- | 661 | } |
|
- | 662 | ||
- | 663 | /* |
|
- | 664 | * dma_buf has taken the base object reference |
|
- | 665 | */ |
|
- | 666 | base = NULL; |
|
- | 667 | prime->dma_buf = dma_buf; |
|
- | 668 | } |
|
- | 669 | mutex_unlock(&prime->mutex); |
|
- | 670 | ||
- | 671 | ret = dma_buf_fd(dma_buf, flags); |
|
- | 672 | if (ret >= 0) { |
|
- | 673 | *prime_fd = ret; |
|
- | 674 | ret = 0; |
|
- | 675 | } else |
|
- | 676 | dma_buf_put(dma_buf); |
|
- | 677 | ||
- | 678 | out_unref: |
|
- | 679 | if (base) |
|
- | 680 | ttm_base_object_unref(&base); |
|
- | 681 | return ret; |
|
- | 682 | } |
|
- | 683 | EXPORT_SYMBOL_GPL(ttm_prime_handle_to_fd); |
|
- | 684 | ||
- | 685 | /** |
|
- | 686 | * ttm_prime_object_init - Initialize a ttm_prime_object |
|
- | 687 | * |
|
- | 688 | * @tfile: struct ttm_object_file identifying the caller |
|
- | 689 | * @size: The size of the dma_bufs we export. |
|
- | 690 | * @prime: The object to be initialized. |
|
- | 691 | * @shareable: See ttm_base_object_init |
|
- | 692 | * @type: See ttm_base_object_init |
|
- | 693 | * @refcount_release: See ttm_base_object_init |
|
- | 694 | * @ref_obj_release: See ttm_base_object_init |
|
- | 695 | * |
|
- | 696 | * Initializes an object which is compatible with the drm_prime model |
|
- | 697 | * for data sharing between processes and devices. |
|
- | 698 | */ |
|
- | 699 | int ttm_prime_object_init(struct ttm_object_file *tfile, size_t size, |
|
- | 700 | struct ttm_prime_object *prime, bool shareable, |
|
- | 701 | enum ttm_object_type type, |
|
- | 702 | void (*refcount_release) (struct ttm_base_object **), |
|
- | 703 | void (*ref_obj_release) (struct ttm_base_object *, |
|
- | 704 | enum ttm_ref_type ref_type)) |
|
- | 705 | { |
|
- | 706 | mutex_init(&prime->mutex); |
|
- | 707 | prime->size = PAGE_ALIGN(size); |
|
- | 708 | prime->real_type = type; |
|
- | 709 | prime->dma_buf = NULL; |
|
- | 710 | prime->refcount_release = refcount_release; |
|
- | 711 | return ttm_base_object_init(tfile, &prime->base, shareable, |
|
- | 712 | ttm_prime_type, |
|
- | 713 | ttm_prime_refcount_release, |
|
- | 714 | ref_obj_release); |
|
- | 715 | } |