diff options
-rw-r--r-- | drivers/gpu/drm/ttm/ttm_bo.c | 171 |
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 4a73f401644d..a1cb783c7131 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 | 458 | static 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 | |||
466 | static 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); |
474 | retry: | 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 | } |
528 | requeue: | 497 | queue: |
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 | |||
523 | static 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 | |||
532 | retry: | ||
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 |