aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Hellstrom <thellstrom@vmware.com>2010-10-19 03:01:01 -0400
committerDave Airlie <airlied@redhat.com>2010-10-20 21:53:28 -0400
commite1efc9b6ac22c605fd326b3f6af9b393325d43b4 (patch)
tree98960a29a6b4217b3ac219fd2be37e6b648e4589
parent40d857bba2915a4e8d82f44744a186bfdd1a46ea (diff)
drm/ttm: Optimize delayed buffer destruction
This commit replaces the ttm_bo_cleanup_ref function with two new functions. One for the case where the bo is not yet on the delayed destroy list, and one for the case where the bo was on the delayed destroy list, at least at the time of call. This makes it possible to optimize the two cases somewhat. It also enables the possibility to directly destroy buffers on the delayed delete list when they are about to be evicted or swapped out. Currently they were only evicted / swapped and destruction was left for the delayed buffer destruction thread. Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com> Signed-off-by: Dave Airlie <airlied@redhat.com>
-rw-r--r--drivers/gpu/drm/ttm/ttm_bo.c171
1 files changed, 107 insertions, 64 deletions
diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c
index 4a73f401644..a1cb783c713 100644
--- a/drivers/gpu/drm/ttm/ttm_bo.c
+++ b/drivers/gpu/drm/ttm/ttm_bo.c
@@ -455,100 +455,123 @@ static void ttm_bo_cleanup_memtype_use(struct ttm_buffer_object *bo)
455 wake_up_all(&bo->event_queue); 455 wake_up_all(&bo->event_queue);
456} 456}
457 457
458 458static void ttm_bo_cleanup_refs_or_queue(struct ttm_buffer_object *bo)
459/**
460 * If bo idle, remove from delayed- and lru lists, and unref.
461 * If not idle, and already on delayed list, do nothing.
462 * If not idle, and not on delayed list, put on delayed list,
463 * up the list_kref and schedule a delayed list check.
464 */
465
466static int ttm_bo_cleanup_refs(struct ttm_buffer_object *bo, bool remove_all)
467{ 459{
468 struct ttm_bo_device *bdev = bo->bdev; 460 struct ttm_bo_device *bdev = bo->bdev;
469 struct ttm_bo_global *glob = bo->glob; 461 struct ttm_bo_global *glob = bo->glob;
470 struct ttm_bo_driver *driver = bdev->driver; 462 struct ttm_bo_driver *driver;
463 void *sync_obj;
464 void *sync_obj_arg;
465 int put_count;
471 int ret; 466 int ret;
472 467
473 spin_lock(&bo->lock); 468 spin_lock(&bo->lock);
474retry: 469 (void) ttm_bo_wait(bo, false, false, true);
475 (void) ttm_bo_wait(bo, false, false, !remove_all);
476
477 if (!bo->sync_obj) { 470 if (!bo->sync_obj) {
478 int put_count;
479
480 spin_unlock(&bo->lock);
481 471
482 spin_lock(&glob->lru_lock); 472 spin_lock(&glob->lru_lock);
483 ret = ttm_bo_reserve_locked(bo, false, !remove_all, false, 0);
484 473
485 /** 474 /**
486 * Someone else has the object reserved. Bail and retry. 475 * Lock inversion between bo::reserve and bo::lock here,
476 * but that's OK, since we're only trylocking.
487 */ 477 */
488 478
489 if (unlikely(ret == -EBUSY)) { 479 ret = ttm_bo_reserve_locked(bo, false, true, false, 0);
490 spin_unlock(&glob->lru_lock);
491 spin_lock(&bo->lock);
492 goto requeue;
493 }
494
495 /**
496 * We can re-check for sync object without taking
497 * the bo::lock since setting the sync object requires
498 * also bo::reserved. A busy object at this point may
499 * be caused by another thread starting an accelerated
500 * eviction.
501 */
502 480
503 if (unlikely(bo->sync_obj)) { 481 if (unlikely(ret == -EBUSY))
504 atomic_set(&bo->reserved, 0); 482 goto queue;
505 wake_up_all(&bo->event_queue);
506 spin_unlock(&glob->lru_lock);
507 spin_lock(&bo->lock);
508 if (remove_all)
509 goto retry;
510 else
511 goto requeue;
512 }
513 483
484 spin_unlock(&bo->lock);
514 put_count = ttm_bo_del_from_lru(bo); 485 put_count = ttm_bo_del_from_lru(bo);
515 486
516 if (!list_empty(&bo->ddestroy)) {
517 list_del_init(&bo->ddestroy);
518 ++put_count;
519 }
520 spin_unlock(&glob->lru_lock); 487 spin_unlock(&glob->lru_lock);
521 ttm_bo_cleanup_memtype_use(bo); 488 ttm_bo_cleanup_memtype_use(bo);
522 489
523 while (put_count--) 490 while (put_count--)
524 kref_put(&bo->list_kref, ttm_bo_ref_bug); 491 kref_put(&bo->list_kref, ttm_bo_ref_bug);
525 492
526 return 0; 493 return;
494 } else {
495 spin_lock(&glob->lru_lock);
527 } 496 }
528requeue: 497queue:
498 sync_obj = bo->sync_obj;
499 sync_obj_arg = bo->sync_obj_arg;
500 driver = bdev->driver;
501
502 kref_get(&bo->list_kref);
503 list_add_tail(&bo->ddestroy, &bdev->ddestroy);
504 spin_unlock(&glob->lru_lock);
505 spin_unlock(&bo->lock);
506
507 if (sync_obj)
508 driver->sync_obj_flush(sync_obj, sync_obj_arg);
509 schedule_delayed_work(&bdev->wq,
510 ((HZ / 100) < 1) ? 1 : HZ / 100);
511}
512
513/**
514 * function ttm_bo_cleanup_refs
515 * If bo idle, remove from delayed- and lru lists, and unref.
516 * If not idle, do nothing.
517 *
518 * @interruptible Any sleeps should occur interruptibly.
519 * @no_wait_reserve Never wait for reserve. Return -EBUSY instead.
520 * @no_wait_gpu Never wait for gpu. Return -EBUSY instead.
521 */
522
523static int ttm_bo_cleanup_refs(struct ttm_buffer_object *bo,
524 bool interruptible,
525 bool no_wait_reserve,
526 bool no_wait_gpu)
527{
528 struct ttm_bo_global *glob = bo->glob;
529 int put_count;
530 int ret = 0;
531
532retry:
533 spin_lock(&bo->lock);
534 ret = ttm_bo_wait(bo, false, interruptible, no_wait_gpu);
535 spin_unlock(&bo->lock);
536
537 if (unlikely(ret != 0))
538 return ret;
539
529 spin_lock(&glob->lru_lock); 540 spin_lock(&glob->lru_lock);
530 if (list_empty(&bo->ddestroy)) { 541 ret = ttm_bo_reserve_locked(bo, interruptible,
531 void *sync_obj = bo->sync_obj; 542 no_wait_reserve, false, 0);
532 void *sync_obj_arg = bo->sync_obj_arg;
533 543
534 kref_get(&bo->list_kref); 544 if (unlikely(ret != 0) || list_empty(&bo->ddestroy)) {
535 list_add_tail(&bo->ddestroy, &bdev->ddestroy);
536 spin_unlock(&glob->lru_lock); 545 spin_unlock(&glob->lru_lock);
537 spin_unlock(&bo->lock); 546 return ret;
547 }
538 548
539 if (sync_obj) 549 /**
540 driver->sync_obj_flush(sync_obj, sync_obj_arg); 550 * We can re-check for sync object without taking
541 schedule_delayed_work(&bdev->wq, 551 * the bo::lock since setting the sync object requires
542 ((HZ / 100) < 1) ? 1 : HZ / 100); 552 * also bo::reserved. A busy object at this point may
543 ret = 0; 553 * be caused by another thread recently starting an accelerated
554 * eviction.
555 */
544 556
545 } else { 557 if (unlikely(bo->sync_obj)) {
558 atomic_set(&bo->reserved, 0);
559 wake_up_all(&bo->event_queue);
546 spin_unlock(&glob->lru_lock); 560 spin_unlock(&glob->lru_lock);
547 spin_unlock(&bo->lock); 561 goto retry;
548 ret = -EBUSY;
549 } 562 }
550 563
551 return ret; 564 put_count = ttm_bo_del_from_lru(bo);
565 list_del_init(&bo->ddestroy);
566 ++put_count;
567
568 spin_unlock(&glob->lru_lock);
569 ttm_bo_cleanup_memtype_use(bo);
570
571 while (put_count--)
572 kref_put(&bo->list_kref, ttm_bo_ref_bug);
573
574 return 0;
552} 575}
553 576
554/** 577/**
@@ -580,7 +603,8 @@ static int ttm_bo_delayed_delete(struct ttm_bo_device *bdev, bool remove_all)
580 } 603 }
581 604
582 spin_unlock(&glob->lru_lock); 605 spin_unlock(&glob->lru_lock);
583 ret = ttm_bo_cleanup_refs(entry, remove_all); 606 ret = ttm_bo_cleanup_refs(entry, false, !remove_all,
607 !remove_all);
584 kref_put(&entry->list_kref, ttm_bo_release_list); 608 kref_put(&entry->list_kref, ttm_bo_release_list);
585 entry = nentry; 609 entry = nentry;
586 610
@@ -623,7 +647,7 @@ static void ttm_bo_release(struct kref *kref)
623 bo->vm_node = NULL; 647 bo->vm_node = NULL;
624 } 648 }
625 write_unlock(&bdev->vm_lock); 649 write_unlock(&bdev->vm_lock);
626 ttm_bo_cleanup_refs(bo, false); 650 ttm_bo_cleanup_refs_or_queue(bo);
627 kref_put(&bo->list_kref, ttm_bo_release_list); 651 kref_put(&bo->list_kref, ttm_bo_release_list);
628 write_lock(&bdev->vm_lock); 652 write_lock(&bdev->vm_lock);
629} 653}
@@ -731,6 +755,18 @@ retry:
731 bo = list_first_entry(&man->lru, struct ttm_buffer_object, lru); 755 bo = list_first_entry(&man->lru, struct ttm_buffer_object, lru);
732 kref_get(&bo->list_kref); 756 kref_get(&bo->list_kref);
733 757
758 if (!list_empty(&bo->ddestroy)) {
759 spin_unlock(&glob->lru_lock);
760 ret = ttm_bo_cleanup_refs(bo, interruptible,
761 no_wait_reserve, no_wait_gpu);
762 kref_put(&bo->list_kref, ttm_bo_release_list);
763
764 if (likely(ret == 0 || ret == -ERESTARTSYS))
765 return ret;
766
767 goto retry;
768 }
769
734 ret = ttm_bo_reserve_locked(bo, false, no_wait_reserve, false, 0); 770 ret = ttm_bo_reserve_locked(bo, false, no_wait_reserve, false, 0);
735 771
736 if (unlikely(ret == -EBUSY)) { 772 if (unlikely(ret == -EBUSY)) {
@@ -1754,6 +1790,13 @@ static int ttm_bo_swapout(struct ttm_mem_shrink *shrink)
1754 struct ttm_buffer_object, swap); 1790 struct ttm_buffer_object, swap);
1755 kref_get(&bo->list_kref); 1791 kref_get(&bo->list_kref);
1756 1792
1793 if (!list_empty(&bo->ddestroy)) {
1794 spin_unlock(&glob->lru_lock);
1795 (void) ttm_bo_cleanup_refs(bo, false, false, false);
1796 kref_put(&bo->list_kref, ttm_bo_release_list);
1797 continue;
1798 }
1799
1757 /** 1800 /**
1758 * Reserve buffer. Since we unlock while sleeping, we need 1801 * Reserve buffer. Since we unlock while sleeping, we need
1759 * to re-check that nobody removed us from the swap-list while 1802 * to re-check that nobody removed us from the swap-list while