diff options
Diffstat (limited to 'include/drm/ttm/ttm_bo_driver.h')
| -rw-r--r-- | include/drm/ttm/ttm_bo_driver.h | 179 |
1 files changed, 114 insertions, 65 deletions
diff --git a/include/drm/ttm/ttm_bo_driver.h b/include/drm/ttm/ttm_bo_driver.h index 9c8dca79808e..8639c85d61c4 100644 --- a/include/drm/ttm/ttm_bo_driver.h +++ b/include/drm/ttm/ttm_bo_driver.h | |||
| @@ -33,11 +33,14 @@ | |||
| 33 | #include <ttm/ttm_bo_api.h> | 33 | #include <ttm/ttm_bo_api.h> |
| 34 | #include <ttm/ttm_memory.h> | 34 | #include <ttm/ttm_memory.h> |
| 35 | #include <ttm/ttm_module.h> | 35 | #include <ttm/ttm_module.h> |
| 36 | #include <ttm/ttm_placement.h> | ||
| 36 | #include <drm/drm_mm.h> | 37 | #include <drm/drm_mm.h> |
| 37 | #include <drm/drm_global.h> | 38 | #include <drm/drm_global.h> |
| 39 | #include <drm/drm_vma_manager.h> | ||
| 38 | #include <linux/workqueue.h> | 40 | #include <linux/workqueue.h> |
| 39 | #include <linux/fs.h> | 41 | #include <linux/fs.h> |
| 40 | #include <linux/spinlock.h> | 42 | #include <linux/spinlock.h> |
| 43 | #include <linux/reservation.h> | ||
| 41 | 44 | ||
| 42 | struct ttm_backend_func { | 45 | struct ttm_backend_func { |
| 43 | /** | 46 | /** |
| @@ -517,7 +520,7 @@ struct ttm_bo_global { | |||
| 517 | * @man: An array of mem_type_managers. | 520 | * @man: An array of mem_type_managers. |
| 518 | * @fence_lock: Protects the synchronizing members on *all* bos belonging | 521 | * @fence_lock: Protects the synchronizing members on *all* bos belonging |
| 519 | * to this device. | 522 | * to this device. |
| 520 | * @addr_space_mm: Range manager for the device address space. | 523 | * @vma_manager: Address space manager |
| 521 | * lru_lock: Spinlock that protects the buffer+device lru lists and | 524 | * lru_lock: Spinlock that protects the buffer+device lru lists and |
| 522 | * ddestroy lists. | 525 | * ddestroy lists. |
| 523 | * @val_seq: Current validation sequence. | 526 | * @val_seq: Current validation sequence. |
| @@ -535,14 +538,13 @@ struct ttm_bo_device { | |||
| 535 | struct list_head device_list; | 538 | struct list_head device_list; |
| 536 | struct ttm_bo_global *glob; | 539 | struct ttm_bo_global *glob; |
| 537 | struct ttm_bo_driver *driver; | 540 | struct ttm_bo_driver *driver; |
| 538 | rwlock_t vm_lock; | ||
| 539 | struct ttm_mem_type_manager man[TTM_NUM_MEM_TYPES]; | 541 | struct ttm_mem_type_manager man[TTM_NUM_MEM_TYPES]; |
| 540 | spinlock_t fence_lock; | 542 | spinlock_t fence_lock; |
| 543 | |||
| 541 | /* | 544 | /* |
| 542 | * Protected by the vm lock. | 545 | * Protected by internal locks. |
| 543 | */ | 546 | */ |
| 544 | struct rb_root addr_space_rb; | 547 | struct drm_vma_offset_manager vma_manager; |
| 545 | struct drm_mm addr_space_mm; | ||
| 546 | 548 | ||
| 547 | /* | 549 | /* |
| 548 | * Protected by the global:lru lock. | 550 | * Protected by the global:lru lock. |
| @@ -771,6 +773,55 @@ extern int ttm_mem_io_lock(struct ttm_mem_type_manager *man, | |||
| 771 | bool interruptible); | 773 | bool interruptible); |
| 772 | extern void ttm_mem_io_unlock(struct ttm_mem_type_manager *man); | 774 | extern void ttm_mem_io_unlock(struct ttm_mem_type_manager *man); |
| 773 | 775 | ||
| 776 | extern void ttm_bo_del_sub_from_lru(struct ttm_buffer_object *bo); | ||
| 777 | extern void ttm_bo_add_to_lru(struct ttm_buffer_object *bo); | ||
| 778 | |||
| 779 | /** | ||
| 780 | * ttm_bo_reserve_nolru: | ||
| 781 | * | ||
| 782 | * @bo: A pointer to a struct ttm_buffer_object. | ||
| 783 | * @interruptible: Sleep interruptible if waiting. | ||
| 784 | * @no_wait: Don't sleep while trying to reserve, rather return -EBUSY. | ||
| 785 | * @use_ticket: If @bo is already reserved, Only sleep waiting for | ||
| 786 | * it to become unreserved if @ticket->stamp is older. | ||
| 787 | * | ||
| 788 | * Will not remove reserved buffers from the lru lists. | ||
| 789 | * Otherwise identical to ttm_bo_reserve. | ||
| 790 | * | ||
| 791 | * Returns: | ||
| 792 | * -EDEADLK: The reservation may cause a deadlock. | ||
| 793 | * Release all buffer reservations, wait for @bo to become unreserved and | ||
| 794 | * try again. (only if use_sequence == 1). | ||
| 795 | * -ERESTARTSYS: A wait for the buffer to become unreserved was interrupted by | ||
| 796 | * a signal. Release all buffer reservations and return to user-space. | ||
| 797 | * -EBUSY: The function needed to sleep, but @no_wait was true | ||
| 798 | * -EALREADY: Bo already reserved using @ticket. This error code will only | ||
| 799 | * be returned if @use_ticket is set to true. | ||
| 800 | */ | ||
| 801 | static inline int ttm_bo_reserve_nolru(struct ttm_buffer_object *bo, | ||
| 802 | bool interruptible, | ||
| 803 | bool no_wait, bool use_ticket, | ||
| 804 | struct ww_acquire_ctx *ticket) | ||
| 805 | { | ||
| 806 | int ret = 0; | ||
| 807 | |||
| 808 | if (no_wait) { | ||
| 809 | bool success; | ||
| 810 | if (WARN_ON(ticket)) | ||
| 811 | return -EBUSY; | ||
| 812 | |||
| 813 | success = ww_mutex_trylock(&bo->resv->lock); | ||
| 814 | return success ? 0 : -EBUSY; | ||
| 815 | } | ||
| 816 | |||
| 817 | if (interruptible) | ||
| 818 | ret = ww_mutex_lock_interruptible(&bo->resv->lock, ticket); | ||
| 819 | else | ||
| 820 | ret = ww_mutex_lock(&bo->resv->lock, ticket); | ||
| 821 | if (ret == -EINTR) | ||
| 822 | return -ERESTARTSYS; | ||
| 823 | return ret; | ||
| 824 | } | ||
| 774 | 825 | ||
| 775 | /** | 826 | /** |
| 776 | * ttm_bo_reserve: | 827 | * ttm_bo_reserve: |
| @@ -778,8 +829,8 @@ extern void ttm_mem_io_unlock(struct ttm_mem_type_manager *man); | |||
| 778 | * @bo: A pointer to a struct ttm_buffer_object. | 829 | * @bo: A pointer to a struct ttm_buffer_object. |
| 779 | * @interruptible: Sleep interruptible if waiting. | 830 | * @interruptible: Sleep interruptible if waiting. |
| 780 | * @no_wait: Don't sleep while trying to reserve, rather return -EBUSY. | 831 | * @no_wait: Don't sleep while trying to reserve, rather return -EBUSY. |
| 781 | * @use_sequence: If @bo is already reserved, Only sleep waiting for | 832 | * @use_ticket: If @bo is already reserved, Only sleep waiting for |
| 782 | * it to become unreserved if @sequence < (@bo)->sequence. | 833 | * it to become unreserved if @ticket->stamp is older. |
| 783 | * | 834 | * |
| 784 | * Locks a buffer object for validation. (Or prevents other processes from | 835 | * Locks a buffer object for validation. (Or prevents other processes from |
| 785 | * locking it for validation) and removes it from lru lists, while taking | 836 | * locking it for validation) and removes it from lru lists, while taking |
| @@ -793,7 +844,7 @@ extern void ttm_mem_io_unlock(struct ttm_mem_type_manager *man); | |||
| 793 | * Processes attempting to reserve multiple buffers other than for eviction, | 844 | * Processes attempting to reserve multiple buffers other than for eviction, |
| 794 | * (typically execbuf), should first obtain a unique 32-bit | 845 | * (typically execbuf), should first obtain a unique 32-bit |
| 795 | * validation sequence number, | 846 | * validation sequence number, |
| 796 | * and call this function with @use_sequence == 1 and @sequence == the unique | 847 | * and call this function with @use_ticket == 1 and @ticket->stamp == the unique |
| 797 | * sequence number. If upon call of this function, the buffer object is already | 848 | * sequence number. If upon call of this function, the buffer object is already |
| 798 | * reserved, the validation sequence is checked against the validation | 849 | * reserved, the validation sequence is checked against the validation |
| 799 | * sequence of the process currently reserving the buffer, | 850 | * sequence of the process currently reserving the buffer, |
| @@ -808,36 +859,31 @@ extern void ttm_mem_io_unlock(struct ttm_mem_type_manager *man); | |||
| 808 | * will eventually succeed, preventing both deadlocks and starvation. | 859 | * will eventually succeed, preventing both deadlocks and starvation. |
| 809 | * | 860 | * |
| 810 | * Returns: | 861 | * Returns: |
| 811 | * -EAGAIN: The reservation may cause a deadlock. | 862 | * -EDEADLK: The reservation may cause a deadlock. |
| 812 | * Release all buffer reservations, wait for @bo to become unreserved and | 863 | * Release all buffer reservations, wait for @bo to become unreserved and |
| 813 | * try again. (only if use_sequence == 1). | 864 | * try again. (only if use_sequence == 1). |
| 814 | * -ERESTARTSYS: A wait for the buffer to become unreserved was interrupted by | 865 | * -ERESTARTSYS: A wait for the buffer to become unreserved was interrupted by |
| 815 | * a signal. Release all buffer reservations and return to user-space. | 866 | * a signal. Release all buffer reservations and return to user-space. |
| 816 | * -EBUSY: The function needed to sleep, but @no_wait was true | 867 | * -EBUSY: The function needed to sleep, but @no_wait was true |
| 817 | * -EDEADLK: Bo already reserved using @sequence. This error code will only | 868 | * -EALREADY: Bo already reserved using @ticket. This error code will only |
| 818 | * be returned if @use_sequence is set to true. | 869 | * be returned if @use_ticket is set to true. |
| 819 | */ | 870 | */ |
| 820 | extern int ttm_bo_reserve(struct ttm_buffer_object *bo, | 871 | static inline int ttm_bo_reserve(struct ttm_buffer_object *bo, |
| 821 | bool interruptible, | 872 | bool interruptible, |
| 822 | bool no_wait, bool use_sequence, uint32_t sequence); | 873 | bool no_wait, bool use_ticket, |
| 874 | struct ww_acquire_ctx *ticket) | ||
| 875 | { | ||
| 876 | int ret; | ||
| 823 | 877 | ||
| 824 | /** | 878 | WARN_ON(!atomic_read(&bo->kref.refcount)); |
| 825 | * ttm_bo_reserve_slowpath_nolru: | ||
| 826 | * @bo: A pointer to a struct ttm_buffer_object. | ||
| 827 | * @interruptible: Sleep interruptible if waiting. | ||
| 828 | * @sequence: Set (@bo)->sequence to this value after lock | ||
| 829 | * | ||
| 830 | * This is called after ttm_bo_reserve returns -EAGAIN and we backed off | ||
| 831 | * from all our other reservations. Because there are no other reservations | ||
| 832 | * held by us, this function cannot deadlock any more. | ||
| 833 | * | ||
| 834 | * Will not remove reserved buffers from the lru lists. | ||
| 835 | * Otherwise identical to ttm_bo_reserve_slowpath. | ||
| 836 | */ | ||
| 837 | extern int ttm_bo_reserve_slowpath_nolru(struct ttm_buffer_object *bo, | ||
| 838 | bool interruptible, | ||
| 839 | uint32_t sequence); | ||
| 840 | 879 | ||
| 880 | ret = ttm_bo_reserve_nolru(bo, interruptible, no_wait, use_ticket, | ||
| 881 | ticket); | ||
| 882 | if (likely(ret == 0)) | ||
| 883 | ttm_bo_del_sub_from_lru(bo); | ||
| 884 | |||
| 885 | return ret; | ||
| 886 | } | ||
| 841 | 887 | ||
| 842 | /** | 888 | /** |
| 843 | * ttm_bo_reserve_slowpath: | 889 | * ttm_bo_reserve_slowpath: |
| @@ -849,54 +895,57 @@ extern int ttm_bo_reserve_slowpath_nolru(struct ttm_buffer_object *bo, | |||
| 849 | * from all our other reservations. Because there are no other reservations | 895 | * from all our other reservations. Because there are no other reservations |
| 850 | * held by us, this function cannot deadlock any more. | 896 | * held by us, this function cannot deadlock any more. |
| 851 | */ | 897 | */ |
| 852 | extern int ttm_bo_reserve_slowpath(struct ttm_buffer_object *bo, | 898 | static inline int ttm_bo_reserve_slowpath(struct ttm_buffer_object *bo, |
| 853 | bool interruptible, uint32_t sequence); | 899 | bool interruptible, |
| 900 | struct ww_acquire_ctx *ticket) | ||
| 901 | { | ||
| 902 | int ret = 0; | ||
| 854 | 903 | ||
| 855 | /** | 904 | WARN_ON(!atomic_read(&bo->kref.refcount)); |
| 856 | * ttm_bo_reserve_nolru: | 905 | |
| 857 | * | 906 | if (interruptible) |
| 858 | * @bo: A pointer to a struct ttm_buffer_object. | 907 | ret = ww_mutex_lock_slow_interruptible(&bo->resv->lock, |
| 859 | * @interruptible: Sleep interruptible if waiting. | 908 | ticket); |
| 860 | * @no_wait: Don't sleep while trying to reserve, rather return -EBUSY. | 909 | else |
| 861 | * @use_sequence: If @bo is already reserved, Only sleep waiting for | 910 | ww_mutex_lock_slow(&bo->resv->lock, ticket); |
| 862 | * it to become unreserved if @sequence < (@bo)->sequence. | 911 | |
| 863 | * | 912 | if (likely(ret == 0)) |
| 864 | * Will not remove reserved buffers from the lru lists. | 913 | ttm_bo_del_sub_from_lru(bo); |
| 865 | * Otherwise identical to ttm_bo_reserve. | 914 | else if (ret == -EINTR) |
| 866 | * | 915 | ret = -ERESTARTSYS; |
| 867 | * Returns: | 916 | |
| 868 | * -EAGAIN: The reservation may cause a deadlock. | 917 | return ret; |
| 869 | * Release all buffer reservations, wait for @bo to become unreserved and | 918 | } |
| 870 | * try again. (only if use_sequence == 1). | ||
| 871 | * -ERESTARTSYS: A wait for the buffer to become unreserved was interrupted by | ||
| 872 | * a signal. Release all buffer reservations and return to user-space. | ||
| 873 | * -EBUSY: The function needed to sleep, but @no_wait was true | ||
| 874 | * -EDEADLK: Bo already reserved using @sequence. This error code will only | ||
| 875 | * be returned if @use_sequence is set to true. | ||
| 876 | */ | ||
| 877 | extern int ttm_bo_reserve_nolru(struct ttm_buffer_object *bo, | ||
| 878 | bool interruptible, | ||
| 879 | bool no_wait, bool use_sequence, | ||
| 880 | uint32_t sequence); | ||
| 881 | 919 | ||
| 882 | /** | 920 | /** |
| 883 | * ttm_bo_unreserve | 921 | * ttm_bo_unreserve_ticket |
| 884 | * | ||
| 885 | * @bo: A pointer to a struct ttm_buffer_object. | 922 | * @bo: A pointer to a struct ttm_buffer_object. |
| 923 | * @ticket: ww_acquire_ctx used for reserving | ||
| 886 | * | 924 | * |
| 887 | * Unreserve a previous reservation of @bo. | 925 | * Unreserve a previous reservation of @bo made with @ticket. |
| 888 | */ | 926 | */ |
| 889 | extern void ttm_bo_unreserve(struct ttm_buffer_object *bo); | 927 | static inline void ttm_bo_unreserve_ticket(struct ttm_buffer_object *bo, |
| 928 | struct ww_acquire_ctx *t) | ||
| 929 | { | ||
| 930 | if (!(bo->mem.placement & TTM_PL_FLAG_NO_EVICT)) { | ||
| 931 | spin_lock(&bo->glob->lru_lock); | ||
| 932 | ttm_bo_add_to_lru(bo); | ||
| 933 | spin_unlock(&bo->glob->lru_lock); | ||
| 934 | } | ||
| 935 | ww_mutex_unlock(&bo->resv->lock); | ||
| 936 | } | ||
| 890 | 937 | ||
| 891 | /** | 938 | /** |
| 892 | * ttm_bo_unreserve_locked | 939 | * ttm_bo_unreserve |
| 893 | * | 940 | * |
| 894 | * @bo: A pointer to a struct ttm_buffer_object. | 941 | * @bo: A pointer to a struct ttm_buffer_object. |
| 895 | * | 942 | * |
| 896 | * Unreserve a previous reservation of @bo. | 943 | * Unreserve a previous reservation of @bo. |
| 897 | * Needs to be called with struct ttm_bo_global::lru_lock held. | ||
| 898 | */ | 944 | */ |
| 899 | extern void ttm_bo_unreserve_locked(struct ttm_buffer_object *bo); | 945 | static inline void ttm_bo_unreserve(struct ttm_buffer_object *bo) |
| 946 | { | ||
| 947 | ttm_bo_unreserve_ticket(bo, NULL); | ||
| 948 | } | ||
| 900 | 949 | ||
| 901 | /* | 950 | /* |
| 902 | * ttm_bo_util.c | 951 | * ttm_bo_util.c |
